English Русский Español Deutsch 日本語 Português
DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能

DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能

MetaTrader 5示例 | 21 二月 2022, 13:41
905 0
Artyom Trishkin
Artyom Trishkin

内容


概述

目前,该函数库能够跟踪客户端终端图表上的标准图形对象,包括删除和修改其某些参数。 有时,直接从程序中了解如何在图表上新设置、修改或删除自定义图形对象非常有用。 然而,目前,我们还缺乏从自定义程序创建标准图形对象的能力。 拥有了针对图形对象和跟踪其属性变化的编程能力,我们就能够创建任意复杂度、嵌套程度、以及可控轴点数量的复合图形对象。 在本文中,我将创建标准图形对象的基本编程功能。 在接下来的文章中,我将完善这些功能,同时考虑基于标准图形对象创建自定义复合图形对象的能力。

此外,我还会逐步完成让函数库对象使用动态数组存储其属性的能力。 事实上,我在上一篇文章中已经开始做这些工作了。 在此,我会修复前一篇文章中的一个逻辑错误;该错误导致无法跟踪拥有两个以上轴心点的对象属性变化。 此外,我将修复并改进多维动态数组类,从而令它可以用作函数库的单独单元,并将其转移到单独的文件之中。


改进库类

抽象图形对象的衍生类需要一些由基准对象支持的属性,从而能够实现属性的搜索、排序,并在终端日志里显示。 在 GStdFiboArcObj.mqhGStdGannFanObj.mqh 文件里,为对象加入支持 "Level value" 实数型属性的代码:

//+------------------------------------------------------------------+
//| Return 'true' if an object supports a passed                     |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CGStdFiboArcObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property)
  {
   switch((int)property)
     {
      //--- Supported properties
      case GRAPH_OBJ_PROP_SCALE        :
      case GRAPH_OBJ_PROP_PRICE        :
      case GRAPH_OBJ_PROP_LEVELVALUE   : return true;
      //--- Other properties are not supported
      //--- Default is 'false'
      default: break;
     }
   return false;
  }
//+------------------------------------------------------------------+

GStdExpansionObj.mqh, GStdFiboChannelObj.mqh, GStdFiboFanObj.mqh, GStdFiboObj.mqh, GStdFiboTimesObj.mqhGStdPitchforkObj.mqh 文件里,按照相同的方法进行以下修改,以便支持相同的属性:

//+------------------------------------------------------------------+
//| Return 'true' if an object supports a passed                     |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CGStdPitchforkObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property)
  {
   switch((int)property)
     {
      //--- Supported properties
      case GRAPH_OBJ_PROP_PRICE        :
      case GRAPH_OBJ_PROP_LEVELVALUE   : return true;
      //--- Other properties are not supported
      //--- Default is 'false'
      default: break;
     }
   return false;
  }
//+------------------------------------------------------------------+

在含有 "Horizontal line" 对象类的 GStdHLineObj.mqh 文件里,从返回对象支持该整数型属性的标志的方法中删除 “Pivot point time” 属性,因为该对象在构造时仅用到价格:

//+------------------------------------------------------------------+
//| Return 'true' if an object supports a passed                     |
//| integer property, otherwise return 'false'                       |
//+------------------------------------------------------------------+
bool CGStdHLineObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property)
  {
   switch((int)property)
     {
      //--- Supported properties
      case GRAPH_OBJ_PROP_ID           :
      case GRAPH_OBJ_PROP_TYPE         :
      case GRAPH_OBJ_PROP_ELEMENT_TYPE : 
      case GRAPH_OBJ_PROP_GROUP        : 
      case GRAPH_OBJ_PROP_BELONG       :
      case GRAPH_OBJ_PROP_CHART_ID     :
      case GRAPH_OBJ_PROP_WND_NUM      :
      case GRAPH_OBJ_PROP_NUM          :
      case GRAPH_OBJ_PROP_CREATETIME   :
      case GRAPH_OBJ_PROP_TIMEFRAMES   :
      case GRAPH_OBJ_PROP_BACK         :
      case GRAPH_OBJ_PROP_ZORDER       :
      case GRAPH_OBJ_PROP_HIDDEN       :
      case GRAPH_OBJ_PROP_SELECTED     :
      case GRAPH_OBJ_PROP_SELECTABLE   :
      case GRAPH_OBJ_PROP_TIME         :
      case GRAPH_OBJ_PROP_COLOR        :
      case GRAPH_OBJ_PROP_STYLE        :
      case GRAPH_OBJ_PROP_WIDTH        : return true;
      //--- Other properties are not supported
      //--- Default is 'false'
      default: break;
     }
   return false;
  }
//+------------------------------------------------------------------+

GStdVLineObj.mqh 文件里的 "Vertical line" 对象在构造时仅用到时间。 故此,我从返回对象支持实数型属性的标志的方法中删除了所有内容 — 该对象不再支持实数型属性

//+------------------------------------------------------------------+
//| Return 'true' if an object supports a passed                     |
//| real property, otherwise return 'false'                          |
//+------------------------------------------------------------------+
bool CGStdVLineObj::SupportProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property)
  {
   return false;
  }
//+------------------------------------------------------------------+


在上一篇文章中,我忽略了一个逻辑错误,当用两个轴点构建对象,或对象提供的级别超过两个时,该错误会阻止我们修改对象轴点和级别的属性。 它主要是关于将指定数量的单元添加到数组末尾的方法。 该方法接收指向外部创建的对象的指针,而数组接收指定数量的这些指针:

//--- Add the specified number of cells with objects to the end of the array
   bool              AddQuantity(const string source,const int total,CObject *object)
                       {
                        //--- Declare the variable for storing the result of adding objects to the list
                        bool res=true;
                        //--- in the list by the number of added objects passed to the method
                        for(int i=0;i<total;i++)
                          {
                           //--- if failed to add the object to the list
                           if(!this.Add(object))
                             {
                              //--- display the appropriate message, add 'false' to the variable value
                              //--- and move on to the loop next iteration
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);

                              res &=false;
                              continue;
                             }
                          }
                        //--- Return the total result of adding the specified number of objects to the list
                        return res;
                       }

然而,这是同一个对象! 我们只需简单地在循环中将指向方法外部创建的对象指针传递给它。 因此,更改对象本身的属性会影响所有指针 — 它们引用的也是同一个对象。 因此,我们在数组中填充的是相同对象属性的实例,而非不同实例的属性。 如果对象具有多个参考点,我们将轴点乘以指定的数量。 取代管理第二、第三、第四和第五个点的实数型数值,我们在数组添加第二个枢轴点的属性。 这会阻止我们去获取、跟踪和更改实数型参考点的数值。 更改第二个轴心点会将这些变化复制到第三、第四和第五个对象点。

我们再添加一个创建新数据对象的方法。 此方法将创建一个新的属性对象。 我们将在 AddQuantity() 方法中把这个新属性(而不是指针)添加到数组中,在该方法中,我们简单地按照指定数量把从外部创建的指针加入数组。

鉴于我们在 \MQL5\Include\DoEasy\Services\XDimArray.mqh 中有三组相同的类 — 创建整数型、实数型和字符串型动态多维数组的类,我们以创建整数型多维动态数组的类作为例子来研究如何运用它们。

在一个 long 型数组维度的类中,编写创建新数据对象的方法

//+------------------------------------------------------------------+
//| Class of a single long array dimension                           |
//+------------------------------------------------------------------+
class CDimLong : public CArrayObj
  {
private:
//--- Create a new data object
   CDataUnitLong    *CreateData(const string source,const long value=0)
                       {
                        //--- Create a new long data object
                        CDataUnitLong *data=new CDataUnitLong();
                        //--- If failed to create an object, inform of that in the journal
                        if(data==NULL)
                           ::Print(source,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ));
                        //--- Otherwise, set the value passed to the method for the object
                        else
                           data.Value=value;
                        //--- Return the pointer to the object or NULL
                        return data;
                       }
//--- Get long data object from the array

这里的一切都很简单:我们创建一个新的 long 型数据对象,并把要传递给方法的数值赋值给它。 如果无法创建对象,则在日志中通报。 该方法返回指向所创建对象的指针,或者在出现错误时返回 NULL

将修改添加到 AddQuantity() 方法之中:

//--- Add the specified number of cells with data to the end of the array
   bool              AddQuantity(const string source,const int total,const long value=0)
                       {
                        //--- Declare the variable for storing the result of adding objects to the list
                        bool res=true;
                        //--- in the list by the number of added objects passed to the method
                        for(int i=0;i<total;i++)
                          {
                           //--- Create a new long data object
                           CDataUnitLong *data=this.CreateData(DFUN,value);
                           //--- If failed to create an object, inform of that and move on to the next iteration
                           if(data==NULL)
                             {
                              res &=false;
                              continue;
                             }
                           data.Value=value;
                           //--- if failed to add the object to the list
                           if(!this.Add(data))
                             {
                              //--- display the appropriate message, remove the object and add 'false' to the variable value
                              //--- and move on to the loop next iteration
                              CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                              delete data;
                              res &=false;
                              continue;
                             }
                          }
                        //--- Return the total result of adding the specified number of objects to the list
                        return res;
                       }

现在,该方法接收要分配给新创建属性的值,取代指向该对象的指针。 在循环中,创建一个新对象,并将其添加到列表当中。

Increase() 方法中,我之前曾创建了一个新对象,并将指向它的指针传递给 AddQuantity() 方法,然后简单地调用 AddQuantity() 方法,因为新对象现在已于循环中创建,并添加到 AddQuantity() 方法内的数组之中,而不是如前在 crease() 方法中创建的单个指向对象的指针。

我们从方法中删除以下代码块

//--- Increase the number of data cells by the specified value, return the number of added elements
   int               Increase(const int total,const long value=0)
                       {
                        //--- Save the current array size
                        int size_prev=this.Total();
                        //--- Create a new long data object
                        CDataUnitLong *data=new CDataUnitLong();
                        //--- If failed to create an object, inform of that and return zero
                        if(data==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_LONG_DATA_OBJ));
                           return 0;
                          }
                        //--- Set the specified value to a newly created object
                        data.Value=value;
                        //--- Add the specified number of object instances to the list
                        //--- and return the difference between the obtained and previous array size
                        this.AddQuantity(DFUN,total,data);
                        return this.Total()-size_prev;
                       }

被调用的 AddQuantity() 方法现在接收新添加到数组中的数据对象的初始值,而不是指针

//--- Increase the number of data cells by the specified value, return the number of added elements
   int               Increase(const int total,const long value=0)
                       {
                        //--- Save the current array size
                        int size_prev=this.Total();
                        //--- Add the specified number of object instances to the list
                        //--- and return the difference between the obtained and previous array size
                        this.AddQuantity(DFUN,total,value);
                        return this.Total()-size_prev;
                       }

针对文件的其余类进行相同的修改。 我不打算在这里重复它们,因为它们雷同。
您可以查看文后附件中的所有修改。

在 \MQL5\Include\DoEasy\Data.mqh 里,加入新的消息索引:

//--- CGraphElementsCollection
   MSG_GRAPH_ELM_COLLECTION_ERR_OBJ_ALREADY_EXISTS,   // Error. A chart control object already exists with chart id 
   MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_CREATE_CTRL_OBJ,// Failed to create chart control object with chart ID 
   MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_GET_CTRL_OBJ,  // Failed to get chart control object with chart ID 
   MSG_GRAPH_ELM_COLLECTION_ERR_GR_OBJ_ALREADY_EXISTS,// Such graphical object already exists: 
   
//--- GStdGraphObj
   MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ,     // Failed to create the class object for a graphical object 
   MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ, // Failed to create a graphical object 
   MSG_GRAPH_STD_OBJ_ERR_NOT_FIND_SUBWINDOW,          // Failed to find the chart subwindow

...

   MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_ON,              // On state
   MSG_GRAPH_OBJ_TEXT_BMP_FILE_STATE_OFF,             // Off state
   
//--- CDataPropObj
   MSG_DATA_PROP_OBJ_OUT_OF_PROP_RANGE,               // Passed property is out of object property range

//--- CGraphElementsCollection
   MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST,           // Failed to get the list of newly added objects
   MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST,         // Failed to remove a graphical object from the list
   
   MSG_GRAPH_OBJ_CREATE_EVN_CTRL_INDICATOR,           // Indicator for controlling and sending events created
   MSG_GRAPH_OBJ_FAILED_CREATE_EVN_CTRL_INDICATOR,    // Failed to create the indicator for controlling and sending events
   MSG_GRAPH_OBJ_CLOSED_CHARTS,                       // Chart windows closed:
   MSG_GRAPH_OBJ_OBJECTS_ON_CLOSED_CHARTS,            // Objects removed together with charts:
   
  };
//+------------------------------------------------------------------+

与新添加的索引相对应的消息文本:

//--- CGraphElementsCollection
   {"Ошибка. Уже существует объект управления чартами с идентификатором чарта ","Error. A chart control object already exists with chart id "},
   {"Не удалось создать объект управления чартами с идентификатором чарта ","Failed to create chart control object with chart id "},
   {"Не удалось получить объект управления чартами с идентификатором чарта ","Failed to get chart control object with chart id "},
   {"Такой графический объект уже существует: ","Such a graphic object already exists: "},
   
//--- GStdGraphObj
   {"Не удалось создать объект класса для графического объекта ","Failed to create class object for graphic object"},
   {"Не удалось создать графический объект ","Failed to create graphic object "},
   {"Не удалось найти подокно графика","Could not find chart subwindow"},

...

   {"Состояние \"On\"","State \"On\""},
   {"Состояние \"Off\"","State \"Off\""},
   
//--- CDataPropObj
   {"Переданное свойство находится за пределами диапазона свойств объекта","The passed property is outside the range of the object's properties"},
   
//--- CGraphElementsCollection
   {"Не удалось получить список вновь добавленных объектов","Failed to get the list of newly added objects"},
   {"Не удалось изъять графический объект из списка","Failed to detach graphic object from the list"},
   
   {"Создан индикатор контроля и отправки событий","An indicator for monitoring and sending events has been created"},
   {"Не удалось создать индикатор контроля и отправки событий","Failed to create indicator for monitoring and sending events"},
   {"Закрыто окон графиков: ","Closed chart windows: "},
   {"С ними удалено объектов: ","Objects removed with them: "},
   
  };
//+---------------------------------------------------------------------+


我们对函数库图形对象的基准对象类进行一些小的改进。

图形对象拥有的 bool 属性能返回某些对象属性的标志。 抽象图形对象类拥有返回和设置此类标志的方法。 方法名则表明该方法是为了设置标志,例如:
SetFlagDrawLines (显示埃洛特波浪标记指示线). 在函数库图形对象的基准对象类中,相应的方法称为 SetDrawLines()。 故此,如果我们尝试为一个对象设置标志,我们将看到两条选择方法的提示。 这有点令人莫名其妙。 此外,如果我们选择基准图形对象的方法,而不是抽象对象的方法,那么对象数组中的属性不会被更改。 代之,我们简单地发出一条命令来修改图形对象本身的属性。 类对象中的相应属性将保持不变。 这意味着我们需要重命名所有这些方法,从而避免在选择两种方法之一时出错。 我相信,以后还需要统一这些方法的返回类型,以便编译器能够明确无误地选择所需的方法。

我们在 \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh 中引入必要的修复。

//--- Set the "Background object" flag
   bool              SetFlagBack(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_BACK,flag))
                          {
                           this.m_back=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Object selection" flag
   bool              SetFlagSelected(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTED,flag))
                          {
                           this.m_selected=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Object selection" flag
   bool              SetFlagSelectable(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag))
                          {
                           this.m_selectable=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }
//--- Set the "Disable displaying the name of a graphical object in the terminal object list" flag
   bool              SetFlagHidden(const bool flag)
                       {
                        ::ResetLastError();
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_SELECTABLE,flag))
                          {
                           this.m_hidden=flag;
                           return true;
                          }
                        else
                           CMessage::ToLog(DFUN,::GetLastError(),true);
                        return false;
                       }


我们将创建多维动态数组的类移至一个单独的文件当中。 我会对改进它们,令它们成为一种工具,可为函数库中的任何现有或计划中的对象创建属性,并应用数组存储其属性(整数型、实数型和字符串型)。

在服务类和函数的 \MQL5\Include\DoEasy\Services\文件夹中,创建一个新的文件 Properties.mqh。 这是为了获得所有用于创建对象属性的二维数组的类,以及在前一篇文章中直接在 CGStdGraphObj 抽象标准图形对象的类主体中设置的属性对象(包括以前的和当前的)

//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {
private:
   //--- Object property class
   class CDataPropObj
     {
   private:
      CArrayObj         m_list;        // list of property objects
      int               m_total_int;   // Number of integer parameters
      int               m_total_dbl;   // Number of real parameters
      int               m_total_str;   // Number of string parameters
      //--- Return the index of the array the (1) double and (2) string properties are actually located at
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_DOUBLE property)              const { return(int)property-this.m_total_int;                     }
      int               IndexProp(ENUM_GRAPH_OBJ_PROP_STRING property)              const { return(int)property-this.m_total_int-this.m_total_dbl;    }
   public:
      //--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties
      CArrayObj        *GetList(void)                                                     { return &this.m_list;                                      }
      CXDimArrayLong   *Long()                                                      const { return this.m_list.At(0);                                 }
      CXDimArrayDouble *Double()                                                    const { return this.m_list.At(1);                                 }
      CXDimArrayString *String()                                                    const { return this.m_list.At(2);                                 }
      //--- Set object's (1) integer, (2) real and (3) string properties
      void              Set(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value)    { this.Long().Set(property,index,value);                    }
      void              Set(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value)   { this.Double().Set(this.IndexProp(property),index,value);  }
      void              Set(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value)   { this.String().Set(this.IndexProp(property),index,value);  }
      //--- Return object’s (1) integer, (2) real and (3) string property from the properties array
      long              Get(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)         const { return this.Long().Get(property,index);                   }
      double            Get(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index)          const { return this.Double().Get(this.IndexProp(property),index); }
      string            Get(ENUM_GRAPH_OBJ_PROP_STRING property,int index)          const { return this.String().Get(this.IndexProp(property),index); }
      
      //--- Return the size of the specified first dimension data array
      int               Size(const int range) const
                          {
                           if(range<this.m_total_int)
                              return this.Long().Size(range);
                           else if(range<this.m_total_int+this.m_total_dbl)
                              return this.Double().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range));
                           else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str)
                              return this.String().Size(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range));
                           return 0;
                          }
      //--- Set the array size in the specified dimensionality
      bool              SetSizeRange(const int range,const int size)
                          {
                           if(range<this.m_total_int)
                              return this.Long().SetSizeRange(range,size);
                           else if(range<this.m_total_int+this.m_total_dbl)
                              return this.Double().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_DOUBLE)range),size);
                           else if(range<this.m_total_int+this.m_total_dbl+this.m_total_str)
                              return this.String().SetSizeRange(this.IndexProp((ENUM_GRAPH_OBJ_PROP_STRING)range),size);
                           return false;
                          }
      //--- Constructor
                        CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string)
                          {
                           this.m_total_int=prop_total_integer;
                           this.m_total_dbl=prop_total_double;
                           this.m_total_str=prop_total_string;
                           this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1));
                           this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1));
                           this.m_list.Add(new CXDimArrayString(this.m_total_str,1));
                          }
      //--- Destructor
                       ~CDataPropObj()
                          {
                           m_list.Clear();
                           m_list.Shutdown();
                          }
     };
   //--- Data class of the current and previous properties
   class CProperty
     {
   public:
      CDataPropObj     *Curr;    // Pointer to the current properties object
      CDataPropObj     *Prev;    // Pointer to the previous properties object
      //--- Set the array size ('size') in the specified dimension ('range')
      bool              SetSizeRange(const int range,const int size)
                          {
                           return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false);
                          }
      //--- Return the size of the specified array of the (1) current and (2) previous first dimension data
      int               CurrSize(const int range)  const { return Curr.Size(range); }
      int               PrevSize(const int range)  const { return Prev.Size(range); }
      //--- Copy the current data to the previous one
      void              CurrentToPrevious(void)
                          {
                           //--- Copy all integer properties
                           for(int i=0;i<this.Curr.Long().Total();i++)
                              for(int r=0;r<this.Curr.Long().Size(i);r++)
                                 this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r));
                           //--- Copy all real properties
                           for(int i=0;i<this.Curr.Double().Total();i++)
                              for(int r=0;r<this.Curr.Double().Size(i);r++)
                                 this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r));
                           //--- Copy all string properties
                           for(int i=0;i<this.Curr.String().Total();i++)
                              for(int r=0;r<this.Curr.String().Size(i);r++)
                                 this.Prev.String().Set(i,r,this.Curr.String().Get(i,r));
                          }
      //--- Constructor
                        CProperty(const int prop_int_total,const int prop_double_total,const int prop_string_total)
                          {
                           this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total);
                           this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total);
                          }
     };

我们需要去掉任何属于特定类对象的枚举引用,从而令类更具通用性。

为了实现这一点,在选择返回实数型属性索引的方法时,用更普通的 int 变量替换所有枚举。 为了计算属性索引,将实数型和字符串型属性的最大属性传递给类构造函数(整数型属性不会有偏移,并且与属性索引完全对应)。 接下来,简单地根据属性值和属性的最大值计算实值。 与往常一样,当展示出代码时,这个思路看起来更清晰。

在新添加的文件 \MQL5\Include\DoEasy\Services\Properties.mqh 中添加以下类:

//+------------------------------------------------------------------+
//|                                                   Properties.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "XDimArray.mqh"
//+------------------------------------------------------------------+
//| Object property class                                            |
//+------------------------------------------------------------------+
//--- Object property class
class CDataPropObj : public CObject
  {
private:
   CArrayObj         m_list;           // list of property objects
   int               m_total_int;      // Number of integer parameters
   int               m_total_dbl;      // Number of real parameters
   int               m_total_str;      // Number of string parameters
   int               m_prop_max_dbl;   // Maximum possible real property value
   int               m_prop_max_str;   // Maximum possible string property value
//--- Return the index of the array the int, double or string property is actually located at
   int               IndexProp(int property) const
                       {
                        //--- If the passed value is less than the number of integer parameters,
                        //--- this is an integer property. Return the value passed to the method
                        if(property<this.m_total_int)
                           return property;
                        //--- Otherwise if the passed value is less than the maximum possible real property value,
                        //--- then this is a real property - return the calculated index in the array of real properties
                        else if(property<this.m_prop_max_dbl)
                           return property-this.m_total_int;
                        //--- Otherwise if the passed value is less than the maximum possible string property value,
                        //--- then this is a string property - return the calculated index in the array of string properties
                        else if(property<this.m_prop_max_str)
                           return property-this.m_total_int-this.m_total_dbl;
                        //--- Otherwise, if the passed value exceeds the maximum range of all values of all properties, 
                        //--- inform of this in the journal and return INT_MAX causing the error
                        //--- accessing the array in XDimArray file classes which send the appropriate warning to the journal
                        CMessage::ToLog(DFUN,MSG_DATA_PROP_OBJ_OUT_OF_PROP_RANGE);
                        return INT_MAX;
                       }
public:
//--- Return the pointer to (1) the list of property objects, as well as to the object of (2) integer, (3) real and (4) string properties
   CArrayObj        *GetList(void)                                                     { return &this.m_list;                                      }
   CXDimArrayLong   *Long()                                                      const { return this.m_list.At(0);                                 }
   CXDimArrayDouble *Double()                                                    const { return this.m_list.At(1);                                 }
   CXDimArrayString *String()                                                    const { return this.m_list.At(2);                                 }
   
//--- Set (1) integer, (2) real and (3) string properties in the appropriate property object
   void              SetLong(int property,int index,long value)                        { this.Long().Set(property,index,value);                    }
   void              SetDouble(int property,int index,double value)                    { this.Double().Set(this.IndexProp(property),index,value);  }
   void              SetString(int property,int index,string value)                    { this.String().Set(this.IndexProp(property),index,value);  }
   //--- Return (1) integer, (2) real and (3) string property from the appropriate object
   long              GetLong(int property,int index)                             const { return this.Long().Get(property,index);                   }
   double            GetDouble(int property,int index)                           const { return this.Double().Get(this.IndexProp(property),index); }
   string            GetString(int property,int index)                           const { return this.String().Get(this.IndexProp(property),index); }
   
//--- Return the size of the specified first dimension data array
   int               Size(const int range) const
                       {
                        if(range<this.m_total_int)
                           return this.Long().Size(range);
                        else if(range<this.m_prop_max_dbl)
                           return this.Double().Size(this.IndexProp(range));
                        else if(range<this.m_prop_max_str)
                           return this.String().Size(this.IndexProp(range));
                        return 0;
                       }
//--- Set the array size in the specified dimensionality
   bool              SetSizeRange(const int range,const int size)
                       {
                        if(range<this.m_total_int)
                           return this.Long().SetSizeRange(range,size);
                        else if(range<this.m_prop_max_dbl)
                           return this.Double().SetSizeRange(this.IndexProp(range),size);
                        else if(range<this.m_prop_max_str)
                           return this.String().SetSizeRange(this.IndexProp(range),size);
                        return false;
                       }
//--- Constructor
                     CDataPropObj(const int prop_total_integer,const int prop_total_double,const int prop_total_string)
                       {
                        //--- Set the passed amounts of integer, real and string properties in the variables
                        this.m_total_int=prop_total_integer;
                        this.m_total_dbl=prop_total_double;
                        this.m_total_str=prop_total_string;
                        //--- Calculate and set the maximum values of real and string properties to the variables
                        this.m_prop_max_dbl=this.m_total_int+this.m_total_dbl;
                        this.m_prop_max_str=this.m_total_int+this.m_total_dbl+this.m_total_str;
                        //--- Add newly created objects of integer, real and string properties to the list
                        this.m_list.Add(new CXDimArrayLong(this.m_total_int, 1));
                        this.m_list.Add(new CXDimArrayDouble(this.m_total_dbl,1));
                        this.m_list.Add(new CXDimArrayString(this.m_total_str,1));
                       }
//--- Destructor
                    ~CDataPropObj()
                       {
                        m_list.Clear();
                        m_list.Shutdown();
                       }
  };
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Data class of the current and previous properties                |
//+------------------------------------------------------------------+
class CProperties : public CObject
  {
private:
   CArrayObj         m_list;  // List for storing the pointers to property objects
public:
   CDataPropObj     *Curr;    // Pointer to the current properties object
   CDataPropObj     *Prev;    // Pointer to the previous properties object
//--- Set the array size ('size') in the specified dimension ('range')
   bool              SetSizeRange(const int range,const int size)
                       {
                        return(this.Curr.SetSizeRange(range,size) && this.Prev.SetSizeRange(range,size) ? true : false);
                       }
//--- Return the size of the specified array of the (1) current and (2) previous first dimension data
   int               CurrSize(const int range)  const { return Curr.Size(range); }
   int               PrevSize(const int range)  const { return Prev.Size(range); }
//--- Copy the current data to the previous one
   void              CurrentToPrevious(void)
                       {
                        //--- Copy all integer properties
                        for(int i=0;i<this.Curr.Long().Total();i++)
                           for(int r=0;r<this.Curr.Long().Size(i);r++)
                              this.Prev.Long().Set(i,r,this.Curr.Long().Get(i,r));
                        //--- Copy all real properties
                        for(int i=0;i<this.Curr.Double().Total();i++)
                           for(int r=0;r<this.Curr.Double().Size(i);r++)
                              this.Prev.Double().Set(i,r,this.Curr.Double().Get(i,r));
                        //--- Copy all string properties
                        for(int i=0;i<this.Curr.String().Total();i++)
                           for(int r=0;r<this.Curr.String().Size(i);r++)
                              this.Prev.String().Set(i,r,this.Curr.String().Get(i,r));
                       }
//--- Constructor
                     CProperties(const int prop_int_total,const int prop_double_total,const int prop_string_total)
                       {
                        //--- Create new objects of the current and previous properties
                        this.Curr=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total);
                        this.Prev=new CDataPropObj(prop_int_total,prop_double_total,prop_string_total);
                        //--- Add newly created objects to the list
                        this.m_list.Add(this.Curr);
                        this.m_list.Add(this.Prev);
                       }
//--- Destructor
                    ~CProperties()
                       {
                        this.m_list.Clear();
                        this.m_list.Shutdown();
                       }
  };
//+------------------------------------------------------------------+

所有主要解释都在代码注释中设置。 将这些类与我在 \MQL5\Include\DoEasy\Objects\Graph\Standard\gstdgraphhobj.mqh 中创建的类进行比较。

现在,我们来改进 \MQL5\Include\DoEasy\Objects\Graph\standard\gstdgraphhobj.mqh 中的抽象标准图形对象类。

首先,包含新创建的对象属性类文件

//+------------------------------------------------------------------+
//|                                                 GStdGraphObj.mqh |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\GBaseObj.mqh"
#include "..\..\..\Services\Properties.mqh"
//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {

属性对象类已经从类的私密部分删除。 指向属性对象的指针的声明也在其中。 访问属性对象的相应方法,位于类公开部分的每个 Get 和 Set 方法:

//+------------------------------------------------------------------+
//| The class of the abstract standard graphical object              |
//+------------------------------------------------------------------+
class CGStdGraphObj : public CGBaseObj
  {
private:
   CProperties      *Prop;                                              // Pointer to the properties object
   int               m_pivots;                                          // Number of object reference points
//--- Read and set (1) the time and (2) the price of the specified object pivot point
   void              SetTimePivot(const int index);
   void              SetPricePivot(const int index);
//--- Read and set (1) color, (2) style, (3) width, (4) value, (5) text of the specified object level
   void              SetLevelColor(const int index);
   void              SetLevelStyle(const int index);
   void              SetLevelWidth(const int index);
   void              SetLevelValue(const int index);
   void              SetLevelText(const int index);
//--- Read and set the BMP file name for the "Bitmap Level" object. Index: 0 - ON, 1 - OFF
   void              SetBMPFile(const int index);

public:
//--- Set object's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value)     { this.Prop.Curr.SetLong(property,index,value);    }
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value)    { this.Prop.Curr.SetDouble(property,index,value);  }
   void              SetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value)    { this.Prop.Curr.SetString(property,index,value);  }
//--- Return object’s (1) integer, (2) real and (3) string property from the properties array
   long              GetProperty(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)          const { return this.Prop.Curr.GetLong(property,index);   }
   double            GetProperty(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index)           const { return this.Prop.Curr.GetDouble(property,index); }
   string            GetProperty(ENUM_GRAPH_OBJ_PROP_STRING property,int index)           const { return this.Prop.Curr.GetString(property,index); }

//--- Set object's previous (1) integer, (2) real and (3) string properties
   void              SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index,long value) { this.Prop.Prev.SetLong(property,index,value);    }
   void              SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index,double value){ this.Prop.Prev.SetDouble(property,index,value);  }
   void              SetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index,string value){ this.Prop.Prev.SetString(property,index,value);  }
//--- Return object’s (1) integer, (2) real and (3) string property from the previous properties array
   long              GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_INTEGER property,int index)      const { return this.Prop.Prev.GetLong(property,index);   }
   double            GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_DOUBLE property,int index)       const { return this.Prop.Prev.GetDouble(property,index); }
   string            GetPropertyPrev(ENUM_GRAPH_OBJ_PROP_STRING property,int index)       const { return this.Prop.Prev.GetString(property,index); }
   
//--- Return itself
   CGStdGraphObj    *GetObject(void)                                       { return &this;}

在公开部分,添加类的析构函数,完成属性对象的删除

//--- Default constructor
                     CGStdGraphObj(){ this.m_type=OBJECT_DE_TYPE_GSTD_OBJ; m_group=WRONG_VALUE; }
//--- Destructor
                    ~CGStdGraphObj()
                       {
                        if(this.Prop!=NULL)
                           delete this.Prop;
                       }
protected:
//--- Protected parametric constructor
                     CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type,
                                   const ENUM_GRAPH_OBJ_BELONG belong,
                                   const ENUM_GRAPH_OBJ_GROUP group,
                                   const long chart_id, const int pivots,
                                   const string name);

在简化访问和设置图形对象属性的方法部分,改进了设置标志属性的方法

//--- Background object
   bool              Back(void)                    const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_BACK,0);                          }
   void              SetFlagBack(const bool flag)
                       {
                        if(CGBaseObj::SetFlagBack(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_BACK,0,flag);
                       }
//--- Priority of a graphical object for receiving the event of clicking on a chart
   long              Zorder(void)                  const { return this.GetProperty(GRAPH_OBJ_PROP_ZORDER,0);                              }
   void              SetZorder(const long value)
                       {
                        if(CGBaseObj::SetZorder(value))
                           this.SetProperty(GRAPH_OBJ_PROP_ZORDER,0,value);
                       }
//--- Disable displaying the name of a graphical object in the terminal object list
   bool              Hidden(void)                  const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_HIDDEN,0);                        }
   void              SetFlagHidden(const bool flag)
                       {
                        if(CGBaseObj::SetFlagHidden(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_HIDDEN,0,flag);
                       }
//--- Object selection
   bool              Selected(void)                const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTED,0);                      }
   void              SetFlagSelected(const bool flag)
                       {
                        if(CGBaseObj::SetFlagSelected(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_SELECTED,0,flag);
                       }
//--- Object availability
   bool              Selectable(void)              const { return (bool)this.GetProperty(GRAPH_OBJ_PROP_SELECTABLE,0);                    }
   void              SetFlagSelectable(const bool flag)
                       {
                        if(CGBaseObj::SetFlagSelectable(flag))
                           this.SetProperty(GRAPH_OBJ_PROP_SELECTABLE,0,flag);
                       }
//--- Time coordinate

把复制当前属性到之前属性的方法从私密部分移动到公开部分

//--- Return the description of the object visibility on timeframes
   string            VisibleOnTimeframeDescription(void);

//--- Re-write all graphical object properties
   void              PropertiesRefresh(void);
//--- Check object property changes
   void              PropertiesCheckChanged(void);
//--- Copy the current data to the previous one
   void              PropertiesCopyToPrevData(void);
   
private:
//--- Get and save (1) integer, (2) real and (3) string properties
   void              GetAndSaveINT(void);
   void              GetAndSaveDBL(void);
   void              GetAndSaveSTR(void);

  };
//+------------------------------------------------------------------+

在受保护的参数化构造函数中,创建图形对象属性的新对象

//+------------------------------------------------------------------+
//| Protected parametric constructor                                 |
//+------------------------------------------------------------------+
CGStdGraphObj::CGStdGraphObj(const ENUM_OBJECT_DE_TYPE obj_type,
                             const ENUM_GRAPH_OBJ_BELONG belong,
                             const ENUM_GRAPH_OBJ_GROUP group,
                             const long chart_id,const int pivots,
                             const string name)
  {
   //--- Create the property object with the default values
   this.Prop=new CProperties(GRAPH_OBJ_PROP_INTEGER_TOTAL,GRAPH_OBJ_PROP_DOUBLE_TOTAL,GRAPH_OBJ_PROP_STRING_TOTAL);
   
//--- Set the number of pivot points and object levels

整数型实数型字符串型图形对象属性的数量传递给类构造函数。

在返回图形整数型属性,并将其保存在类对象属性中的方法中,检查对象级别的数量是否已更改如果是,则修改所有属性的数组大小,从而确保能够存储级别值。
否则,在设置级别属性时,我们可能会收到数组超界错误:

   //--- Properties belonging to different graphical objects
   this.SetProperty(GRAPH_OBJ_PROP_FILL,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_FILL));              // Fill an object with color
   this.SetProperty(GRAPH_OBJ_PROP_READONLY,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_READONLY));      // Ability to edit text in the Edit object
   this.SetProperty(GRAPH_OBJ_PROP_LEVELS,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_LEVELS));          // Number of levels
   
   if(this.GetProperty(GRAPH_OBJ_PROP_LEVELS,0)!=this.GetPropertyPrev(GRAPH_OBJ_PROP_LEVELS,0))                      // Check if the number of levels has changed
     {
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELCOLOR,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELSTYLE,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELWIDTH,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELVALUE,this.Levels());
      this.Prop.SetSizeRange(GRAPH_OBJ_PROP_LEVELTEXT,this.Levels()); 
     }
   for(int i=0;i<this.Levels();i++)                                                                                  // Level data
     {
      this.SetLevelColor(i);
      this.SetLevelStyle(i);
      this.SetLevelWidth(i);
     }
   this.SetProperty(GRAPH_OBJ_PROP_ALIGN,0,::ObjectGetInteger(this.ChartID(),this.Name(),OBJPROP_ALIGN));            // Horizontal text alignment in the Edit object (OBJ_EDIT)

简化检查对象属性变化的方法:

//+------------------------------------------------------------------+
//| Check object property changes                                    |
//+------------------------------------------------------------------+
void CGStdGraphObj::PropertiesCheckChanged(void)
  {
   bool changed=false;
   int begin=0, end=GRAPH_OBJ_PROP_INTEGER_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_INTEGER prop=(ENUM_GRAPH_OBJ_PROP_INTEGER)i;
      if(!this.SupportProperty(prop)) continue;
      for(int j=0;j<Prop.CurrSize(prop);j++)
        {
         if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))
           {
            changed=true;
            ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop));
           }
        }
     }

   begin=end; end+=GRAPH_OBJ_PROP_DOUBLE_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_DOUBLE prop=(ENUM_GRAPH_OBJ_PROP_DOUBLE)i;
      if(!this.SupportProperty(prop)) continue;
      for(int j=0;j<Prop.CurrSize(prop);j++)
        {
         if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))
           {
            changed=true;
            ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop));
           }
        }
     }

   begin=end; end+=GRAPH_OBJ_PROP_STRING_TOTAL;
   for(int i=begin; i<end; i++)
     {
      ENUM_GRAPH_OBJ_PROP_STRING prop=(ENUM_GRAPH_OBJ_PROP_STRING)i;
      if(!this.SupportProperty(prop)) continue;
      for(int j=0;j<Prop.CurrSize(prop);j++)
        {
         if(this.GetProperty(prop,j)!=this.GetPropertyPrev(prop,j))

           {
            changed=true;
            ::Print(DFUN,this.Name(),": ",TextByLanguage(" Изменённое свойство: "," Modified property: "),this.GetPropertyDescription(prop));
           }
        }
     }
   if(changed)
      PropertiesCopyToPrevData();
  }
//+------------------------------------------------------------------+

在过去的方法实现中,我采用 if-else 构造来确保属性拥有多个值(例如锚定点时间),并在单独的代码模块中逐一处理每个属性。 由于我们能知道每个属性的属性数组大小,故只需依据数组第二维度的大小循环遍历单个属性的值就足够了。 对于单个属性,第二个维度的大小为 1,而对于多个属性,它等于多属性值的数量。 因此,在单循环中即可完成每个对象属性的访问。 这就是我在上面所做的。

我还在同一个文件中实现了一些小的改进(例如更改方法名)。 举例来说,LevelColorsDescription() 已重命名为 LevelsColorDescription(),这更符合方法的原意。 我不会在此讨论如何重新命名。 您可以在附件中找到它们。

在其它属性之外,每个函数库对象都有一个自定义对象 ID。 图形元素集合类提供了两个集合 — 图形元素集合,在图形对象集合(以手动创建的标准图形对象为特征)完成之前,我暂停了它的开发;我现在正忙于可编程创建标准图形对象。 在此,我启动开发可编程标准图形对象的功能。
以编程方式创建的图形对象的 ID 将处于 1 到 10000(含)之间。 手动创建的图形对象的 ID 从 10001 开始。
我们在 \MQL5\Include\DoEasy\Defines.mqh 文件里设置这个阈值 :

//--- Pending request type IDs
#define PENDING_REQUEST_ID_TYPE_ERR    (1)                        // Type of a pending request created based on the server return code
#define PENDING_REQUEST_ID_TYPE_REQ    (2)                        // Type of a pending request created by request
//--- Timeseries parameters
#define SERIES_DEFAULT_BARS_COUNT      (1000)                     // Required default amount of timeseries data
#define PAUSE_FOR_SYNC_ATTEMPTS        (16)                       // Amount of pause milliseconds between synchronization attempts
#define ATTEMPTS_FOR_SYNC              (5)                        // Number of attempts to receive synchronization with the server
//--- Tick series parameters
#define TICKSERIES_DEFAULT_DAYS_COUNT  (1)                        // Required number of days for tick data in default series
#define TICKSERIES_MAX_DATA_TOTAL      (200000)                   // Maximum number of stored tick data of a single symbol
//--- Parameters of the DOM snapshot series
#define MBOOKSERIES_DEFAULT_DAYS_COUNT (1)                        // The default required number of days for DOM snapshots in the series
#define MBOOKSERIES_MAX_DATA_TOTAL     (200000)                   // Maximum number of stored DOM snapshots of a single symbol
//--- Canvas parameters
#define PAUSE_FOR_CANV_UPDATE          (16)                       // Canvas update frequency
#define NULL_COLOR                     (0x00FFFFFF)               // Zero for the canvas with the alpha channel
#define OUTER_AREA_SIZE                (16)                       // Size of one side of the outer area around the workspace
//--- Graphical object parameters
#define PROGRAM_OBJ_MAX_ID             (10000)                    // Maximum value of an ID of a graphical object belonging to a program
//+------------------------------------------------------------------+
//| Enumerations                                                     |
//+------------------------------------------------------------------+


标准图形对象的编程方法

我们已拥有跟踪图表上手动创建图形对象、创建相应类对象并将它们添加到集合列表当中的方法。 当然,最好在当前的任务中使用它们,但有一些原因迫使我放弃使用部分现成的方法。 我们简单地跟踪计时器中图形对象的外观。 当以编程方式创建对象时,我不想等待计时器的下一次跳动,并定义新创建的对象,及其创建方法(编程和手动)。

取而代之,我将在图形元素集合类中创建构建标准图形对象的方法。 在构建对象之后,我将立即创建相应的类对象,并将其放置在集合当中。 搜索对象属性中的变化改由已创建的功能执行。 因此,我们将能够创建对象,并将其添加到集合当中,同时无需考虑对象创建方法,即可保留搜索其变化的能力。 将来,这将简化复合图形对象的创建和属性管理。

在以编程方式创建的图形对象时,其名称将包含源自创建对象程序的名称。 这将令我们能够区分“自我”图形对象,和手动创建的图形对象。
为了实现这一点,在图形元素集合类 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh 文件中的图表对象管理类的私密部分中添加存储程序名的新变量

//+------------------------------------------------------------------+
//| Chart object management class                                    |
//+------------------------------------------------------------------+
class CChartObjectsControl : public CObject
  {
private:
   CArrayObj         m_list_new_graph_obj;      // List of added graphical objects
   ENUM_TIMEFRAMES   m_chart_timeframe;         // Chart timeframe
   long              m_chart_id;                // Chart ID
   long              m_chart_id_main;           // Control program chart ID
   string            m_chart_symbol;            // Chart symbol
   bool              m_is_graph_obj_event;      // Event flag in the list of graphical objects
   int               m_total_objects;           // Number of graphical objects
   int               m_last_objects;            // Number of graphical objects during the previous check
   int               m_delta_graph_obj;         // Difference in the number of graphical objects compared to the previous check
   int               m_handle_ind;              // Event controller indicator handle
   string            m_name_ind;                // Short name of the event controller indicator
   string            m_name_program;            // Program name
   
//--- Return the name of the last graphical object added to the chart
   string            LastAddedGraphObjName(void);
//--- Set the permission to track mouse events and graphical objects
   void              SetMouseEvent(void);

public:

在类的公开部分,从 CreateNewGraphObj() 方法中删除指定图表 ID 的操作,因为该 ID 是图表对象的主要属性之一,其可直接从该对象获得,无需传递。
将程序名称赋值给类构造函数中的相应变量:

public:
//--- Return the variable values
   ENUM_TIMEFRAMES   Timeframe(void)                           const { return this.m_chart_timeframe;    }
   long              ChartID(void)                             const { return this.m_chart_id;           }
   string            Symbol(void)                              const { return this.m_chart_symbol;       }
   bool              IsEvent(void)                             const { return this.m_is_graph_obj_event; }
   int               TotalObjects(void)                        const { return this.m_total_objects;      }
   int               Delta(void)                               const { return this.m_delta_graph_obj;    }
//--- Create a new standard graphical object
   CGStdGraphObj    *CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name);
//--- Return the list of newly added objects
   CArrayObj        *GetListNewAddedObj(void)                        { return &this.m_list_new_graph_obj;}
//--- Create the event control indicator
   bool              CreateEventControlInd(const long chart_id_main);
//--- Add the event control indicator to the chart
   bool              AddEventControlInd(void);
//--- Check the chart objects
   void              Refresh(void);
//--- Constructors
                     CChartObjectsControl(void)
                       { 
                        this.m_name_program=::MQLInfoString(MQL_PROGRAM_NAME);
                        this.m_chart_id=::ChartID();
                        this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id);
                        this.m_chart_symbol=::ChartSymbol(this.m_chart_id);
                        this.m_chart_id_main=::ChartID();
                        this.m_list_new_graph_obj.Clear();
                        this.m_list_new_graph_obj.Sort();
                        this.m_is_graph_obj_event=false;
                        this.m_total_objects=0;
                        this.m_last_objects=0;
                        this.m_delta_graph_obj=0;
                        this.m_name_ind="";
                        this.m_handle_ind=INVALID_HANDLE;
                        this.SetMouseEvent();
                       }
                     CChartObjectsControl(const long chart_id)
                       { 
                        this.m_name_program=::MQLInfoString(MQL_PROGRAM_NAME);
                        this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id);
                        this.m_chart_symbol=::ChartSymbol(this.m_chart_id);
                        this.m_chart_id_main=::ChartID();
                        this.m_list_new_graph_obj.Clear();
                        this.m_list_new_graph_obj.Sort();
                        this.m_chart_id=chart_id;
                        this.m_is_graph_obj_event=false;
                        this.m_total_objects=0;
                        this.m_last_objects=0;
                        this.m_delta_graph_obj=0;
                        this.m_name_ind="";
                        this.m_handle_ind=INVALID_HANDLE;
                        this.SetMouseEvent();
                       }

除了检查空名称之外,确保对象不是在检查图表对象的方法中以编程方式创建的

//+------------------------------------------------------------------+
//| CChartObjectsControl: Check objects on a chart                   |
//+------------------------------------------------------------------+
void CChartObjectsControl::Refresh(void)
  {
//--- Graphical objects on the chart
   this.m_total_objects=::ObjectsTotal(this.ChartID());
   this.m_delta_graph_obj=this.m_total_objects-this.m_last_objects;
   
//--- If the number of objects has changed
   if(this.m_delta_graph_obj!=0)
     {
      //--- Create the string and display it in the journal with the chart ID, its symbol and timeframe
      string txt=", "+(m_delta_graph_obj>0 ? "Added: " : "Deleted: ")+(string)fabs(m_delta_graph_obj)+" obj";
      Print(DFUN,"ChartID=",this.ChartID(),", ",this.Symbol(),", ",TimeframeDescription(this.Timeframe()),txt);
     }
   //--- If an object is added to the chart
   if(this.m_delta_graph_obj>0)
     {
      //--- find the last added graphical object, select it and write its name
      string name=this.LastAddedGraphObjName();
      if(name!="" && ::StringFind(name,m_name_program)==WRONG_VALUE)
        {
         //--- Create the object of the graphical object class corresponding to the added graphical object type
         ENUM_OBJECT type=(ENUM_OBJECT)::ObjectGetInteger(this.ChartID(),name,OBJPROP_TYPE);
         ENUM_OBJECT_DE_TYPE obj_type=ENUM_OBJECT_DE_TYPE(type+OBJECT_DE_TYPE_GSTD_OBJ+1);
         CGStdGraphObj *obj=this.CreateNewGraphObj(type,name);
         if(obj==NULL)
            return;
         //--- Set the object affiliation and add the created object to the list of new objects
         obj.SetBelong(GRAPH_OBJ_BELONG_NO_PROGRAM); 
         if(this.m_list_new_graph_obj.Search(obj)==WRONG_VALUE)
           {
            this.m_list_new_graph_obj.Add(obj);
           }
        }
     }
     
//--- save the index of the last added graphical object and the difference with the last check
   this.m_last_objects=this.m_total_objects;
   this.m_is_graph_obj_event=(bool)this.m_delta_graph_obj;
  }
//+------------------------------------------------------------------+

换句话说,如果一个对象名没有包含程序名称的子字符串,那么该对象应由该方法处理,否则这是一个通过编程创建的图形对象,其应由另一个方法添加到集合列表当中。

在创建新标准图形对象的方法中以前需传递给方法的所有 chart_id,现在可由对象自身所含的 id 替换:

//+------------------------------------------------------------------+
//| CChartObjectsControl:                                            |
//| Create a new standard graphical object                           |
//+------------------------------------------------------------------+
CGStdGraphObj *CChartObjectsControl::CreateNewGraphObj(const ENUM_OBJECT obj_type,const string name)
  {
   CGStdGraphObj *obj=NULL;
   switch((int)obj_type)
     {
      //--- Lines
      case OBJ_VLINE             : return new CGStdVLineObj(this.ChartID(),name);
      case OBJ_HLINE             : return new CGStdHLineObj(this.ChartID(),name);
      case OBJ_TREND             : return new CGStdTrendObj(this.ChartID(),name);
      case OBJ_TRENDBYANGLE      : return new CGStdTrendByAngleObj(this.ChartID(),name);
      case OBJ_CYCLES            : return new CGStdCyclesObj(this.ChartID(),name);
      case OBJ_ARROWED_LINE      : return new CGStdArrowedLineObj(this.ChartID(),name);
      //--- Channels
      case OBJ_CHANNEL           : return new CGStdChannelObj(this.ChartID(),name);
      case OBJ_STDDEVCHANNEL     : return new CGStdStdDevChannelObj(this.ChartID(),name);
      case OBJ_REGRESSION        : return new CGStdRegressionObj(this.ChartID(),name);
      case OBJ_PITCHFORK         : return new CGStdPitchforkObj(this.ChartID(),name);
      //--- Gann
      case OBJ_GANNLINE          : return new CGStdGannLineObj(this.ChartID(),name);
      case OBJ_GANNFAN           : return new CGStdGannFanObj(this.ChartID(),name);
      case OBJ_GANNGRID          : return new CGStdGannGridObj(this.ChartID(),name);
      //--- Fibo
      case OBJ_FIBO              : return new CGStdFiboObj(this.ChartID(),name);
      case OBJ_FIBOTIMES         : return new CGStdFiboTimesObj(this.ChartID(),name);
      case OBJ_FIBOFAN           : return new CGStdFiboFanObj(this.ChartID(),name);
      case OBJ_FIBOARC           : return new CGStdFiboArcObj(this.ChartID(),name);
      case OBJ_FIBOCHANNEL       : return new CGStdFiboChannelObj(this.ChartID(),name);
      case OBJ_EXPANSION         : return new CGStdExpansionObj(this.ChartID(),name);
      //--- Elliott
      case OBJ_ELLIOTWAVE5       : return new CGStdElliotWave5Obj(this.ChartID(),name);
      case OBJ_ELLIOTWAVE3       : return new CGStdElliotWave3Obj(this.ChartID(),name);
      //--- Shapes
      case OBJ_RECTANGLE         : return new CGStdRectangleObj(this.ChartID(),name);
      case OBJ_TRIANGLE          : return new CGStdTriangleObj(this.ChartID(),name);
      case OBJ_ELLIPSE           : return new CGStdEllipseObj(this.ChartID(),name);
      //--- Arrows
      case OBJ_ARROW_THUMB_UP    : return new CGStdArrowThumbUpObj(this.ChartID(),name);
      case OBJ_ARROW_THUMB_DOWN  : return new CGStdArrowThumbDownObj(this.ChartID(),name);
      case OBJ_ARROW_UP          : return new CGStdArrowUpObj(this.ChartID(),name);
      case OBJ_ARROW_DOWN        : return new CGStdArrowDownObj(this.ChartID(),name);
      case OBJ_ARROW_STOP        : return new CGStdArrowStopObj(this.ChartID(),name);
      case OBJ_ARROW_CHECK       : return new CGStdArrowCheckObj(this.ChartID(),name);
      case OBJ_ARROW_LEFT_PRICE  : return new CGStdArrowLeftPriceObj(this.ChartID(),name);
      case OBJ_ARROW_RIGHT_PRICE : return new CGStdArrowRightPriceObj(this.ChartID(),name);
      case OBJ_ARROW_BUY         : return new CGStdArrowBuyObj(this.ChartID(),name);
      case OBJ_ARROW_SELL        : return new CGStdArrowSellObj(this.ChartID(),name);
      case OBJ_ARROW             : return new CGStdArrowObj(this.ChartID(),name);
      //--- Graphical objects
      case OBJ_TEXT              : return new CGStdTextObj(this.ChartID(),name);
      case OBJ_LABEL             : return new CGStdLabelObj(this.ChartID(),name);
      case OBJ_BUTTON            : return new CGStdButtonObj(this.ChartID(),name);
      case OBJ_CHART             : return new CGStdChartObj(this.ChartID(),name);
      case OBJ_BITMAP            : return new CGStdBitmapObj(this.ChartID(),name);
      case OBJ_BITMAP_LABEL      : return new CGStdBitmapLabelObj(this.ChartID(),name);
      case OBJ_EDIT              : return new CGStdEditObj(this.ChartID(),name);
      case OBJ_EVENT             : return new CGStdEventObj(this.ChartID(),name);
      case OBJ_RECTANGLE_LABEL   : return new CGStdRectangleLabelObj(this.ChartID(),name);
      default                    : return NULL;
     }
  }
//+------------------------------------------------------------------+


在图形对象的 CGraphElementsCollection 集合类中,即,在返回第一个可用图形对象 ID 的方法中添加标志,指定所需对象 ID:false — 对于手动创建的对象;true — 对于编程创建的对象:

//--- Return the first free ID of the graphical (1) object and (2) element on canvas
   long              GetFreeGraphObjID(bool program_object);
   long              GetFreeCanvElmID(void);
//--- Add a graphical object to the collection

声明创建新标准图形对象的私密方法

//--- Remove the object of managing charts from the list
   bool              DeleteGraphObjCtrlObjFromList(CChartObjectsControl *obj);
//--- Create a new standard graphical object, return an object name
   bool              CreateNewStdGraphObject(const long chart_id,
                                             const string name,
                                             const ENUM_OBJECT type,
                                             const int subwindow,
                                             const datetime time1,
                                             const double price1,
                                             const datetime time2=0,
                                             const double price2=0,
                                             const datetime time3=0,
                                             const double price3=0,
                                             const datetime time4=0,
                                             const double price4=0,
                                             const datetime time5=0,
                                             const double price5=0);
public:

在类的私密部分,编写创建新图形对象,并返回指向图表管理对象指针的方法:

//--- Event handler
   void              OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);

private:
//--- Create a new graphical object, return the pointer to the chart management object
   CChartObjectsControl *CreateNewStdGraphObjectAndGetCtrlObj(const long chart_id,
                                                              const string name,
                                                              int subwindow,
                                                              const ENUM_OBJECT type_object,
                                                              const datetime time1,
                                                              const double price1,
                                                              const datetime time2=0,
                                                              const double price2=0,
                                                              const datetime time3=0,
                                                              const double price3=0,
                                                              const datetime time4=0,
                                                              const double price4=0,
                                                              const datetime time5=0,
                                                              const double price5=0)
                       {
                        //--- If an object with a chart ID and name is already present in the collection, inform of that and return NULL
                        if(this.IsPresentGraphObjInList(chart_id,name))
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_GR_OBJ_ALREADY_EXISTS)," ChartID ",(string)chart_id,", ",name);
                           return NULL;
                          }
                        //--- If failed to create a new standard graphical object, inform of that and return NULL
                        if(!this.CreateNewStdGraphObject(chart_id,name,type_object,subwindow,time1,0))
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_STD_GRAPH_OBJ),StdGraphObjectTypeDescription(type_object));
                           CMessage::ToLog(::GetLastError(),true);
                           return NULL;
                          }
                        //--- If failed to get a chart management object, inform of that
                        CChartObjectsControl *ctrl=this.GetChartObjectCtrlObj(chart_id);
                        if(ctrl==NULL)
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_ELM_COLLECTION_ERR_FAILED_GET_CTRL_OBJ),(string)chart_id);
                        //--- Return the pointer to a chart management object or NULL in case of a failed attempt to get it
                        return ctrl;
                       }

public:

方法逻辑已在代码注释中描述。 该方法将在类的公开部分创建指定类型的标准图形对象时被调用。

创建“垂直线”图形对象的方法:

public:
//--- Create the "Vertical line" graphical object
   bool              CreateLineVertical(const long chart_id,const string name,const int subwindow,const datetime time)
                       {
                        //--- Set the name and type of a created object
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_VLINE;
                        //--- Create a new graphical object and get the pointer to the chart management object
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,0);
                        if(ctrl==NULL)
                           return false;
                        //--- Create a new class object corresponding to the newly created graphical object
                        CGStdVLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        //--- If failed to add an object to the collection list,
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           //--- inform of that, remove the graphical and class object, and return 'false'
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        //--- Redraw the chart and display all object properties in the journal (temporarily, for test purposes only)
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

该方法的代码注释中已有详细描述。 每个特定对象中固有的属性,以及参数中传递的属性,将在每个此类对象中进行设置。 首先在指定的图表上创建一个物理图形对象,形成指向图表管理对象的指针。 其 CreateNewGraphObj() 方法创建与指定类型相对应的类对象。 如果将对象添加到列表中失败,则物理图形对象本身和类对象将被删除,并向日志发送错误消息。 如果创建成功,图表将被更新,方法将返回 true

其余创建图形对象的方法与上述方法雷同,仅在为每个特定图形对象定义的参数集上有所区别。
我们来看看添加的其它所有方法的清单:

//--- Create the "Horizontal line" graphical object
   bool              CreateLineHorizontal(const long chart_id,const string name,const int subwindow,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_HLINE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdHLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }
 
//--- Create the "Trend line" graphical object
   bool              CreateLineTrend(const long chart_id,const string name,const int subwindow,
                                     const datetime time1,const double price1,const datetime time2,const double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_TREND;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdTrendObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }
//--- Create the "Trend line by angle" graphical object
   bool              CreateLineTrendByAngle(const long chart_id,const string name,const int subwindow,
                                            const datetime time1,const double price1,const datetime time2,const double price2,const double angle)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_TRENDBYANGLE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdTrendByAngleObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetAngle(angle);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Cyclic lines" graphical object
   bool              CreateLineCycle(const long chart_id,const string name,const int subwindow,
                                     const datetime time1,double price1,const datetime time2,double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_CYCLES;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdCyclesObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Arrowed line" graphical object
   bool              CreateLineArrowed(const long chart_id,const string name,const int subwindow,
                                       const datetime time1,double price1,const datetime time2,double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROWED_LINE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowedLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Equidistant channel" graphical object
   bool              CreateChannel(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,double price1,const datetime time2,
                                   double price2,const datetime time3,double price3)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_CHANNEL;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdChannelObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Standard deviation channel" graphical object
   bool              CreateChannelStdDeviation(const long chart_id,const string name,const int subwindow,
                                               const datetime time1,double price1,const datetime time2,double price2,const double deviation=1.5)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_STDDEVCHANNEL;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdStdDevChannelObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetDeviation(deviation);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Linear regression channel" graphical object
   bool              CreateChannelRegression(const long chart_id,const string name,const int subwindow,
                                             const datetime time1,double price1,const datetime time2,double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_REGRESSION;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdRegressionObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Andrews' Pitchfork" graphical object
   bool              CreatePitchforkAndrews(const long chart_id,const string name,const int subwindow,
                                            const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_PITCHFORK;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdPitchforkObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Gann line" graphical object
   bool              CreateGannLine(const long chart_id,const string name,const int subwindow,
                                    const datetime time1,double price1,const datetime time2,double price2,double angle)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_GANNLINE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdGannLineObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetAngle(angle);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Gann fan" graphical object
   bool              CreateGannFan(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,double price1,const datetime time2,double price2,
                                   const ENUM_GANN_DIRECTION direction,const double scale)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_GANNFAN;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdGannFanObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetDirection(direction);
                        obj.SetScale(scale);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Gann grid" graphical object
   bool              CreateGannGrid(const long chart_id,const string name,const int subwindow,
                                    const datetime time1,double price1,const datetime time2,
                                    const ENUM_GANN_DIRECTION direction,const double scale)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_GANNGRID;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdGannGridObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetDirection(direction);
                        obj.SetScale(scale);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Fibo levels" graphical object
   bool              CreateFiboLevels(const long chart_id,const string name,const int subwindow,
                                      const datetime time1,double price1,const datetime time2,double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_FIBO;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdFiboObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Fibo Time Zones" graphical object
   bool              CreateFiboTimeZones(const long chart_id,const string name,const int subwindow,
                                         const datetime time1,double price1,const datetime time2,double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_FIBOTIMES;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdFiboTimesObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Fibo fan" graphical object
   bool              CreateFiboFan(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,double price1,const datetime time2,double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_FIBOFAN;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdFiboFanObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Fibo arc" graphical object
   bool              CreateFiboArc(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,double price1,const datetime time2,double price2,
                                   const double scale,const bool ellipse)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_FIBOARC;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdFiboArcObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetScale(scale);
                        obj.SetFlagEllipse(ellipse);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Fibo channel" graphical object
   bool              CreateFiboChannel(const long chart_id,const string name,const int subwindow,
                                       const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_FIBOCHANNEL;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdFiboChannelObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }
//--- Create the "Fibo extension" graphical object
   bool              CreateFiboExpansion(const long chart_id,const string name,const int subwindow,
                                         const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_EXPANSION;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdExpansionObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Elliott 5 waves" graphical object
   bool              CreateElliothWave5(const long chart_id,const string name,const int subwindow,
                                        const datetime time1,double price1,const datetime time2,double price2,
                                        const datetime time3,double price3,const datetime time4,double price4,
                                        const datetime time5,double price5,const ENUM_ELLIOT_WAVE_DEGREE degree,
                                        const bool draw_lines)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ELLIOTWAVE5;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdElliotWave5Obj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetDegree(degree);
                        obj.SetFlagDrawLines(draw_lines);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Elliott 3 waves" graphical object
   bool              CreateElliothWave3(const long chart_id,const string name,const int subwindow,
                                        const datetime time1,double price1,const datetime time2,
                                        double price2,const datetime time3,double price3,
                                        const ENUM_ELLIOT_WAVE_DEGREE degree,const bool draw_lines)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ELLIOTWAVE3;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdElliotWave3Obj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetDegree(degree);
                        obj.SetFlagDrawLines(draw_lines);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Rectangle graphical object
   bool              CreateRectangle(const long chart_id,const string name,const int subwindow,
                                     const datetime time1,double price1,const datetime time2,double price2)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_RECTANGLE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdRectangleObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Triangle graphical object
   bool              CreateTriangle(const long chart_id,const string name,const int subwindow,
                                    const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_TRIANGLE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdTriangleObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Ellipse graphical object
   bool              CreateEllipse(const long chart_id,const string name,const int subwindow,
                                   const datetime time1,double price1,const datetime time2,double price2,const datetime time3,double price3)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ELLIPSE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time1,price1,time2,price2,time3,price3);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdEllipseObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Thumb up" graphical object
   bool              CreateThumbUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_THUMB_UP;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowThumbUpObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Thumb down" graphical object
   bool              CreateThumbDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_THUMB_DOWN;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowThumbDownObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Arrow up" graphical object
   bool              CreateArrowUp(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_UP;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowUpObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Arrow down" graphical object
   bool              CreateArrowDown(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_DOWN;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowDownObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Stop graphical object
   bool              CreateSignalStop(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_STOP;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowStopObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Check mark" graphical object
   bool              CreateSignalCheck(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_CHECK;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowCheckObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Left price label" graphical object
   bool              CreatePriceLabelLeft(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_LEFT_PRICE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowLeftPriceObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Right price label" graphical object
   bool              CreatePriceLabelRight(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_RIGHT_PRICE;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowRightPriceObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Buy graphical object
   bool              CreateSignalBuy(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_BUY;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowBuyObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Sell graphical object
   bool              CreateSignalSell(const long chart_id,const string name,const int subwindow,const datetime time,const double price)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW_SELL;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowSellObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Arrow graphical object
   bool              CreateArrow(const long chart_id,const string name,const int subwindow,const datetime time,const double price,
                                 const uchar arrow_code,const ENUM_ARROW_ANCHOR anchor)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_ARROW;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdArrowObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetArrowCode(arrow_code);
                        obj.SetAnchor(anchor);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }
//--- Create the Text graphical object
   bool              CreateText(const long chart_id,const string name,const int subwindow,const datetime time,const double price,
                                const string text,const int size,const ENUM_ANCHOR_POINT anchor_point,const double angle)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_TEXT;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdTextObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetText(text);
                        obj.SetFontSize(size);
                        obj.SetAnchor(anchor_point);
                        obj.SetAngle(angle);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Text label" graphical object
   bool              CreateTextLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,
                                     const string text,const int size,const ENUM_BASE_CORNER corner,
                                     const ENUM_ANCHOR_POINT anchor_point,const double angle)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_LABEL;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdLabelObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetXDistance(x);
                        obj.SetYDistance(y);
                        obj.SetText(text);
                        obj.SetFontSize(size);
                        obj.SetCorner(corner);
                        obj.SetAnchor(anchor_point);
                        obj.SetAngle(angle);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Button graphical object
   bool              CreateButton(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                  const ENUM_BASE_CORNER corner,const int font_size,const bool button_state)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_BUTTON;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdButtonObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetXDistance(x);
                        obj.SetYDistance(y);
                        obj.SetXSize(w);
                        obj.SetYSize(h);
                        obj.SetCorner(corner);
                        obj.SetFontSize(font_size);
                        obj.SetFlagState(button_state);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Chart graphical object
   bool              CreateChart(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                 const ENUM_BASE_CORNER corner,const int scale,const string symbol,const ENUM_TIMEFRAMES timeframe)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_CHART;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdChartObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        obj.SetXDistance(x);
                        obj.SetYDistance(y);
                        obj.SetXSize(w);
                        obj.SetYSize(h);
                        obj.SetCorner(corner);
                        obj.SetChartObjChartScale(scale);
                        obj.SetChartObjSymbol(symbol);
                        obj.SetChartObjPeriod(timeframe);
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the Bitmap graphical object
   bool              CreateBitmap(const long chart_id,const string name,const int subwindow,const datetime time,const double price,
                                  const string image1,const string image2,const ENUM_ANCHOR_POINT anchor)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_BITMAP;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,price);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdBitmapObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetAnchor(anchor);
                        obj.SetBMPFile(image1,0);
                        obj.SetBMPFile(image2,1);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Bitmap label" graphical object
   bool              CreateBitmapLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                       const string image1,const string image2,const ENUM_BASE_CORNER corner,const ENUM_ANCHOR_POINT anchor,
                                       const bool state)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_BITMAP_LABEL;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdBitmapLabelObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetXDistance(x);
                        obj.SetYDistance(y);
                        obj.SetXSize(w);
                        obj.SetYSize(h);
                        obj.SetCorner(corner);
                        obj.SetAnchor(anchor);
                        obj.SetBMPFile(image1,0);
                        obj.SetBMPFile(image2,1);
                        obj.SetFlagState(state);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Input field" graphical object
   bool              CreateEditField(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                     const int font_size,const ENUM_BASE_CORNER corner,const ENUM_ALIGN_MODE align,const bool readonly)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_EDIT;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdEditObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetXDistance(x);
                        obj.SetYDistance(y);
                        obj.SetXSize(w);
                        obj.SetYSize(h);
                        obj.SetFontSize(font_size);
                        obj.SetCorner(corner);
                        obj.SetAlign(align);
                        obj.SetFlagReadOnly(readonly);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Economic calendar event" graphical object
   bool              CreateCalendarEvent(const long chart_id,const string name,const int subwindow,const datetime time)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_EVENT;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,time,0);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdEventObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }

//--- Create the "Rectangular label" graphical object
   bool              CreateRectangleLabel(const long chart_id,const string name,const int subwindow,const int x,const int y,const int w,const int h,
                                          const ENUM_BASE_CORNER corner,const ENUM_BORDER_TYPE border)
                       {
                        string nm=this.m_name_program+"_"+name;
                        ENUM_OBJECT type_object=OBJ_RECTANGLE_LABEL;
                        CChartObjectsControl *ctrl=this.CreateNewStdGraphObjectAndGetCtrlObj(chart_id,nm,subwindow,type_object,0,0);
                        if(ctrl==NULL)
                           return false;
                        
                        CGStdRectangleLabelObj *obj=ctrl.CreateNewGraphObj(type_object,nm);
                        if(obj==NULL)
                          {
                           ::Print(DFUN,CMessage::Text(MSG_GRAPH_STD_OBJ_ERR_FAILED_CREATE_CLASS_OBJ),StdGraphObjectTypeDescription(type_object));
                           return false;
                          }
                        //--- Set the necessary minimal parameters for an object
                        obj.SetBelong(GRAPH_OBJ_BELONG_PROGRAM);
                        obj.SetFlagSelectable(true);
                        obj.SetFlagSelected(true);
                        obj.SetObjectID(this.GetFreeGraphObjID(true));
                        obj.SetXDistance(x);
                        obj.SetYDistance(y);
                        obj.SetXSize(w);
                        obj.SetYSize(h);
                        obj.SetCorner(corner);
                        obj.SetBorderType(border);
                        obj.PropertiesCopyToPrevData();
                        
                        if(!this.m_list_all_graph_obj.Add(obj))
                          {
                           CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
                           ::ObjectDelete(chart_id,nm);
                           delete obj;
                           return false;
                          }
                        ::ChartRedraw(chart_id);
                        obj.Print();
                        return true;
                       }
 
  };
//+------------------------------------------------------------------+

所有方法都有自己的输入集合。 这些参数设置的最小对象属性,足以创建一个对象。 创建图形对象后,所有其余的属性可以随时更改。

返回第一个可用图形对象 ID 的方法:

//+------------------------------------------------------------------+
//| Return the first free graphical object ID                        |
//+------------------------------------------------------------------+
long CGraphElementsCollection::GetFreeGraphObjID(bool program_object)
  {
   CArrayObj *list=NULL;
   int index=WRONG_VALUE;
   if(program_object)
      list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ID,0,PROGRAM_OBJ_MAX_ID,EQUAL_OR_LESS);
   else
      list=CSelect::ByGraphicStdObjectProperty(this.GetListGraphObj(),GRAPH_OBJ_PROP_ID,0,PROGRAM_OBJ_MAX_ID,MORE);
   index=CSelect::FindGraphicStdObjectMax(list,GRAPH_OBJ_PROP_ID,0);
   CGStdGraphObj *obj=list.At(index);
   int first_id=(program_object ? 1 : PROGRAM_OBJ_MAX_ID+1);
   return(obj!=NULL ? obj.ObjectID()+1 : first_id);
  }
//+------------------------------------------------------------------+

现在,该方法要考虑接收所需的 ID。
如果它用于编程创建图形对象,则获取 ID 小于或等于 PROGRAM_OBJ_MAX_ID (10000) 常量值的所有对象的列表。
如果它用于手动创建图形对象,则获取 ID 大于 PROGRAM_OBJ_MAX_ID 的所有对象的列表。
接下来,从获得的列表中提取最大 ID 的对象索引,并依据其索引获取所列对象
接着,计算第一个 ID 的值(对于编程对象 — 1,对于手动创建对象 — 10000+1)。
如果接收到 ID 最大的对象,则取其 ID+1 的值否则,对象不在列表中,并返回第一个计算 ID 值(1 或 10001)。

在添加图形对象到集合的方法中找出一个对象是通过编程还是手动创建的(依据对象名)来搜索 ID,并将其值传递给 GetFreeGraphBobjid() 方法:

//+------------------------------------------------------------------+
//| Add a graphical object to the collection                         |
//+------------------------------------------------------------------+
bool CGraphElementsCollection::AddGraphObjToCollection(const string source,CChartObjectsControl *obj_control)
  {
   //--- Get the list of the last added graphical objects from the class for managing graphical objects
   CArrayObj *list=obj_control.GetListNewAddedObj();
   //--- If failed to obtain the list, inform of that and return 'false'
   if(list==NULL)
     {
      CMessage::ToLog(DFUN_ERR_LINE,MSG_GRAPH_OBJ_FAILED_GET_ADDED_OBJ_LIST);
      return false;
     }
   //--- If the list is empty, return 'false'
   if(list.Total()==0)
      return false;
   //--- Declare the variable for storing the result
   bool res=true;
   //--- In the loop by the list of newly added standard graphical objects,
   for(int i=0;i<list.Total();i++)
     {
      //--- retrieve the next object from the list and
      CGStdGraphObj *obj=list.Detach(i);
      //--- if failed to retrieve the object, inform of that, add 'false' to the resulting variable and move on to the next one
      if(obj==NULL)
        {
         CMessage::ToLog(source,MSG_GRAPH_OBJ_FAILED_DETACH_OBJ_FROM_LIST);
         res &=false;
         continue;
        }
      //--- if failed to add the object to the collection list, inform of that,
      //--- remove the object, add 'false' to the resulting variable and move on to the next one
      if(!this.m_list_all_graph_obj.Add(obj))
        {
         CMessage::ToLog(source,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
         delete obj;
         res &=false;
         continue;
        }
      //--- The object has been successfully retrieved from the list of newly added graphical objects and introduced into the collection -
      //--- find the next free object ID, write it to the property and display the short object description in the journal
      else
        {
         bool program_object=(::StringFind(obj.Name(),this.m_name_program)==0);
         obj.SetObjectID(this.GetFreeGraphObjID(program_object));
         obj.Print();
        }
     }
   //--- Return the result of adding the object to the collection
   return res;
  }
//+------------------------------------------------------------------+

我们去掉 if-else,并添加对象单击跟踪来简化事件处理程序逻辑,从而判断用鼠标选择对象(尚未实现):

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CGraphElementsCollection::OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   CGStdGraphObj *obj=NULL;
   ushort idx=ushort(id-CHARTEVENT_CUSTOM);
   if(id==CHARTEVENT_OBJECT_CHANGE  || id==CHARTEVENT_OBJECT_DRAG    || 
      idx==CHARTEVENT_OBJECT_CHANGE || idx==CHARTEVENT_OBJECT_DRAG   ||
      id==CHARTEVENT_OBJECT_CLICK   || idx==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Get the chart ID. If lparam is zero,
      //--- the event is from the current chart,
      //--- otherwise, this is a custom event from an indicator
      long chart_id=(lparam==0 ? ::ChartID() : lparam);
      //--- Get the object, whose properties were changed or which was relocated,
      //--- from the collection list by its name set in sparam
      obj=this.GetStdGraphObject(sparam,chart_id);
      
      //--- If failed to get the object by its name, it is not on the list,
      //--- which means its name has been changed
      if(obj==NULL)
        {
         //--- Let's search the list for the object that is not on the chart
         obj=this.FindMissingObj(chart_id);
         //--- If failed to find the object here as well, exit
         if(obj==NULL)
            return;
         //--- Get the name of the renamed graphical object on the chart, which is not in the collection list
         string name_new=this.FindExtraObj(chart_id);
         //--- Set a new name for the collection list object, which does not correspond to any graphical object on the chart
         obj.SetName(name_new);
        }
      //--- Update the properties of the obtained object
      //--- and check their change
      obj.PropertiesRefresh();
      obj.PropertiesCheckChanged();
     }
  }
//+------------------------------------------------------------------+

创建新标准图形对象的方法:

//+------------------------------------------------------------------+
//| Create a new standard graphical object                           |
//+------------------------------------------------------------------+
bool CGraphElementsCollection::CreateNewStdGraphObject(const long chart_id,
                                                       const string name,
                                                       const ENUM_OBJECT type,
                                                       const int subwindow,
                                                       const datetime time1,
                                                       const double price1,
                                                       const datetime time2=0,
                                                       const double price2=0,
                                                       const datetime time3=0,
                                                       const double price3=0,
                                                       const datetime time4=0,
                                                       const double price4=0,
                                                       const datetime time5=0,
                                                       const double price5=0)
  {
   ::ResetLastError();
   switch(type)
     {
      //--- Lines
      case OBJ_VLINE             : return ::ObjectCreate(chart_id,name,OBJ_VLINE,subwindow,time1,0);
      case OBJ_HLINE             : return ::ObjectCreate(chart_id,name,OBJ_HLINE,subwindow,0,price1);
      case OBJ_TREND             : return ::ObjectCreate(chart_id,name,OBJ_TREND,subwindow,time1,price1,time2,price2);
      case OBJ_TRENDBYANGLE      : return ::ObjectCreate(chart_id,name,OBJ_TRENDBYANGLE,subwindow,time1,price1,time2,price2);
      case OBJ_CYCLES            : return ::ObjectCreate(chart_id,name,OBJ_CYCLES,subwindow,time1,price1,time2,price2);
      case OBJ_ARROWED_LINE      : return ::ObjectCreate(chart_id,name,OBJ_ARROWED_LINE,subwindow,time1,price1,time2,price2);
      //--- Channels
      case OBJ_CHANNEL           : return ::ObjectCreate(chart_id,name,OBJ_CHANNEL,subwindow,time1,price1,time2,price2,time3,price3);
      case OBJ_STDDEVCHANNEL     : return ::ObjectCreate(chart_id,name,OBJ_STDDEVCHANNEL,subwindow,time1,price1,time2,price2);
      case OBJ_REGRESSION        : return ::ObjectCreate(chart_id,name,OBJ_REGRESSION,subwindow,time1,price1,time2,price2);
      case OBJ_PITCHFORK         : return ::ObjectCreate(chart_id,name,OBJ_PITCHFORK,subwindow,time1,price1,time2,price2,time3,price3);
      //--- Gann
      case OBJ_GANNLINE          : return ::ObjectCreate(chart_id,name,OBJ_GANNLINE,subwindow,time1,price1,time2,price2);
      case OBJ_GANNFAN           : return ::ObjectCreate(chart_id,name,OBJ_GANNFAN,subwindow,time1,price1,time2,price2);
      case OBJ_GANNGRID          : return ::ObjectCreate(chart_id,name,OBJ_GANNGRID,subwindow,time1,price1,time2,price2);
      //--- Fibo
      case OBJ_FIBO              : return ::ObjectCreate(chart_id,name,OBJ_FIBO,subwindow,time1,price1,time2,price2);
      case OBJ_FIBOTIMES         : return ::ObjectCreate(chart_id,name,OBJ_FIBOTIMES,subwindow,time1,price1,time2,price2);
      case OBJ_FIBOFAN           : return ::ObjectCreate(chart_id,name,OBJ_FIBOFAN,subwindow,time1,price1,time2,price2);
      case OBJ_FIBOARC           : return ::ObjectCreate(chart_id,name,OBJ_FIBOARC,subwindow,time1,price1,time2,price2);
      case OBJ_FIBOCHANNEL       : return ::ObjectCreate(chart_id,name,OBJ_FIBOCHANNEL,subwindow,time1,price1,time2,price2,time3,price3);
      case OBJ_EXPANSION         : return ::ObjectCreate(chart_id,name,OBJ_EXPANSION,subwindow,time1,price1,time2,price2,time3,price3);
      //--- Elliott
      case OBJ_ELLIOTWAVE5       : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE5,subwindow,time1,price1,time2,price2,time3,price3,time4,price4,time5,price5);
      case OBJ_ELLIOTWAVE3       : return ::ObjectCreate(chart_id,name,OBJ_ELLIOTWAVE3,subwindow,time1,price1,time2,price2,time3,price3);
      //--- Shapes
      case OBJ_RECTANGLE         : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE,subwindow,time1,price1,time2,price2);
      case OBJ_TRIANGLE          : return ::ObjectCreate(chart_id,name,OBJ_TRIANGLE,subwindow,time1,price1,time2,price2,time3,price3);
      case OBJ_ELLIPSE           : return ::ObjectCreate(chart_id,name,OBJ_ELLIPSE,subwindow,time1,price1,time2,price2,time3,price3);
      //--- Arrows
      case OBJ_ARROW_THUMB_UP    : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_UP,subwindow,time1,price1);
      case OBJ_ARROW_THUMB_DOWN  : return ::ObjectCreate(chart_id,name,OBJ_ARROW_THUMB_DOWN,subwindow,time1,price1);
      case OBJ_ARROW_UP          : return ::ObjectCreate(chart_id,name,OBJ_ARROW_UP,subwindow,time1,price1);
      case OBJ_ARROW_DOWN        : return ::ObjectCreate(chart_id,name,OBJ_ARROW_DOWN,subwindow,time1,price1);
      case OBJ_ARROW_STOP        : return ::ObjectCreate(chart_id,name,OBJ_ARROW_STOP,subwindow,time1,price1);
      case OBJ_ARROW_CHECK       : return ::ObjectCreate(chart_id,name,OBJ_ARROW_CHECK,subwindow,time1,price1);
      case OBJ_ARROW_LEFT_PRICE  : return ::ObjectCreate(chart_id,name,OBJ_ARROW_LEFT_PRICE,subwindow,time1,price1);
      case OBJ_ARROW_RIGHT_PRICE : return ::ObjectCreate(chart_id,name,OBJ_ARROW_RIGHT_PRICE,subwindow,time1,price1);
      case OBJ_ARROW_BUY         : return ::ObjectCreate(chart_id,name,OBJ_ARROW_BUY,subwindow,time1,price1);
      case OBJ_ARROW_SELL        : return ::ObjectCreate(chart_id,name,OBJ_ARROW_SELL,subwindow,time1,price1);
      case OBJ_ARROW             : return ::ObjectCreate(chart_id,name,OBJ_ARROW,subwindow,time1,price1);
      //--- Graphical objects
      case OBJ_TEXT              : return ::ObjectCreate(chart_id,name,OBJ_TEXT,subwindow,time1,price1);
      case OBJ_LABEL             : return ::ObjectCreate(chart_id,name,OBJ_LABEL,subwindow,0,0);
      case OBJ_BUTTON            : return ::ObjectCreate(chart_id,name,OBJ_BUTTON,subwindow,0,0);
      case OBJ_CHART             : return ::ObjectCreate(chart_id,name,OBJ_CHART,subwindow,0,0);
      case OBJ_BITMAP            : return ::ObjectCreate(chart_id,name,OBJ_BITMAP,subwindow,time1,price1);
      case OBJ_BITMAP_LABEL      : return ::ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,subwindow,0,0);
      case OBJ_EDIT              : return ::ObjectCreate(chart_id,name,OBJ_EDIT,subwindow,0,0);
      case OBJ_EVENT             : return ::ObjectCreate(chart_id,name,OBJ_EVENT,subwindow,time1,0);
      case OBJ_RECTANGLE_LABEL   : return ::ObjectCreate(chart_id,name,OBJ_RECTANGLE_LABEL,subwindow,0,0);
      //---
      default: return false;
     }
  }
//+------------------------------------------------------------------+

该方法接收对象所处的图表 ID、其名称、类型、图表子窗口,和五个轴心点坐标。 第一个坐标(时间和价格)是必需的,而其它坐标都有预定义的默认值,允许用户构建任何标准图形对象。 在该方法中,重置最后一个错误代码,并根据对象类型返回 ObjectCreate() 函数执行的结果。 在对象创建错误的情况下,上面研究的 CreateNewStdGraphObjectAndGetCtrlObj() 方法和调用方法,都会向日志发送含有错误代码及其描述的消息。

现在,一切就绪,可以测试改进实现的类,以及可编程标准图形对象。

测试

我不会创建所有图形对象,而是将限定为一条垂直线。 在图表上按住 Ctrl 键的同时单击鼠标左键,将创建该垂线。 我们检查一下对象的创建,在尝试创建同名对象时处理错误,处理时间坐标的更改,以及跟踪含有两个以上轴点的对象更改其轴点坐标。

为了执行测试,我借助来自上一篇文章中的 EA,并将其保存在 \MQL5\Experts\TestDoEasy\Part89\ 中,命名为 TestDoEasyPart89.mq5

在 EA 的 OnChartEvent() 应答程序中,禁用按住 Ctrl 键创建窗体对象的代码块添加代码块,在图表上按住 Ctrl 键的同时用鼠标单击坐标,创建含有指定名称的垂直线

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- If working in the tester, exit
   if(MQLInfoInteger(MQL_TESTER))
      return;
//--- If the mouse is moved
   /*
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      CForm *form=NULL;
      datetime time=0;
      double price=0;
      int wnd=0;
      
      //--- If Ctrl is not pressed,
      if(!IsCtrlKeyPressed())
        {
         //--- clear the list of created form objects, allow scrolling a chart with the mouse and show the context menu
         list_forms.Clear();
         ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,true);
         ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,true);
         return;
        }
      
      //--- If X and Y chart coordinates are successfully converted into time and price,
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price))
        {
         //--- get the bar index the cursor is hovered over
         int index=iBarShift(Symbol(),PERIOD_CURRENT,time);
         if(index==WRONG_VALUE)
            return;
         
         //--- Get the bar index by index
         CBar *bar=engine.SeriesGetBar(Symbol(),Period(),index);
         if(bar==NULL)
            return;
         
         //--- Convert the coordinates of a chart from the time/price representation of the bar object to the X and Y coordinates
         int x=(int)lparam,y=(int)dparam;
         if(!ChartTimePriceToXY(ChartID(),0,bar.Time(),(bar.Open()+bar.Close())/2.0,x,y))
            return;
         
         //--- Disable moving a chart with the mouse and showing the context menu
         ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,false);
         ChartSetInteger(ChartID(),CHART_CONTEXT_MENU,false);
         
         //--- Create the form object name and hide all objects except one having such a name
         string name="FormBar_"+(string)index;
         HideFormAllExceptOne(name);
         
         //--- If the form object with such a name does not exist yet,
         if(!IsPresentForm(name))
           {
            //--- create a new form object
            form=bar.CreateForm(index,name,x,y,114,16);   
            if(form==NULL)
               return;
            
            //--- Set activity and unmoveability flags for the form
            form.SetActive(true);
            form.SetMovable(false);
            //--- Set the opacity of 200
            form.SetOpacity(200);
            //--- The form background color is set as the first color from the color array
            form.SetColorBackground(array_clr[0]);
            //--- Form outlining frame color
            form.SetColorFrame(C'47,70,59');
            //--- Draw the shadow drawing flag
            form.SetShadow(true);
            //--- Calculate the shadow color as the chart background color converted to the monochrome one
            color clrS=form.ChangeColorSaturation(form.ColorBackground(),-100);
            //--- If the settings specify the usage of the chart background color, replace the monochrome color with 20 units
            //--- Otherwise, use the color specified in the settings for drawing the shadow
            color clr=(InpUseColorBG ? form.ChangeColorLightness(clrS,-20) : InpColorForm3);
            //--- Draw the form shadow with the right-downwards offset from the form by three pixels along all axes
            //--- Set the shadow opacity to 200, while the blur radius is equal to 4
            form.DrawShadow(2,2,clr,200,3);
            //--- Fill the form background with a vertical gradient
            form.Erase(array_clr,form.Opacity());
            //--- Draw an outlining rectangle at the edges of the form
            form.DrawRectangle(0,0,form.Width()-1,form.Height()-1,form.ColorFrame(),form.Opacity());
            //--- If failed to add the form object to the list, remove the form and exit the handler
            if(!list_forms.Add(form))
              {
               delete form;
               return;
              }
            //--- Capture the form appearance
            form.Done();
           }
         //--- If the form object exists,
         if(form!=NULL)
           {
            //--- draw a text with the bar type description on it and show the form. The description corresponds to the mouse cursor position
            form.TextOnBG(0,bar.BodyTypeDescription(),form.Width()/2,form.Height()/2-1,FRAME_ANCHOR_CENTER,C'7,28,21');
            form.Show();
           }
         //--- Re-draw the chart
         ChartRedraw();
        }
     }
   */
   if(id==CHARTEVENT_CLICK)
     {
      if(!IsCtrlKeyPressed())
         return;
      datetime time=0;
      double price=0;
      int sw=0;
      if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,sw,time,price))
         engine.GetGraphicObjCollection().CreateLineVertical(ChartID(),"LineVertical",0,time);
     }
   engine.GetGraphicObjCollection().OnChartEvent(id,lparam,dparam,sparam);
   
  }
//+------------------------------------------------------------------+

编译 EA,并在图表上启动它。

首先,在图表上按住 Ctrl 键的同时单击鼠标,创建一条垂直线,查看垂线 ID,以及当它沿图表移动线时对象属性的变化。 如果我们重新创建同一条垂线,我们在日志中会收到错误消息
接下来,创建一个等距通道,查看其 ID 值,并检查如何跟踪其三个轴点属性的变化:



下一步是什么?

在下一篇文章中,我将继续研究可编程图形对象的功能。

以下是该函数库当前版本的所有文件,以及 MQL5 的测试 EA 文件,供您测试和下载。 请记住,您需要来自第八十七部分中的指标文件,以便让函数库处理不属于该程序所创的图表图形对象。

在评论中留下您的问题、意见和建议。

返回内容目录

*该系列的前几篇文章:


本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/10119

附加的文件 |
MQL5.zip (4174.43 KB)
在 MQL5 中使用 AutoIt 在 MQL5 中使用 AutoIt
简述。 在本文中,我们将探索采用 MetraTrader 5 终端里以集成的 MQL5 编写 AutoIt 脚本。 在其中,我们将覆盖如何操纵终端的用户界面来自动完成各种任务,并介绍一个采用 AutoItX 库的类。
固化价格动作止损或固化 RSI(智能止损) 固化价格动作止损或固化 RSI(智能止损)
在交易中,止损是资金管理采用的主要工具。 有效利用止损、获利回吐和成交量可以使交易者在交易中更加一致,总体上更加有利可图。 尽管止损是一个极好的工具,但在运用中也会遇到一些挑战。 最主要的是止损猎杀(stop-loss hunt)。 本文展望如何降低交易中的猎杀,并与经典的止损用例进行比较,从而判定其盈利能力。
以 Doji(十字星)为例阐述改进的烛条形态识别 以 Doji(十字星)为例阐述改进的烛条形态识别
如何找到比平常更多的烛条形态? 简单的烛条形态背后,还有一个严重的瑕疵,可经由现代自动交易化工具所提供的强大能力来抵消。
针对交易的组合数学和概率论(第五部分):曲线分析 针对交易的组合数学和概率论(第五部分):曲线分析
在本文中,我决定进行一项研究,探讨将多重状态系统简化为双重状态系统的可能性。 本文的主要目的是分析并推导出有用的结论,这些结论也许有助于基于概率论的可伸缩交易算法的深入发展。 当然,这个话题会涉及到数学知识。 不过,根据之前文章的经验,我认为广谱信息比细节作用更大。