English Русский 中文 Español 日本語 Português
Grafiken in der Bibliothek DoEasy (Teil 89): Programmieren von grafischen Standardobjekten, grundlegende Funktionsweise

Grafiken in der Bibliothek DoEasy (Teil 89): Programmieren von grafischen Standardobjekten, grundlegende Funktionsweise

MetaTrader 5Beispiele | 25 Januar 2022, 16:19
282 0
Artyom Trishkin
Artyom Trishkin

Inhalt


Konzept

Derzeit ist die Bibliothek in der Lage, Standard-Grafikobjekte auf dem Client-Terminal-Chart zu kontrollieren, einschließlich ihrer Entfernung und Änderung einiger ihrer Parameter. Manchmal ist es nützlich, über neu eingestellte, geänderte oder entfernte nutzerdefinierte grafische Objekte in einem Charts direkt aus Ihrem Programm zu wissen. Im Moment fehlt uns jedoch die Möglichkeit, Standard-Grafikobjekte aus nutzerdefinierten Programmen zu erstellen. Mit der Möglichkeit, grafische Objekte zu programmieren und Änderungen ihrer Eigenschaften zu verfolgen, können wir zusammengesetzte grafische Objekte beliebiger Komplexität, Verschachtelungstiefe und Anzahl kontrollierter Pivotpunkte erstellen. In diesem Artikel werde ich die grundlegenden Funktionen für die Programmierung grafischer Standardobjekte erstellen. Ich werde die Funktionalität in den kommenden Artikeln verfeinern und dabei die Möglichkeit berücksichtigen, nutzerdefinierte zusammengesetzte grafische Objekte auf der Grundlage der Standardobjekte zu erstellen.

Außerdem werde ich nach und nach dafür sorgen, dass Bibliotheksobjekte dynamische Arrays zur Speicherung ihrer Eigenschaften verwenden. In der Tat habe ich damit bereits im vorherigen Artikel begonnen. Hier werde ich einen logischen Fehler beheben, der im vorigen Artikel gemacht wurde und dazu führte, dass Eigenschaftsänderungen von Objekten mit mehr als zwei Pivot-Punkten nicht verfolgt werden konnten. Außerdem werde ich die Klasse eines mehrdimensionalen dynamischen Arrays korrigieren und verbessern, so dass sie als separate Einheit der Bibliothek verwendet werden kann, und sie in eine separate Datei verschieben.


Verbesserung der Klassenbibliothek

Die abgeleiteten Klassen eines abstrakten grafischen Objekts benötigen einige Eigenschaften, die von dem Objekt unterstützt werden, damit diese Eigenschaften bei der Suche, Sortierung und Anzeige der Eigenschaften im Terminaljournal berücksichtigt werden können. In den Dateien GStdFiboArcObj.mqh und GStdGannFanObj.mqh fügen wir die Zeichenkette zur Unterstützung der realen Eigenschaft "Pegelwert" durch das Objekt hinzu:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

In den Dateien GStdExpansionObj.mqh, GStdFiboChannelObj.mqh, GStdFiboFanObj.mqh, GStdFiboObj.mqh, GStdFiboTimesObj.mqh und GStdPitchforkObj.mqh wurden die folgenden Änderungen in der gleichen Methode vorgenommen, um die gleiche Eigenschaft zu unterstützen:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

In der Datei GStdHLineObj.mqh der Objektklasse "Horizontal line", entfernen wir die Eigenschaft "Pivot point time" aus der Methode, die das Flag des Objekts zurückgibt, das die Integer-Eigenschaft unterstützt, da das Objekt nur den Preis zur Konstruktion verwendet:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Das Objekt "Vertikale Linie" in der Datei GStdVLineObj.mqh verwendet nur Zeit für seine Konstruktion. Daher werde ich alles aus der Methode entfernen, das das Flag des Objekts zurückgibt, das eine echte Eigenschaft unterstützt — das Objekt unterstützt keine echten Eigenschaften:

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


Im vorigen Artikel habe ich einen logischen Fehler übersehen, der uns daran hindert, die Änderungen der Eigenschaften von Objekt-Drehpunkten und -Ebenen zu kontrollieren, wenn zwei Drehpunkte für die Objektkonstruktion verwendet werden oder das Objekt mehr als zwei Ebenen aufweist. Es handelte sich hauptsächlich um die Methode, die die angegebene Anzahl von Zellen am Ende des Arrays hinzufügt. Die Methode erhielt den Zeiger auf ein außerhalb erstelltes Objekt, während das Array die angegebene Anzahl dieser Zeiger erhielt:

//--- 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;
                       }

Es handelt sich jedoch um das gleiche Objekt! Wir übergeben einfach den Zeiger auf ein außerhalb der Methode erzeugtes Objekt und multiplizieren die Zeiger darauf in einer Schleife. Daher wirkt sich eine Änderung der Eigenschaften des Objekts selbst auf alle Zeiger aus — auch sie verweisen auf dasselbe Objekt. Daher haben wir das Array mit Instanzen derselben Objekteigenschaft und nicht mit unterschiedlichen Eigenschaften gefüllt. Wenn das Objekt mehrere Bezugspunkte aufwies, haben wir den Drehpunkt mit der angegebenen Anzahl multipliziert. Anstatt die realen Werte des zweiten, dritten, vierten und fünften Punktes zu verwalten, fügten wir dem Array die Eigenschaft des zweiten Drehpunktes hinzu. Dies verhinderte, dass wir die Werte des realen Referenzpunktes abrufen, verfolgen und ändern konnten. Die Änderung des zweiten Pivotpunkts führte dazu, dass diese Änderungen auf den dritten, vierten und fünften Objektpunkt kopiert wurden.

Fügen wir eine weitere Methode zum Erstellen eines neuen Datenobjekts hinzu. Mit dieser Methode wird ein neues Eigenschaftsobjekt erstellt. Diese neue Eigenschaft (und nicht den Zeiger) fügen wir dem Array in der Methode AddQuantity() hinzu, in der wir einfach den von außen erstellten Zeiger in der angegebenen Menge dem Array hinzugefügt haben.

Da wir in \MQL5\Include\DoEasy\Services\XDimArray.mqh drei Sätze identischer Klassen haben — die Klassen zur Erstellung dynamischer mehrdimensionaler Integer-, Real- und String-Arrays -, wollen wir dies am Beispiel der Klassen zur Erstellung eines mehrdimensionalen dynamischen Integer-Arrays betrachten.

In der Klasse eines Array vom Typ long schreiben wir die Methode zur Erstellung eines neuen Datenobjekts:

//+------------------------------------------------------------------+
//| 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

Hier ist alles ganz einfach: wir erstellen ein neues Objekt mit datem dey Typs long und setzen den Wert, der der Methode übergeben wurde, für dieses Objekt. Wenn es nicht gelingt, ein Objekt zu erstellen, wird das im Journal mitgeteilt. Die Methode gibt den Zeiger auf das erstellte Objekt zurück oder NULL im Falle eines Fehlers.

Fügen Sie die Änderungen in der Methode AddQuantity() hinzu:

//--- 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;
                       }

Anstelle des Zeigers auf das Objekt erhält die Methode nun den Wert, der einer neu erstellten Eigenschaft zugewiesen werden soll. In der Schleife wird ein neues Objekt erstellt und der Liste hinzugefügt.

In der Methode Increase(), in der ich zuvor ein neues Objekt erstellt und den Zeiger darauf an die Methode AddQuantity() übergeben habe, rufe ich einfach die Methode AddQuantity() auf, da nun neue Objekte in der Schleife erstellt und dem Array innerhalb der Methode AddQuantity() hinzugefügt werden und nicht mehr ein Zeiger auf ein einzelnes Objekt, das zuvor in der Methode Increase() erstellt wurde.

Entfernen wir den folgenden Codeblock aus der Methode:

//--- 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;
                       }

Die aufgerufene Methode AddQuantity() erhält nun einen Anfangswert für ein neu zum Array hinzugefügtes Datenobjekt anstelle eines Zeigers:

//--- 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;
                       }

Die gleichen Änderungen wurden an den übrigen Klassen der Datei vorgenommen. Ich werde sie hier nicht wiederholen, da sie identisch sind.
Sie können alle Änderungen in den unten angehängten Dateien sehen.

In \MQL5\Include\DoEasy\Data.mqh fügen wir die neue Nachrichtenindizes hinzu:

//--- 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:
   
  };
//+------------------------------------------------------------------+

und die Nachrichtentexte, die den neu hinzugefügten Indizes entsprechen:

//--- 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: "},
   
  };
//+---------------------------------------------------------------------+


Machen wir noch kleinere Verbesserungen in der Klasse des Basisobjekts der grafischen Objekte der Bibliothek.

Die grafischen Objekte verfügen über Eigenschaften vom Typ bool, die die Flags einiger Objekteigenschaften zurückgeben. Die abstrakte Klasse der grafischen Objekte hat Methoden, die solche Flags zurückgeben und setzen. Die Methodennamen zeigen an, dass die Methode das Flag setzt, zum Beispiel:
SetFlagDrawLines (Linien für die Elliott-Wellenmarkierung anzeigen). In der Klasse des Basisobjekts der grafischen Objekte der Bibliothek gibt es eine entsprechende Methode namens SetDrawLines(). Wenn wir also versuchen, das Flag für ein Objekt zu setzen, sehen wir zwei Hinweise zur Auswahl einer Methode. Das ist verwirrend. Wenn wir außerdem die Methode des grafischen Basisobjekts und nicht des abstrakten Objekts auswählen, wird in den Eigenschaften keine Änderung vorgenommen, die in den Objektarrays festgelegt wurde. Stattdessen geben wir einfach einen Befehl zur Änderung einer Eigenschaft im grafischen Objekt selbst. Die entsprechende Eigenschaft im Klassenobjekt bleibt unverändert. Das bedeutet, dass wir alle diese Methoden umbenennen müssen, um Fehler bei der Auswahl von zwei Methoden zu vermeiden. Ich glaube, dass es später auch notwendig sein wird, die Rückgabetypen dieser Methoden zu vereinheitlichen, damit der Compiler in der Lage ist, die erforderliche Methode eindeutig auszuwählen.

Lassen Sie uns die notwendigen Korrekturen in \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh einführen:

//--- 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;
                       }


Verschieben wir die Klassen zur Erstellung eines multidimensionalen dynamischen Arrays in eine separate Datei. Ich werde sie so verbessern, dass sie zu einem Werkzeug für die Erstellung von Eigenschaftsobjekten für jedes bestehende oder geplante Objekt der Bibliothek werden, das Arrays für die Speicherung seiner Eigenschaften (Integer, Real und String) verwendet.

Im Ordner \MQL5\Include\DoEasy\Services\ der Serviceklassen und -funktionen erstellen wir die neue Datei Properties.mqh. Sie soll alle Klassen für die Erstellung eines zweidimensionalen Arrays von Objekteigenschaften und eines Eigenschaftsobjekts (sowohl die vorherigen als auch die aktuellen), die im vorherigen Artikel festgelegt wurden, direkt in den Klassenkörper des abstrakten grafischen Standardobjekts CGStdGraphObj bringen:

//+------------------------------------------------------------------+
//| 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);
                          }
     };

Um die Klasse universell zu machen, müssen wir die Verweise auf alle Aufzählungen, die zu einem bestimmten Klassenobjekt gehören, entfernen.

Um dies zu erreichen, ersetzen wir alle Enumerationen, die zur Auswahl der Methoden verwendet werden, die einen realen Eigenschaftsindex zurückgeben, durch gewöhnliche int-Variablen. Um die Eigenschaftsindizes zu berechnen, übergeben wir den Klassenkonstruktoren die maximale Eigenschaft für Real- und String-Eigenschaften (eine Integer-Eigenschaft verschiebt ihren Wert nicht und entspricht vollständig dem Eigenschaftsindex). Berechnen wir dann einfach die reellen Werte auf der Grundlage des Eigenschaftswerts und des Maximalwerts der Eigenschaften. Wie üblich wird die Idee deutlicher, wenn sie als Code dargestellt wird.

Die folgenden Klassen fügen wir der neu hinzugefügte Datei \MQL5\Include\DoEasy\Services\Properties.mqh hinzu:

//+------------------------------------------------------------------+
//|                                                   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();
                       }
  };
//+------------------------------------------------------------------+

Alle wichtigen Erklärungen sind in den Codekommentaren enthalten. Vergleichen wir diese Klassen mit denen, die im vorherigen Artikel in \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh erstellt wurden.

Nun wollen wir die abstrakte grafische Standardobjektklasse in \MQL5\Include\DoEasy\Objects\Graph\Standard\GStdGraphObj.mqh verbessern.

Zunächst fügen wir die neu erstellte Datei der Objekteigenschaftsklassen hinzu:

//+------------------------------------------------------------------+
//|                                                 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
  {

Die Klassen der Eigenschaftsobjekte sind bereits aus dem privaten Abschnitt der Klasse entfernt. Der Zeiger auf das Eigenschaftsobjekt wird ebenfalls darin deklariert. Die entsprechende Methode des properties-Objekts wird in jeder der Get- und Set-Methoden im öffentlichen Abschnitt der Klasse aufgerufen:

//+------------------------------------------------------------------+
//| 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;}

Im öffentlichen Abschnitt tragen wir den Destruktor der Klasse ein, in der das Eigenschaftsobjekt entfernt werden soll:

//--- 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);

Im Abschnitt der Methoden für den vereinfachten Zugriff und das Setzen von grafischen Objekteigenschaften, verbessern wir die Methoden zum Setzen der Eigenschaften der Flags:

//--- 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

Die Methode, die die aktuellen Eigenschaften zu den vorherigen kopiert, wird aus dem privaten Bereich in den öffentlichen verschoben:

//--- 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);

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

In dem geschützten parametrischen Konstruktor erzeugen wir ein neues Objekt mit den Eigenschaften des grafischen Objekts:

//+------------------------------------------------------------------+
//| 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

Die Anzahl der grafischen Objekteigenschaften der Typen ganzzahlig, reellen und Text wird dem Klassenkonstruktor übergeben.

In der Methode, die die ganzzahligen Eigenschaften eines grafischen Objekts zurückgibt und sie in den Objekteigenschaften der Klasse speichert, wird geprüft, ob sich die Anzahl der Objektebenen geändert hat. Wenn ja, dann wird die Größe der Arrays aller Eigenschaften, die die Ebenenwerte speichern, geändert.
Andernfalls wird beim Setzen der Ebeneneigenschaften der Fehler "Array out of range" angezeigt:

   //--- 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)

Vereinfachung der Methode zur Überprüfung der Änderungen von Objekteigenschaften:

//+------------------------------------------------------------------+
//| 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();
  }
//+------------------------------------------------------------------+

In der bisherigen Methodenimplementierung habe ich die if-else-Konstruktion verwendet, um sicherzustellen, dass die Eigenschaft mehrere Werte hat (z. B. die Ankerpunktzeit), und jede solche Eigenschaft in einem eigenen Codeblock behandelt. Da wir in der Lage sind, die Größe des Eigenschaftsarrays für jede der Eigenschaften zu kennen, ist es ausreichend, die Werte einer einzelnen Eigenschaft in der Schleife einfach nach der Größe der zweiten Dimension des Arrays durchzugehen. Für eine einzelne Eigenschaft ist die Größe der zweiten Dimension 1, während sie für eine mehrfache gleich der Anzahl der Werte der Eigenschaft multi-properties ist. Somit kann alles in einer einzigen Schleife für jede der Objekteigenschaften durchgeführt werden. Genau das habe ich oben getan.

Ich habe auch einige kleinere Verbesserungen (z. B. Änderung der Methodennamen) in derselben Datei vorgenommen. Zum Beispiel wurde LevelColorsDescription() in LevelsColorDescription() umbenannt, was mehr dem Zweck der Methode entspricht. Ich werde diese Umbenennung hier nicht weiter besprechen. Sie finden sie in den angehängten Dateien.

Jedes der Bibliotheksobjekte hat neben anderen Eigenschaften auch eine eigene Objekt-ID. Die Kollektionsklasse der grafischen Elemente verfügt über zwei Kollektionen — die Kollektion der grafischen Elemente, deren Entwicklung ich bis zur Fertigstellung der Sammlung der grafischen Objekte (mit manuell erstellten grafischen Standardobjekten), an der ich gerade arbeite, ausgesetzt habe, und die grafischen Standardobjekte, die programmatisch erstellt werden. Hier werde ich mit der Entwicklung der Funktionalität zur Programmierung von grafischen Standardobjekten beginnen.
Die IDs von programmatisch erstellten grafischen Objekten werden im Bereich von 1 bis einschließlich 10000 liegen. Die IDs von manuell erstellten grafischen Objekten beginnen bei 10001.
Lassen Sie uns diesen Schwellenwert in \MQL5\Include\DoEasy\Defines.mqh einstellen:

//--- 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                                                     |
//+------------------------------------------------------------------+


Methoden zur Programmierung grafischer Standardobjekte

Wir verfügen bereits über Methoden, die die manuelle Erstellung von grafischen Objekten auf einem Diagramm, die Erstellung der entsprechenden Klassenobjekte und das Hinzufügen zur Kollektion verfolgen. Natürlich wäre es gut, sie für die aktuellen Aufgaben zu verwenden, aber es gibt einige Gründe, die mich gezwungen haben, die Verwendung von teilweise fertigen Methoden aufzugeben. Wir verfolgen einfach das Erscheinen von grafischen Objekten im Timer. Wenn ich ein Objekt programmatisch erstelle, möchte ich nicht auf den nächsten Timer-Tick warten und das neu erstellte Objekt sowie seine Erstellungsmethode (programmatisch und manuell) definieren.

Stattdessen werde ich die Methode in der Kollektion der grafischen Elemente für die Erstellung von grafischen Standardobjekten erstellen. Unmittelbar nach der Konstruktion des Objekts werde ich das entsprechende Klassenobjekt erstellen und es in die Kollektion aufnehmen. Die Suche nach Änderungen in den Objekteigenschaften wird von der bereits erstellten Funktionalität durchgeführt. Auf diese Weise werden wir in der Lage sein, Objekte zu erstellen und sie der Kollektion hinzuzufügen, während wir die Möglichkeit behalten, nach Änderungen zu suchen, ohne die Methode der Objekterstellung zu berücksichtigen. In Zukunft wird dies die Erstellung von zusammengesetzten grafischen Objekten und die Verwaltung ihrer Eigenschaften vereinfachen.

Der Name eines programmatisch erstellten grafischen Objekts enthält den Namen des Programms, aus dem das Objekt erstellt wurde. Dies wird es uns ermöglichen, unsere "eigenen" grafischen Objekte von manuell erstellten Objekten zu unterscheiden.
Um dies zu erreichen, fügen wir die neue Variable für die Speicherung des Programmnamens in den privaten Abschnitt der Diagrammobjekt-Verwaltungsklasse in der Datei der grafischen Element-Kollektion-Klasse \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh ein:

//+------------------------------------------------------------------+
//| 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:

Im öffentlichen Abschnitt der Klasse entfernen wir die Angabe einer Chart-ID aus der Methode CreateNewGraphObj(), da die ID eine der primären Eigenschaften des Verwaltungsobjekts des Chartobjekt ist und sie direkt vom Objekt und nicht durch Übergabe an die Methode erhalten werden kann.
Setzen des Wertes des Programmnamens auf die entsprechende Variable in den Klassenkonstruktoren:

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();
                       }

Bei der Prüfung auf einen leeren Namen ist außerdem darauf zu achten, dass das Objekt in der Methode, die Chart-Objekte prüft, nicht programmatisch erstellt wird:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Mit anderen Worten, wenn ein Objektname keine Teilzeichenkette mit einem Programmnamen hat, sollte ein solches Objekt von der Methode behandelt werden, andernfalls handelt es sich um ein programmatisch erzeugtes grafisches Objekt, das durch eine andere Methode der Kollektion hinzugefügt wird.

In der Methode zum Erzeugen eines neuen grafischen Standardobjekts, ersetzen wir alle chart_id, die zuvor an die Methode übergeben wurden, durch die Chart-ID, die für das von ihr kontrollierte Objekt festgelegt wurde:

//+------------------------------------------------------------------+
//| 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;
     }
  }
//+------------------------------------------------------------------+


In der Kollektion CGraphElementsCollection von grafischen Objekten, nämlich in der Methode, die die ID des ersten freien grafischen Objekts zurückgibt, fügen wir das Flag hinzu, das die ID des benötigten Objekts angibt: false — für ein manuell erstelltes Objekt, true — für ein programmatisch erstelltes Objekt

//--- 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

Deklarieren der privaten Methode, die ein neues grafisches Standardobjekt erstellt:

//--- 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:

Im privaten Abschnitt der Klasse schreiben wir die Methode, die ein neues grafisches Objekt erstellt und den Zeiger auf das Chart-Verwaltungsobjekt zurückgibt:

//--- 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:

Die Logik der Methode wird in den Code-Kommentaren beschrieben. Die Methode wird bei der Erstellung bestimmter grafischer Standardobjekttypen verwendet, die sich weiter im öffentlichen Teil der Klasse befinden.

Die Methode, die das grafische Objekt "Vertikale Linie" erzeugt:

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;
                       }

Die Methode wird in den Codekommentaren hinreichend genau erklärt. Die Eigenschaften, die jedem spezifischen Objekt innewohnen und in den Parametern übergeben werden, werden in jedem dieser Objekte eingestellt. Auf dem angegebenen Chart wird zunächst ein physisches grafisches Objekt erstellt, das einen Zeiger auf das Chart-Verwaltungsobjekt bildet. Dessen Methode CreateNewGraphObj() wird verwendet, um das Klassenobjekt zu erstellen, das dem erstellten Objekttyp entspricht. Wenn das Hinzufügen des Objekts zur Liste fehlschlägt, werden das physische grafische Objekt selbst und das Klassenobjekt entfernt und eine Fehlermeldung an das Journal gesendet. Wenn die Erstellung erfolgreich war, wird das Chart aktualisiert und die Methode gibt true zurück.

Die übrigen Methoden zur Erstellung von grafischen Objekten sind identisch mit der oben betrachteten und unterscheiden sich nur durch den Satz von Parametern, die für jedes spezifische grafische Objekt definiert sind.
Werfen wir einen Blick auf die Auflistung aller anderen hinzugefügten Methoden:

//--- 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;
                       }
 
  };
//+------------------------------------------------------------------+

Alle Methoden verfügen über ihre eigenen Eingabeparameter. Diese Parameter werden als minimale Objekteigenschaften festgelegt, die für die Erstellung des Objekts ausreichen. Alle übrigen Eigenschaften können nach der Erstellung eines grafischen Objekts geändert werden.

Die Methode gibt die erste freie grafische Objekt-ID zurück:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

Die Methode berücksichtigt nun eine notwendige ID, die übergeben werden muss.
Wenn sie für ein programmatisch erzeugtes grafisches Objekt bestimmt ist, holt sie die Liste aller Objekte, deren ID kleiner oder gleich dem Wert der Konstante PROGRAM_OBJ_MAX_ID (10000) ist.
Wenn es sich um ein manuell erstelltes grafisches Objekt handelt, hole die Liste aller Objekte mit IDs über PROGRAM_OBJ_MAX_ID.
Als Nächstes holen wir den Index eines Objekts mit der maximalen ID aus der erhaltenen Liste, sowie ein aufgelistetes Objekt nach seinem Index.
Danach berechnen wir den Wert der allerersten ID (für ein programmiertes Objekt — 1, für ein manuell erstelltes Objekt — 10000+1).
Wenn das Objekt mit der höchsten ID empfangen wurde, erhalte den Wert seiner ID+1. Andernfalls ist das Objekt nicht in der Liste und es wird der berechnete Wert der ersten ID (1 oder 10001) zurückgegeben.

In der Methode, die das grafische Objekt zur Kollektion hinzufügt, ermitteln wir, ob ein Objekt programmatisch oder manuell erstellt wurde (über den Objektnamen), um nach einer ID zu suchen und übergeben den Wert an die Methode GetFreeGraphObjID():

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Vereinfachen wir die Logik der Ereignisbehandlung, indem wir if-else loswerden und ein Objekt-Klick-Tracking hinzufügen, um die Objektauswahl mit der Maus zu bestimmen (noch nicht implementiert):

//+------------------------------------------------------------------+
//| 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();
     }
  }
//+------------------------------------------------------------------+

Die Methode, die ein neues grafisches Standardobjekts erstellt:

//+------------------------------------------------------------------+
//| 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;
     }
  }
//+------------------------------------------------------------------+

Die Methode erhält die ID des Charts, auf dem ein Objekt dargestellt werden soll, seinen Namen, seinen Typ, das Chart-Unterfenster und fünf Pivotpunkt-Koordinaten. Die erste Koordinate (Zeit und Preis) ist obligatorisch, während die übrigen vordefinierte Standardwerte haben, die es dem Nutzer ermöglichen, jedes beliebige grafische Standardobjekt zu erstellen. In der Methode wird der letzte Fehlercode zurückgesetzt und das Ergebnis der Ausführung der Funktion ObjectCreate() in Abhängigkeit von einem Objekttyp zurückgegeben. Im Falle eines Fehlers bei der Objekterzeugung wird die oben besprochenen Methode CreateNewStdGraphObjectAndGetCtrlObj() und der Aufruf der Methode die Fehlermeldung mit dem Fehlercode und dessen Beschreibung an das Journal gesendet.

Jetzt ist alles bereit, um die Verbesserungen zu testen, die in den Klassen und im Programm für grafische Standardobjekte implementiert wurden.

Test

Anstatt alle grafischen Objekte zu erstellen, beschränke ich mich auf eine vertikale Linie. Sie wird erstellt, wenn Sie mit der linken Maustaste auf ein Chart klicken und dabei die Strg-Taste gedrückt halten. Prüfen wir die Erstellung eines Objekts, die Behandlung eines Fehlers beim Versuch, ein Objekt mit demselben Namen zu erstellen, die Behandlung von Änderungen der Zeitkoordinate sowie die Verfolgung von Änderungen der Pivotpunktkoordinaten von Objekten mit mehr als zwei Pivotpunkten.

Um den Test durchzuführen, verwende ich den EA aus dem vorherigen Artikel und speichere ihn in \MQL5\Experts\TestDoEasy\Part89\ als TestDoEasyPart89.mq5.

In der Ereignisfunktion OnChartEvent() des EAs wird der Codeblock für die Erstellung von Formularobjekten bei gedrückter Strg-Taste deaktiviert und der Codeblock für die Erstellung einer vertikalen Linie mit einem bestimmten Namen hinzugefügt, wenn bei gedrückter Strg-Taste in der Mausklickkoordinate auf einen Chart geklickt wird:

//+------------------------------------------------------------------+
//| 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);
   
  }
//+------------------------------------------------------------------+

Kompilieren Sie den EA und starten Sie ihn auf dem Chart.

Zunächst wird eine vertikale Linie erstellt, durch einen klick auf einen Chart bei gedrückter Strg-Taste. Sehen Sie sich die Linien-ID an und beobachten Sie, wie sich die Objekteigenschaften beim Verschieben der Linie entlang des Charts ändern. Wenn wir die gleiche Linie erneut erstellen, erhalten wir die Fehlermeldung im Journal.
Als Nächstes erstellen wir einen äquidistanten Kanal, und wir sehen seinen ID-Wert an und können prüfen, wie die Änderungen der Eigenschaften seiner drei Pivotpunkte kontrolliert werden:



Was kommt als Nächstes?

Im nächsten Artikel werde ich weiter an der Funktionalität zur Programmierung grafischer Objekte arbeiten.

Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit der Test-EA-Datei für MQL5 zum Testen und Herunterladen angehängt. Beachten Sie, dass Sie die Indikator-Datei aus dem Artikel 87 benötigen, damit die Bibliothek mit Chart-Grafikobjekten arbeiten kann, die nicht zum Programm gehören.

Stellen Sie Ihre Fragen, Kommentare und Vorschläge bitte im Kommentarteil.

Zurück zum Inhalt

*Frühere Artikel dieser Serie:


Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/10119

Beigefügte Dateien |
MQL5.zip (4174.43 KB)
Lernen Sie warum und wie Sie Ihr algorithmisches Handelssystem entwerfen Lernen Sie warum und wie Sie Ihr algorithmisches Handelssystem entwerfen
Dieser Artikel zeigt die Grundlagen von MQL für Anfänger, um ihr Algorithmisches Handelssystem (Expert Advisor) zu entwerfen, indem sie ein einfaches algorithmisches Handelssystem entwerfen, nachdem sie einige Grundlagen von MQL5 erwähnt haben.
Websockets für MetaTrader 5 — Unter Verwendung der Windows API Websockets für MetaTrader 5 — Unter Verwendung der Windows API
In diesem Artikel werden wir die WinHttp.dll verwenden, um einen Websocket-Client für MetaTrader 5-Programme zu erstellen. Der Client wird letztendlich als Klasse implementiert und auch gegen die Binary.com Websocket API getestet.
Universelles Regressionsmodell für die Prognostizierung von Marktpreisen (Teil 2): Natürliche, technologische und soziale Übergangsfunktionen Universelles Regressionsmodell für die Prognostizierung von Marktpreisen (Teil 2): Natürliche, technologische und soziale Übergangsfunktionen
Dieser Artikel ist eine logische Fortsetzung des vorangegangenen Artikels. Er hebt die Fakten hervor, die die im ersten Artikel gezogenen Schlussfolgerungen bestätigen. Diese Fakten wurden in den zehn Jahren nach der Veröffentlichung dieses Artikels beobachtet. Sie konzentrieren sich auf drei festgestellte dynamische Übergangsfunktionen (transient functions), die die Muster der Marktpreisänderungen beschreiben.
Ein manuelles Chart- und Handelswerkzeug (Teil III). Optimierungen und neue Werkzeuge Ein manuelles Chart- und Handelswerkzeug (Teil III). Optimierungen und neue Werkzeuge
In diesem Artikel werden wir die Idee des Zeichnens von grafischen Objekten auf Charts mit Hilfe von Tastenkombinationen weiterentwickeln. Der Bibliothek wurden neue Werkzeuge hinzugefügt, darunter eine gerade Linie, die durch beliebige Scheitelpunkte gezeichnet wird, und eine Reihe von Rechtecken, die die Auswertung der Umkehrzeit und des Levels ermöglichen. Außerdem zeigt der Artikel die Möglichkeit, den Code zu optimieren, um die Leistung zu verbessern. Das Implementierungsbeispiel wurde umgeschrieben, sodass Shortcuts neben anderen Handelsprogrammen verwendet werden können. Erforderliche Code-Kenntnisse: etwas höher als die eines Anfängers.