DoEasy 函数库中的图形(第八十二部分):函数库对象重构和图形对象集合

25 十月 2021, 13:15
Artyom Trishkin
0
611

内容


概述

在上一篇文章中,我开始将图形处理与函数库对象集成在一起。 每个函数库对象都有自己的对象实例,用于处理图形对象,允许它构建相应的图形对象(标准和基于 CCanvas 的对象)。

为了将图形集成到函数库对象当中,我在上一篇文章中开始细化柱线对象。 特别是,我实现了图形管理类。 调试后,我准备将新创建和调试好的图表处理机制添加到其它对象当中。

现在,到了改进所有函数库对象的时候了。 每个对象都应该有其独有的 ID — Type() 允许我们为该对象进行定义。 每个函数库对象都应该能够创建图形对象,而图形对象应该“知道”自己是谁创建的。 每当任何函数库对象创建了图形对象之后,图形对象应该知道是谁创建了自己,并拥有指向其父对象的指针,而父对象也应该知道其生成的图形对象,并拥有指向它们的指针。

同时,在创建图形对象时,我们需要将其放入到单个图形对象集合列表之中。 所有图形对象都需要一个新属性 — 对象关联。 它允许我们判定图形对象是如何创建的 — 是通过程序,亦或在终端中手工创建。 从程序里利用函数库创建的对象,会立即添加到列表当中。 通过终端创建的图形(手工添加到图表的各种图形对象),应由图形对象的集合类跟踪,并在列表中添加 / 删除。 应为它们创建图形对象类的单独程序对象,以便程序也能够管理它们。
为此,我们需要在图形对象的集合类中实现跟踪终端里所有已打开图表窗口的状态,即标准图形对象的出现、创建函数库对象、并将它们添加到集合列表中。 删除标准图形对象也是如此。

故此,我们的函数库最终能够控制已打开图表上存在的所有标准图形对象,并将它们视为自己的对象,同时亦考虑到手工创建的对象。

这是前面若干篇文章的基础。
在此,我打算为它们分配类型来改进所有函数库对象,以及在图形对象集合类上的操作,即在终端已打开图表上安排跟踪新增 / 删除现有的图形对象。


改进库类

我们在 \MQL5\Include\DoEasy\Defines.mqh 中添加新的宏替换和枚举。 我们需要添加所有函数库对象的类型,从而可在创建对象的“type” 属性时立即为其设置初值。

但首先,我们在现有集合的计时器参数列表末尾添加指定图形对象集合计时器参数的宏替换

//--- Parameters of the chart collection timer
#define COLLECTION_CHARTS_PAUSE        (500)                      // Chart collection timer pause in milliseconds
#define COLLECTION_CHARTS_COUNTER_STEP (16)                       // Chart timer counter increment
#define COLLECTION_CHARTS_COUNTER_ID   (9)                        // Chart timer counter ID
//--- Parameters of the graphical objects collection timer
#define COLLECTION_GRAPH_OBJ_PAUSE        (250)                   // Graphical objects collection timer pause in milliseconds
#define COLLECTION_GRAPH_OBJ_COUNTER_STEP (16)                    // Graphical objects timer counter increment
#define COLLECTION_GRAPH_OBJ_COUNTER_ID   (10)                    // Graphical objects timer counter ID

//--- Collection list IDs


该文件已包含集合列表 ID。
继续列举对象类型 ID 是合理的。 由于我将继续添加新的对象集合,且它们的 ID 列表将被扩展,我们应该添加一个标签作为对象类型值的起点

//--- Collection list IDs
#define COLLECTION_HISTORY_ID          (0x777A)                   // Historical collection list ID
#define COLLECTION_MARKET_ID           (0x777B)                   // Market collection list ID
#define COLLECTION_EVENTS_ID           (0x777C)                   // Event collection list ID
#define COLLECTION_ACCOUNT_ID          (0x777D)                   // Account collection list ID
#define COLLECTION_SYMBOLS_ID          (0x777E)                   // Symbol collection list ID
#define COLLECTION_SERIES_ID           (0x777F)                   // Timeseries collection list ID
#define COLLECTION_BUFFERS_ID          (0x7780)                   // Indicator buffer collection list ID
#define COLLECTION_INDICATORS_ID       (0x7781)                   // Indicator collection list ID
#define COLLECTION_INDICATORS_DATA_ID  (0x7782)                   // Indicator data collection list ID
#define COLLECTION_TICKSERIES_ID       (0x7783)                   // Tick series collection list ID
#define COLLECTION_MBOOKSERIES_ID      (0x7784)                   // DOM series collection list ID
#define COLLECTION_MQL5_SIGNALS_ID     (0x7785)                   // MQL5 signals collection list ID
#define COLLECTION_CHARTS_ID           (0x7786)                   // Chart collection list ID
#define COLLECTION_CHART_WND_ID        (0x7787)                   // Chart window list ID
#define COLLECTION_GRAPH_OBJ_ID        (0x7788)                   // Graphical object collection list ID

#define COLLECTION_ID_LIST_END         (COLLECTION_GRAPH_OBJ_ID)  // End of collection ID list

//--- Pending request type IDs

标签值 + 1 将成为我们现在要添加的函数库对象类型枚举第一个常量值

//--- 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
//+------------------------------------------------------------------+
//| Enumerations                                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| List of library object types                                     |
//+------------------------------------------------------------------+
enum ENUM_OBJECT_DE_TYPE
  {
//--- Graphics
   OBJECT_DE_TYPE_GBASE =  COLLECTION_ID_LIST_END+1,              // "Base object of all library graphical objects" object type
   OBJECT_DE_TYPE_GELEMENT,                                       // "Graphical element" object type
   OBJECT_DE_TYPE_GFORM,                                          // Form object type
   OBJECT_DE_TYPE_GSHADOW,                                        // Shadow object type
//--- Animation
   OBJECT_DE_TYPE_GFRAME,                                         // "Single animation frame" object type
   OBJECT_DE_TYPE_GFRAME_TEXT,                                    // "Single text animation frame" object type
   OBJECT_DE_TYPE_GFRAME_QUAD,                                    // "Single rectangular animation frame" object type
   OBJECT_DE_TYPE_GFRAME_GEOMETRY,                                // "Single geometric animation frame" object type
   OBJECT_DE_TYPE_GANIMATIONS,                                    // "Animations" object type
//--- Managing graphical objects
   OBJECT_DE_TYPE_GELEMENT_CONTROL,                               // "Managing graphical objects" object type
//--- Standard graphical objects
   OBJECT_DE_TYPE_GSTD_VLINE              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_VLINE,             // "Vertical line" object type
   OBJECT_DE_TYPE_GSTD_HLINE              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_HLINE,             // "Horizontal line" object type
   OBJECT_DE_TYPE_GSTD_TREND              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TREND,             // "Trend line" object type
   OBJECT_DE_TYPE_GSTD_TRENDBYANGLE       =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TRENDBYANGLE,      // "Trend line by angle" object type
   OBJECT_DE_TYPE_GSTD_CYCLES             =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_CYCLES,            // "Cyclic lines" object type
   OBJECT_DE_TYPE_GSTD_ARROWED_LINE       =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROWED_LINE,      // "Arrowed line" object type
   OBJECT_DE_TYPE_GSTD_CHANNEL            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_CHANNEL,           // "Equidistant channel" object type
   OBJECT_DE_TYPE_GSTD_STDDEVCHANNEL      =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_STDDEVCHANNEL,     // "Standard deviation channel" object type
   OBJECT_DE_TYPE_GSTD_REGRESSION         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_REGRESSION,        // "Linear regression channel" object type
   OBJECT_DE_TYPE_GSTD_PITCHFORK          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_PITCHFORK,         // "Andrews' pitchfork" object type
   OBJECT_DE_TYPE_GSTD_GANNLINE           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_GANNLINE,          // "Gann line" object type
   OBJECT_DE_TYPE_GSTD_GANNFAN            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_GANNFAN,           // "Gann fan" object type
   OBJECT_DE_TYPE_GSTD_GANNGRID           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_GANNGRID,          // "Gann grid" object type
   OBJECT_DE_TYPE_GSTD_FIBO               =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBO,              // "Fibo levels" object type
   OBJECT_DE_TYPE_GSTD_FIBOTIMES          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOTIMES,         // "Fibo time zones" object type
   OBJECT_DE_TYPE_GSTD_FIBOFAN            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOFAN,           // "Fibo fan" object type
   OBJECT_DE_TYPE_GSTD_FIBOARC            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOARC,           // "Fibo arcs" object type
   OBJECT_DE_TYPE_GSTD_FIBOCHANNEL        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOCHANNEL,       // "Fibo channel" object type
   OBJECT_DE_TYPE_GSTD_EXPANSION          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_EXPANSION,         // "Fibo expansion" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE5        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ELLIOTWAVE5,       // "Elliott 5 waves" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE3        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ELLIOTWAVE3,       // "Elliott 3 waves" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_RECTANGLE,         // "Rectangle" object type
   OBJECT_DE_TYPE_GSTD_TRIANGLE           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TRIANGLE,          // "Triangle" object type
   OBJECT_DE_TYPE_GSTD_ELLIPSE            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ELLIPSE,           // "Ellipse" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_UP     =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_THUMB_UP,    // "Thumb up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_DOWN   =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_THUMB_DOWN,  // "Thumb down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_UP           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_UP,          // "Arrow up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_DOWN         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_DOWN,        // "Arrow down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_STOP         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_STOP,        // "Stop sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_CHECK        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_CHECK,       // "Check mark" object type
   OBJECT_DE_TYPE_GSTD_ARROW_LEFT_PRICE   =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_LEFT_PRICE,  // "Left price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_RIGHT_PRICE  =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_RIGHT_PRICE, // "Right price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_BUY          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_BUY,         // "Buy sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_SELL         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_SELL,        // "Sell sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW,             // "Arrow" object type
   OBJECT_DE_TYPE_GSTD_TEXT               =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TEXT,              // "Text" object type
   OBJECT_DE_TYPE_GSTD_LABEL              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_LABEL,             // "Text label" object type
   OBJECT_DE_TYPE_GSTD_BUTTON             =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_BUTTON,            // "Button" object type
   OBJECT_DE_TYPE_GSTD_CHART              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_CHART,             // "Chart" object type
   OBJECT_DE_TYPE_GSTD_BITMAP             =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_BITMAP,            // "Bitmap" object type
   OBJECT_DE_TYPE_GSTD_BITMAP_LABEL       =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_BITMAP_LABEL,      // "Bitmap label" object type
   OBJECT_DE_TYPE_GSTD_EDIT               =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_EDIT,              // "Input field" object type
   OBJECT_DE_TYPE_GSTD_EVENT              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_EVENT,             // "Event object which corresponds to an event in Economic Calendar" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL    =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_RECTANGLE_LABEL,   // "Rectangle Label object used to create and design the custom graphical interface" object type
   
//--- Objects
   OBJECT_DE_TYPE_BASE  =  OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL+1, // Base object for all library objects
   OBJECT_DE_TYPE_BASE_EXT,                                       // Extended base object for all library objects
   
   OBJECT_DE_TYPE_ACCOUNT,                                        // "Account" object type
   OBJECT_DE_TYPE_BOOK_ORDER,                                     // "Book order" object type
   OBJECT_DE_TYPE_BOOK_BUY,                                       // "Book buy order" object type
   OBJECT_DE_TYPE_BOOK_BUY_MARKET,                                // "Book buy order at market price" object type
   OBJECT_DE_TYPE_BOOK_SELL,                                      // "Book sell order" object type
   OBJECT_DE_TYPE_BOOK_SELL_MARKET,                               // "Book sell order at market price" object type
   OBJECT_DE_TYPE_BOOK_SNAPSHOT,                                  // "Book snapshot" object type
   OBJECT_DE_TYPE_BOOK_SERIES,                                    // "Book snapshot series" object type
   
   OBJECT_DE_TYPE_CHART,                                          // "Chart" object type
   OBJECT_DE_TYPE_CHART_WND,                                      // "Chart window" object type
   OBJECT_DE_TYPE_CHART_WND_IND,                                  // "Chart window indicator" object type
   
   OBJECT_DE_TYPE_EVENT,                                          // "Event" object type
   OBJECT_DE_TYPE_EVENT_BALANCE,                                  // "Balance operation event" object type
   OBJECT_DE_TYPE_EVENT_MODIFY,                                   // "Pending order/position modification event" object type
   OBJECT_DE_TYPE_EVENT_ORDER_PLASED,                             // "Placing a pending order event" object type
   OBJECT_DE_TYPE_EVENT_ORDER_REMOVED,                            // "Pending order removal event" object type
   OBJECT_DE_TYPE_EVENT_POSITION_CLOSE,                           // "Position closure event" object type
   OBJECT_DE_TYPE_EVENT_POSITION_OPEN,                            // "Position opening event" object type
   
   OBJECT_DE_TYPE_IND_BUFFER,                                     // "Indicator buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_ARROW,                               // "Arrow rendering buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_BAR,                                 // "Bar buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_CALCULATE,                           // "Calculated buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_CANDLE,                              // "Candle buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_FILLING,                             // "Filling buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_HISTOGRAMM,                          // "Histogram buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_HISTOGRAMM2,                         // "Histogram 2 buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_LINE,                                // "Line buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_SECTION,                             // "Section buffer" object type
   OBJECT_DE_TYPE_IND_BUFFER_ZIGZAG,                              // "Zigzag buffer" object type
   OBJECT_DE_TYPE_INDICATOR,                                      // "Indicator" object type
   OBJECT_DE_TYPE_IND_DATA,                                       // "Indicator data" object type
   OBJECT_DE_TYPE_IND_DATA_LIST,                                  // "Indicator data list" object type
   
   OBJECT_DE_TYPE_IND_AC,                                         // "Accelerator Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_AD,                                         // "Accumulation/Distribution indicator" object type
   OBJECT_DE_TYPE_IND_ADX,                                        // "Average Directional Index indicator" object type
   OBJECT_DE_TYPE_IND_ADXW,                                       // "ADX indicator by Welles Wilder" object type
   OBJECT_DE_TYPE_IND_ALLIGATOR,                                  // "Alligator indicator" object type
   OBJECT_DE_TYPE_IND_AMA,                                        // "Adaptive Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_AO,                                         // "Awesome Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_ATR,                                        // "Average True Range" object type
   OBJECT_DE_TYPE_IND_BANDS,                                      // "Bollinger Bands® indicator" object type
   OBJECT_DE_TYPE_IND_BEARS,                                      // "Bears Power indicator" object type
   OBJECT_DE_TYPE_IND_BULLS,                                      // "Bulls Power indicator" object type
   OBJECT_DE_TYPE_IND_BWMFI,                                      // "Market Facilitation Index indicator" object type
   OBJECT_DE_TYPE_IND_CCI,                                        // "Commodity Channel Index indicator" object type
   OBJECT_DE_TYPE_IND_CHAIKIN,                                    // "Chaikin Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_CUSTOM,                                     // "Custom indicator" object type
   OBJECT_DE_TYPE_IND_DEMA,                                       // "Double Exponential Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_DEMARKER,                                   // "DeMarker indicator" object type
   OBJECT_DE_TYPE_IND_ENVELOPES,                                  // "Envelopes indicator" object type
   OBJECT_DE_TYPE_IND_FORCE,                                      // "Force Index indicator" object type
   OBJECT_DE_TYPE_IND_FRACTALS,                                   // "Fractals indicator" object type
   OBJECT_DE_TYPE_IND_FRAMA,                                      // "Fractal Adaptive Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_GATOR,                                      // "Gator Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_ICHIMOKU,                                   // "Ichimoku Kinko Hyo indicator" object type
   OBJECT_DE_TYPE_IND_MA,                                         // "Moving Average indicator" object type
   OBJECT_DE_TYPE_IND_MACD,                                       // "Moving Average Convergence/Divergence indicator" object type
   OBJECT_DE_TYPE_IND_MFI,                                        // "Money Flow Index indicator" object type
   OBJECT_DE_TYPE_IND_MOMENTUM,                                   // "Momentum indicator" object type
   OBJECT_DE_TYPE_IND_OBV,                                        // "On Balance Volume indicator" object type
   OBJECT_DE_TYPE_IND_OSMA,                                       // "Moving Average of Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_RSI,                                        // "Relative Strength Index indicator" object type
   OBJECT_DE_TYPE_IND_RVI,                                        // "Relative Vigor Index indicator" object type
   OBJECT_DE_TYPE_IND_SAR,                                        // "Parabolic SAR indicator" object type
   OBJECT_DE_TYPE_IND_STDEV,                                      // "Standard Deviation indicator" object type
   OBJECT_DE_TYPE_IND_STOCH,                                      // "Stochastic Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_TEMA,                                       // "Triple Exponential Moving Average indicator" object
   OBJECT_DE_TYPE_IND_TRIX,                                       // "Triple Exponential Moving Averages Oscillator indicator" object type
   OBJECT_DE_TYPE_IND_VIDYA,                                      // "Variable Index Dynamic Average indicator" object type
   OBJECT_DE_TYPE_IND_VOLUMES,                                    // "Volumes indicator" object type
   OBJECT_DE_TYPE_IND_WPR,                                        // "Williams' Percent Range indicator" object type
   
   OBJECT_DE_TYPE_MQL5_SIGNAL,                                    // "mql5 signal" object type
   
   OBJECT_DE_TYPE_ORDER_DEAL_POSITION,                            // "Order/Deal/Position" object type
   OBJECT_DE_TYPE_HISTORY_BALANCE,                                // "Historical balance operation" object type
   OBJECT_DE_TYPE_HISTORY_DEAL,                                   // "Historical deal" object type
   OBJECT_DE_TYPE_HISTORY_ORDER_MARKET,                           // "Historical market order" object type
   OBJECT_DE_TYPE_HISTORY_ORDER_PENDING,                          // "Historical removed pending order" object type
   OBJECT_DE_TYPE_MARKET_ORDER,                                   // "Market order" object type
   OBJECT_DE_TYPE_MARKET_PENDING,                                 // "Pending order" object type
   OBJECT_DE_TYPE_MARKET_POSITION,                                // "Market position" object type
   
   OBJECT_DE_TYPE_PENDING_REQUEST,                                // "Pending trading request" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_POSITION_OPEN,                  // "Pending request to open a position" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_POSITION_CLOSE,                 // "Pending request to close a position" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_POSITION_SLTP,                  // "Pending request to modify position stop orders" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_ORDER_PLACE,                    // "Pending request to place a pending order" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_ORDER_REMOVE,                   // "Pending request to delete a pending order" object type
   OBJECT_DE_TYPE_PENDING_REQUEST_ORDER_MODIFY,                   // "Pending request to modify pending order parameters" object type
   
   OBJECT_DE_TYPE_SERIES_BAR,                                     // "Bar" object type
   OBJECT_DE_TYPE_SERIES_PERIOD,                                  // "Period timeseries" object type
   OBJECT_DE_TYPE_SERIES_SYMBOL,                                  // "Symbol timeseries" object type
   
   OBJECT_DE_TYPE_SYMBOL,                                         // "Symbol" object type
   OBJECT_DE_TYPE_SYMBOL_BONDS,                                   // "Bond symbol" object type
   OBJECT_DE_TYPE_SYMBOL_CFD,                                     // "CFD (contract for difference) symbol" object type
   OBJECT_DE_TYPE_SYMBOL_COLLATERAL,                              // "Non-tradable asset symbol" object type" object type
   OBJECT_DE_TYPE_SYMBOL_COMMODITY,                               // "Commodity symbol" object type
   OBJECT_DE_TYPE_SYMBOL_COMMON,                                  // "Common group symbol" object type
   OBJECT_DE_TYPE_SYMBOL_CRYPTO,                                  // "Cryptocurrency symbol" object type
   OBJECT_DE_TYPE_SYMBOL_CUSTOM,                                  // "Custom symbol" object type
   OBJECT_DE_TYPE_SYMBOL_EXCHANGE,                                // "Exchange symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FUTURES,                                 // "Futures symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX,                                      // "Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_EXOTIC,                               // "Exotic Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_MAJOR,                                // "Major Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_MINOR,                                // "Minor Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_FX_RUB,                                  // "RUB Forex symbol" object type
   OBJECT_DE_TYPE_SYMBOL_INDEX,                                   // "Index symbol" object type
   OBJECT_DE_TYPE_SYMBOL_INDICATIVE,                              // "Indicative symbol" object type
   OBJECT_DE_TYPE_SYMBOL_METALL,                                  // "Metal symbol" object type
   OBJECT_DE_TYPE_SYMBOL_OPTION,                                  // "Option symbol" object type
   OBJECT_DE_TYPE_SYMBOL_STOCKS,                                  // "Stock symbol" object type
   
   OBJECT_DE_TYPE_TICK,                                           // "Tick" object type
   OBJECT_DE_TYPE_NEW_TICK,                                       // "New tick" object type
   OBJECT_DE_TYPE_TICKSERIES,                                     // "Tick data series" object type
   
   OBJECT_DE_TYPE_TRADE,                                          // "Trading object" object type
  };

//+------------------------------------------------------------------+
//| Search and sorting data                                          |
//+------------------------------------------------------------------+

如果我们仔细研究枚举常量,我们会看到对应于标准图形对象的对象类型,使用函数库对象枚举的前一个常量的值 + 1 + 相应图形对象的标准枚举值。 标准图形对象列表的枚举完成后,我接着是函数库对象类型枚举列表,从最后一个图形对象的常量值 +1 开始:

//--- Managing graphical objects
   OBJECT_DE_TYPE_GELEMENT_CONTROL,                               // "Managing graphical objects" object type
//--- Standard graphical objects
   OBJECT_DE_TYPE_GSTD_VLINE              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_VLINE,             // "Vertical line" object type
   OBJECT_DE_TYPE_GSTD_HLINE              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_HLINE,             // "Horizontal line" object type
   OBJECT_DE_TYPE_GSTD_TREND              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TREND,             // "Trend line" object type
   OBJECT_DE_TYPE_GSTD_TRENDBYANGLE       =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TRENDBYANGLE,      // "Trend line by angle" object type
   OBJECT_DE_TYPE_GSTD_CYCLES             =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_CYCLES,            // "Cyclic lines" object type
   OBJECT_DE_TYPE_GSTD_ARROWED_LINE       =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROWED_LINE,      // "Arrowed line" object type
   OBJECT_DE_TYPE_GSTD_CHANNEL            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_CHANNEL,           // "Equidistant channel" object type
   OBJECT_DE_TYPE_GSTD_STDDEVCHANNEL      =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_STDDEVCHANNEL,     // "Standard deviation channel" object type
   OBJECT_DE_TYPE_GSTD_REGRESSION         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_REGRESSION,        // "Linear regression channel" object type
   OBJECT_DE_TYPE_GSTD_PITCHFORK          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_PITCHFORK,         // "Andrews' pitchfork" object type
   OBJECT_DE_TYPE_GSTD_GANNLINE           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_GANNLINE,          // "Gann line" object type
   OBJECT_DE_TYPE_GSTD_GANNFAN            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_GANNFAN,           // "Gann fan" object type
   OBJECT_DE_TYPE_GSTD_GANNGRID           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_GANNGRID,          // "Gann grid" object type
   OBJECT_DE_TYPE_GSTD_FIBO               =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBO,              // "Fibo levels" object type
   OBJECT_DE_TYPE_GSTD_FIBOTIMES          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOTIMES,         // "Fibo time zones" object type
   OBJECT_DE_TYPE_GSTD_FIBOFAN            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOFAN,           // "Fibo fan" object type
   OBJECT_DE_TYPE_GSTD_FIBOARC            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOARC,           // "Fibo arcs" object type
   OBJECT_DE_TYPE_GSTD_FIBOCHANNEL        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_FIBOCHANNEL,       // "Fibo channel" object type
   OBJECT_DE_TYPE_GSTD_EXPANSION          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_EXPANSION,         // "Fibo expansion" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE5        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ELLIOTWAVE5,       // "Elliott 5 waves" object type
   OBJECT_DE_TYPE_GSTD_ELLIOTWAVE3        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ELLIOTWAVE3,       // "Elliott 3 waves" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_RECTANGLE,         // "Rectangle" object type
   OBJECT_DE_TYPE_GSTD_TRIANGLE           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TRIANGLE,          // "Triangle" object type
   OBJECT_DE_TYPE_GSTD_ELLIPSE            =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ELLIPSE,           // "Ellipse" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_UP     =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_THUMB_UP,    // "Thumb up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_THUMB_DOWN   =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_THUMB_DOWN,  // "Thumb down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_UP           =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_UP,          // "Arrow up" object type
   OBJECT_DE_TYPE_GSTD_ARROW_DOWN         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_DOWN,        // "Arrow down" object type
   OBJECT_DE_TYPE_GSTD_ARROW_STOP         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_STOP,        // "Stop sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_CHECK        =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_CHECK,       // "Check mark" object type
   OBJECT_DE_TYPE_GSTD_ARROW_LEFT_PRICE   =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_LEFT_PRICE,  // "Left price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_RIGHT_PRICE  =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_RIGHT_PRICE, // "Right price label" object type
   OBJECT_DE_TYPE_GSTD_ARROW_BUY          =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_BUY,         // "Buy sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW_SELL         =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW_SELL,        // "Sell sign" object type
   OBJECT_DE_TYPE_GSTD_ARROW              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_ARROW,             // "Arrow" object type
   OBJECT_DE_TYPE_GSTD_TEXT               =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_TEXT,              // "Text" object type
   OBJECT_DE_TYPE_GSTD_LABEL              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_LABEL,             // "Text label" object type
   OBJECT_DE_TYPE_GSTD_BUTTON             =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_BUTTON,            // "Button" object type
   OBJECT_DE_TYPE_GSTD_CHART              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_CHART,             // "Chart" object type
   OBJECT_DE_TYPE_GSTD_BITMAP             =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_BITMAP,            // "Bitmap" object type
   OBJECT_DE_TYPE_GSTD_BITMAP_LABEL       =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_BITMAP_LABEL,      // "Bitmap label" object type
   OBJECT_DE_TYPE_GSTD_EDIT               =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_EDIT,              // "Input field" object type
   OBJECT_DE_TYPE_GSTD_EVENT              =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_EVENT,             // "Event object which corresponds to an event in Economic Calendar" object type
   OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL    =  OBJECT_DE_TYPE_GELEMENT_CONTROL+1+OBJ_RECTANGLE_LABEL,   // "Rectangle Label object used to create and design the custom graphical interface" object type
   
//--- Objects
   OBJECT_DE_TYPE_BASE  =  OBJECT_DE_TYPE_GSTD_RECTANGLE_LABEL+1, // Base object for all library objects

如此,基于标准图形对象的图形库对象拥有与标准图形对象类型相对应的类型值。 这种类型很容易计算,而后续类型继续获取高于最后一个标准图形对象的常量值,并且不会导致枚举常量值之间发生任何冲突。

接下来,我们需要稍微改进图形对象属性列表。 即,我们应在对象从属关系的枚举里添加“由程序”或“由终端”(创建方法 — 程序化或手工),并且将此属性添加到图形对象整数型属性的枚举之中

//+------------------------------------------------------------------+
//| List of graphical objects affiliations                           |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_OBJ_BELONG
  {
   GRAPH_OBJ_BELONG_PROGRAM,                          // Graphical object belongs to a program
   GRAPH_OBJ_BELONG_TERMINAL,                         // Graphical object does not belong to a program
  };
//+------------------------------------------------------------------+
//| The list of graphical element types                              |
//+------------------------------------------------------------------+
enum ENUM_GRAPH_ELEMENT_TYPE
  {
   GRAPH_ELEMENT_TYPE_ELEMENT,                        // Element
   GRAPH_ELEMENT_TYPE_SHADOW_OBJ,                     // Shadow object
   GRAPH_ELEMENT_TYPE_FORM,                           // Form
   GRAPH_ELEMENT_TYPE_WINDOW,                         // Window
  };
//+------------------------------------------------------------------+
//| Integer properties of the graphical element on the canvas        |
//+------------------------------------------------------------------+
enum ENUM_CANV_ELEMENT_PROP_INTEGER
  {
   CANV_ELEMENT_PROP_ID = 0,                          // Element ID
   CANV_ELEMENT_PROP_TYPE,                            // Graphical element type
   CANV_ELEMENT_PROP_BELONG,                          // Graphical element affiliation
   CANV_ELEMENT_PROP_NUM,                             // Element index in the list
   CANV_ELEMENT_PROP_CHART_ID,                        // Chart ID
   CANV_ELEMENT_PROP_WND_NUM,                         // Chart subwindow index
   CANV_ELEMENT_PROP_COORD_X,                         // Form's X coordinate on the chart
   CANV_ELEMENT_PROP_COORD_Y,                         // Form's Y coordinate on the chart
   CANV_ELEMENT_PROP_WIDTH,                           // Element width
   CANV_ELEMENT_PROP_HEIGHT,                          // Element height
   CANV_ELEMENT_PROP_RIGHT,                           // Element right border
   CANV_ELEMENT_PROP_BOTTOM,                          // Element bottom border
   CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,                  // Active area offset from the left edge of the element
   CANV_ELEMENT_PROP_ACT_SHIFT_TOP,                   // Active area offset from the upper edge of the element
   CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,                 // Active area offset from the right edge of the element
   CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,                // Active area offset from the bottom edge of the element
   CANV_ELEMENT_PROP_MOVABLE,                         // Element moveability flag
   CANV_ELEMENT_PROP_ACTIVE,                          // Element activity flag
   CANV_ELEMENT_PROP_COORD_ACT_X,                     // X coordinate of the element active area
   CANV_ELEMENT_PROP_COORD_ACT_Y,                     // Y coordinate of the element active area
   CANV_ELEMENT_PROP_ACT_RIGHT,                       // Right border of the element active area
   CANV_ELEMENT_PROP_ACT_BOTTOM,                      // Bottom border of the element active area
  };
#define CANV_ELEMENT_PROP_INTEGER_TOTAL (22)          // Total number of integer properties
#define CANV_ELEMENT_PROP_INTEGER_SKIP  (0)           // Number of integer properties not used in sorting
//+------------------------------------------------------------------+

由于添加了新的属性,我们需要增加这些属性的总数(从 21 改为 22。 此外,我们还应该在可能的图形对象排序标准枚举中增加按属性排序

//+------------------------------------------------------------------+
//| Possible sorting criteria of graphical elements on the canvas    |
//+------------------------------------------------------------------+
#define FIRST_CANV_ELEMENT_DBL_PROP  (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP)
#define FIRST_CANV_ELEMENT_STR_PROP  (CANV_ELEMENT_PROP_INTEGER_TOTAL-CANV_ELEMENT_PROP_INTEGER_SKIP+CANV_ELEMENT_PROP_DOUBLE_TOTAL-CANV_ELEMENT_PROP_DOUBLE_SKIP)
enum ENUM_SORT_CANV_ELEMENT_MODE
  {
//--- Sort by integer properties
   SORT_BY_CANV_ELEMENT_ID = 0,                       // Sort by element ID
   SORT_BY_CANV_ELEMENT_TYPE,                         // Sort by graphical element type
   SORT_BY_CANV_ELEMENT_BELONG,                       // Sort by a graphical element affiliation
   SORT_BY_CANV_ELEMENT_NUM,                          // Sort by form index in the list
   SORT_BY_CANV_ELEMENT_CHART_ID,                     // Sort by chart ID
   SORT_BY_CANV_ELEMENT_WND_NUM,                      // Sort by chart window index
   SORT_BY_CANV_ELEMENT_COORD_X,                      // Sort by the element X coordinate on the chart
   SORT_BY_CANV_ELEMENT_COORD_Y,                      // Sort by the element Y coordinate on the chart
   SORT_BY_CANV_ELEMENT_WIDTH,                        // Sort by the element width
   SORT_BY_CANV_ELEMENT_HEIGHT,                       // Sort by the element height
   SORT_BY_CANV_ELEMENT_RIGHT,                        // Sort by the element right border
   SORT_BY_CANV_ELEMENT_BOTTOM,                       // Sort by the element bottom border
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_LEFT,               // Sort by the active area offset from the left edge of the element
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_TOP,                // Sort by the active area offset from the top edge of the element
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_RIGHT,              // Sort by the active area offset from the right edge of the element
   SORT_BY_CANV_ELEMENT_ACT_SHIFT_BOTTOM,             // Sort by the active area offset from the bottom edge of the element
   SORT_BY_CANV_ELEMENT_MOVABLE,                      // Sort by the element moveability flag
   SORT_BY_CANV_ELEMENT_ACTIVE,                       // Sort by the element activity flag
   SORT_BY_CANV_ELEMENT_COORD_ACT_X,                  // Sort by X coordinate of the element active area
   SORT_BY_CANV_ELEMENT_COORD_ACT_Y,                  // Sort by Y coordinate of the element active area
   SORT_BY_CANV_ELEMENT_ACT_RIGHT,                    // Sort by the right border of the element active area
   SORT_BY_CANV_ELEMENT_ACT_BOTTOM,                   // Sort by the bottom border of the element active area
//--- Sort by real properties

//--- Sort by string properties
   SORT_BY_CANV_ELEMENT_NAME_OBJ = FIRST_CANV_ELEMENT_STR_PROP,// Sort by an element object name
   SORT_BY_CANV_ELEMENT_NAME_RES,                     // Sort by the graphical resource name
  };
//+------------------------------------------------------------------+


在 \MQL5\Include\DoEasy\Data.mqh 中,为图形对象集合添加新的消息索引

//--- CShadowObj
   MSG_SHADOW_OBJ_IMG_SMALL_BLUR_LARGE,               // Error! Image size too small or blur too extensive

//--- CGraphElementsCollection
   MSG_CHART_OBJ_COLLECTION_ERR_OBJ_ALREADY_EXISTS,   // Error. A chart control object already exists with chart id 
   MSG_CHART_OBJ_COLLECTION_ERR_FAILED_CREATE_CTRL_OBJ,// Failed to create chart control object with chart id 
   
  };
//+------------------------------------------------------------------+

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

//--- CShadowObj
   {"Ошибка! Размер изображения очень маленький или очень большое размытие","Error! Image size is very small or very large blur"},
      
//--- CGraphElementsCollection
   {"Ошибка. Уже существует объект управления чартами с идентификатором чарта ","Error. A chart control object already exists with chart id "},
   {"Не удалось создать объект управления чартами с идентификатором чарта ","Failed to create chart control object with chart id "},

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


现在我们需要在创建时为每个显要的(非辅助)函数库对象指定类型。 辅助对象是主对象运行所必需的对象。 无需为此类对象分配类型,因为它们并非集合对象。 取而代之,它们仅用于主要函数库对象中安排操作和简化计算。

许多函数库对象是从所有函数库对象的基准对象派生而来的。 它所提供的功能,包括存储对象类型值的 m_type 变量,和返回变量所设置对象类型的 Type() 虚拟方法。 相应地,在其衍生后代的构造函数中指定与对象类型 m_type 变量对应的值就足够了。

鉴于我曾介绍过对象从属关系的概念,即从属关系是由图形对象名称中存在的程序名称来定义的。 为了达成这一点,\MQL5\Include\DoEasy\Objects\BaseObj.mqh 中所有函数库对象的基准对象应该在类的受保护部分含有一个新变量,用来存储程序名称:

//+------------------------------------------------------------------+
//| Base object class for all library objects                        |
//+------------------------------------------------------------------+
class CBaseObj : public CObject
  {
protected:
   CGraphElmControl  m_graph_elm;                              // Instance of the class for managing graphical elements
   ENUM_LOG_LEVEL    m_log_level;                              // Logging level
   ENUM_PROGRAM_TYPE m_program;                                // Program type
   bool              m_first_start;                            // First launch flag
   bool              m_use_sound;                              // Flag of playing the sound set for an object
   bool              m_available;                              // Flag of using a descendant object in the program
   int               m_global_error;                           // Global error code
   long              m_chart_id_main;                          // Control program chart ID
   long              m_chart_id;                               // Chart ID
   string            m_name_program;                           // Program name
   string            m_name;                                   // Object name
   string            m_folder_name;                            // Name of the folder storing CBaseObj descendant objects 
   string            m_sound_name;                             // Object sound file name
   int               m_type;                                   // Object type (corresponds to the object type from the ENUM_OBJECT_DE_TYPE enumeration)

public:

在类构造函数中,指定程序名对象类型作为基准对象

//--- Constructor
                     CBaseObj() : m_program((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)),
                                  m_name_program(::MQLInfoString(MQL_PROGRAM_NAME)),
                                  m_global_error(ERR_SUCCESS),
                                  m_log_level(LOG_LEVEL_ERROR_MSG),
                                  m_chart_id_main(::ChartID()),
                                  m_chart_id(::ChartID()),
                                  m_folder_name(DIRECTORY),
                                  m_sound_name(""),
                                  m_name(__FUNCTION__),
                                  m_type(OBJECT_DE_TYPE_BASE),
                                  m_use_sound(false),
                                  m_available(true),
                                  m_first_start(true) {}
  };
//+------------------------------------------------------------------+

除了基准对象类,该文件还包含所有函数库对象的扩展基准对象类。 在其构造函数中将对象类型指定为 base-extended

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CBaseObjExt::CBaseObjExt() : m_hash_sum(0),m_hash_sum_prev(0),
                             m_is_event(false),m_event_code(WRONG_VALUE),
                             m_long_prop_total(0),
                             m_double_prop_total(0)
  {
   this.m_type=OBJECT_DE_TYPE_BASE_EXT;
   ::ArrayResize(this.m_long_prop_event,0,100);
   ::ArrayResize(this.m_double_prop_event,0,100);
   ::ArrayResize(this.m_long_prop_event_prev,0,100);
   ::ArrayResize(this.m_double_prop_event_prev,0,100);
   ::ZeroMemory(this.m_tick);
   this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif);
   this.m_list_events.Clear();
   this.m_list_events.Sort();
   this.m_list_events_base.Clear();
   this.m_list_events_base.Sort();
  }
//+------------------------------------------------------------------+

如果所有函数库对象都衍生自这两个类(基准和基准扩展),则在其构造函数的 m_type 变量中指定对象类型就足够了。

对于 \MQL5\Include\DoEasy\Objects\Accounts\Account.mqh 中的帐户对象,它应如下所示(整个构造函数):

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CAccount::CAccount(void)
  {
   this.m_type=OBJECT_DE_TYPE_ACCOUNT;
//--- Initialize control data
   this.SetControlDataArraySizeLong(ACCOUNT_PROP_INTEGER_TOTAL);
   this.SetControlDataArraySizeDouble(ACCOUNT_PROP_DOUBLE_TOTAL);
   this.ResetChangesParams();
   this.ResetControlsParams();
  
//--- Save integer properties
   this.m_long_prop[ACCOUNT_PROP_LOGIN]                              = ::AccountInfoInteger(ACCOUNT_LOGIN);
   this.m_long_prop[ACCOUNT_PROP_TRADE_MODE]                         = ::AccountInfoInteger(ACCOUNT_TRADE_MODE);
   this.m_long_prop[ACCOUNT_PROP_LEVERAGE]                           = ::AccountInfoInteger(ACCOUNT_LEVERAGE);
   this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS]                       = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE]                     = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
   this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED]                      = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED);
   this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT]                       = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
   this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE]                        = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ;
   this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS]                    = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif ;
   this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE]                        = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4);
   this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE]                         = (#ifdef __MQL5__::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? false : ::AccountInfoInteger(ACCOUNT_FIFO_CLOSE) #else false #endif );
   
//--- Save real properties
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)]          = ::AccountInfoDouble(ACCOUNT_BALANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)]           = ::AccountInfoDouble(ACCOUNT_CREDIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)]           = ::AccountInfoDouble(ACCOUNT_PROFIT);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)]           = ::AccountInfoDouble(ACCOUNT_EQUITY);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)]           = ::AccountInfoDouble(ACCOUNT_MARGIN);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)]      = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)]     = ::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)]   = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)]     = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)]   = ::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)]           = ::AccountInfoDouble(ACCOUNT_ASSETS);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)]      = ::AccountInfoDouble(ACCOUNT_LIABILITIES);
   this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED);
   
//--- Save string properties
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)]             = ::AccountInfoString(ACCOUNT_NAME);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)]           = ::AccountInfoString(ACCOUNT_SERVER);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)]         = ::AccountInfoString(ACCOUNT_CURRENCY);
   this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)]          = ::AccountInfoString(ACCOUNT_COMPANY);

//--- Account object name, object and account type (MetaTrader 5 or 4)
   this.m_name=CMessage::Text(MSG_LIB_PROP_ACCOUNT)+" "+(string)this.Login()+": "+this.Name()+" ("+this.Company()+")";
   this.m_type=COLLECTION_ACCOUNT_ID;
   this.m_type_server=(::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4);

//--- Filling in the current account data
   for(int i=0;i<ACCOUNT_PROP_INTEGER_TOTAL;i++)
      this.m_long_prop_event[i][3]=this.m_long_prop[i];
   for(int i=0;i<ACCOUNT_PROP_DOUBLE_TOTAL;i++)
      this.m_double_prop_event[i][3]=this.m_double_prop[i];

//--- Update the base object data and search for changes
   CBaseObjExt::Refresh();
  }
//+-------------------------------------------------------------------+

如您所见,我们应该只为 m_type 变量设置必要的对象类型。 在这种情况下,它是 “account” 类型。 在基准对象类中编写声明新对象类型值,会将对象类型从 “base” 重新定义为 “account”。 现在,返回 m_type 变量值的虚拟 Type() 方法,已在基准对象中实现,也也会返回在帐户对象类构造函数中重新定义的变量值。

\MQL5\Include\DoEasy\Objects\Book\MarketBookOrd.mqh 中的市场深度抽象订单类拥有两个构造函数 — 默认和参数型构造函数。 在两个构造函数中设置对象类型

默认构造函数:

//--- Compare CMarketBookOrd objects by all properties (to search for equal request objects)
   bool              IsEqual(CMarketBookOrd* compared_req) const;
   
//--- Default constructor
                     CMarketBookOrd(){ this.m_type=OBJECT_DE_TYPE_BOOK_ORDER; }
protected:
//--- Protected parametric constructor
                     CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol);
                     
public:
//+-------------------------------------------------------------------+ 
//|Methods of a simplified access to the DOM request object properties|
//+-------------------------------------------------------------------+

以及参数型:

//+------------------------------------------------------------------+
//| Protected parametric constructor                                 |
//+------------------------------------------------------------------+
CMarketBookOrd::CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol)
  {
   this.m_type=OBJECT_DE_TYPE_BOOK_ORDER;
//--- Save symbol’s Digits
   this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS);
//--- Save integer object properties
   this.SetProperty(MBOOK_ORD_PROP_STATUS,status);
   this.SetProperty(MBOOK_ORD_PROP_TYPE,book_info.type);
   this.SetProperty(MBOOK_ORD_PROP_VOLUME,book_info.volume);
//--- Save real object properties
   this.SetProperty(MBOOK_ORD_PROP_PRICE,book_info.price);
   this.SetProperty(MBOOK_ORD_PROP_VOLUME_REAL,book_info.volume_real);
//--- Save additional object properties
   this.SetProperty(MBOOK_ORD_PROP_SYMBOL,(symbol==NULL || symbol=="" ? ::Symbol() : symbol));
//--- Order time is not present in the parameters and is considered in the DOM snapshot class. Reset the time
   this.SetProperty(MBOOK_ORD_PROP_TIME_MSC,0);
  }
//+------------------------------------------------------------------+

在市场深度抽象订单的衍生后代中,添加相应的对象类型。

\MQL5\Include\DoEasy\Objects\Book\MarketBookBuy.mqh 中的市场深度买单:

//+------------------------------------------------------------------+
//| Buy order in DOM                                                 |
//+------------------------------------------------------------------+
class CMarketBookBuy : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookBuy(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_BUY,book_info,symbol) { this.m_type=OBJECT_DE_TYPE_BOOK_BUY; }
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Book\MarketBookBuyMarket.mqh 中位于市价的市场深度买单:

//+------------------------------------------------------------------+
//| Buy order by Market in DOM                                       |
//+------------------------------------------------------------------+
class CMarketBookBuyMarket : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookBuyMarket(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_BUY,book_info,symbol) { this.m_type=OBJECT_DE_TYPE_BOOK_BUY_MARKET; }
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Book\MarketBookSell.mqh 中的市场深度卖单:

//+------------------------------------------------------------------+
//| Sell order in DOM                                                |
//+------------------------------------------------------------------+
class CMarketBookSell : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookSell(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_SELL,book_info,symbol) { this.m_type=OBJECT_DE_TYPE_BOOK_SELL; }
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Book\MarketBookBuyMarket.mqh 中位于市价的市场深度卖单:

//+------------------------------------------------------------------+
//| Sell order by Market in DOM                                      |
//+------------------------------------------------------------------+
class CMarketBookSellMarket : public CMarketBookOrd
  {
private:

public:
   //--- Constructor
                     CMarketBookSellMarket(const string symbol,const MqlBookInfo &book_info) :
                        CMarketBookOrd(MBOOK_ORD_STATUS_SELL,book_info,symbol) { this.m_type=OBJECT_DE_TYPE_BOOK_SELL_MARKET; }
   //--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property);
//--- Return the object short name
   virtual string    Header(const bool symbol=false);
//--- Return the description of order type (ENUM_BOOK_TYPE)
   virtual string    TypeDescription(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Book\MarketBookSnapshot.mqh 中的“市场深度快照”类有两个构造函数 — 默认构造函数和参数型构造函数。 此处我们需要在两个构造函数中均指定一个对象类型

默认构造函数:

//--- Return the DOM snapshot change
   string            Header(void);
//--- Display (1) description and (2) short description of a DOM snapshot
   virtual void      Print(const bool full_prop=false,const bool dash=false);
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);

//--- Constructors
                     CMBookSnapshot(){ this.m_type=OBJECT_DE_TYPE_BOOK_SNAPSHOT; }
                     CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]);
//+---------------------------------------------------------------------+ 
//|Methods of a simplified access to the DOM snapshot object properties |
//+---------------------------------------------------------------------+

以及参数型:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CMBookSnapshot::CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]) : m_time(time)
  {
   this.m_type=OBJECT_DE_TYPE_BOOK_SNAPSHOT;
   //--- Set a symbol
   this.SetSymbol(symbol);
   //--- Clear the list
   this.m_list.Clear();
   //--- In the loop by the structure array
   int total=::ArraySize(book_array);
   this.m_volume_buy=this.m_volume_sell=0;
   this.m_volume_buy_real=this.m_volume_sell_real=0;
   for(int i=0;i<total;i++)
     {
      //--- Create order objects of the current DOM snapshot depending on the order type
      CMarketBookOrd *mbook_ord=NULL;
      switch(book_array[i].type)
        {
         case BOOK_TYPE_BUY         : mbook_ord=new CMarketBookBuy(this.m_symbol,book_array[i]);         break;
         case BOOK_TYPE_SELL        : mbook_ord=new CMarketBookSell(this.m_symbol,book_array[i]);        break;
         case BOOK_TYPE_BUY_MARKET  : mbook_ord=new CMarketBookBuyMarket(this.m_symbol,book_array[i]);   break;
         case BOOK_TYPE_SELL_MARKET : mbook_ord=new CMarketBookSellMarket(this.m_symbol,book_array[i]);  break;
         default: break;
        }
      if(mbook_ord==NULL)
         continue;
      //--- Set the DOM snapshot time for the order
      mbook_ord.SetTime(this.m_time);

      //--- Set the sorted list flag for the list (by the price value) and add the current order object to it
      //--- If failed to add the object to the DOM order list, remove the order object
      this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE);
      if(!this.m_list.InsertSort(mbook_ord))
         delete mbook_ord;
      //--- If the order object is successfully added to the DOM order list, supplement the total snapshot volumes
      else
        {
         switch(mbook_ord.TypeOrd())
           {
            case BOOK_TYPE_BUY         : 
              this.m_volume_buy+=mbook_ord.Volume(); 
              this.m_volume_buy_real+=mbook_ord.VolumeReal();
              break;
            case BOOK_TYPE_SELL        : 
              this.m_volume_sell+=mbook_ord.Volume(); 
              this.m_volume_sell_real+=mbook_ord.VolumeReal();
              break;
            case BOOK_TYPE_BUY_MARKET  : 
              this.m_volume_buy+=mbook_ord.Volume(); 
              this.m_volume_buy_real+=mbook_ord.VolumeReal();
              break;
            case BOOK_TYPE_SELL_MARKET : 
              this.m_volume_buy+=mbook_ord.Volume(); 
              this.m_volume_buy_real+=mbook_ord.VolumeReal();
              break;
            default: break;
           }
        }
     }
  }
//+------------------------------------------------------------------+

“市场深度快照序列”类也有两个构造函数。 我们在两者中设置对象类型

默认:

//--- Display (1) description and (2) short description of a DOM snapshot series
   virtual void      Print(const bool full_prop=false,const bool dash=false);
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);

//--- Constructors
                     CMBookSeries(){ this.m_type=OBJECT_DE_TYPE_BOOK_SERIES; }
                     CMBookSeries(const string symbol,const uint required=0);

//+------------------------------------------------------------------+ 
//| Methods of working with objects and accessing their properties   |
//+------------------------------------------------------------------+

以及参数型:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CMBookSeries::CMBookSeries(const string symbol,const uint required=0) : m_symbol(symbol)
  {
   this.m_type=OBJECT_DE_TYPE_BOOK_SERIES;
   this.m_list.Clear();
   this.m_list.Sort(SORT_BY_MBOOK_ORD_TIME_MSC);
   this.SetRequiredUsedDays(required);
  }
//+------------------------------------------------------------------+


\MQL5\Include\DoEasy\Objects\Events\Event.mqh 中的抽象事件类不是基准对象的衍生后代,也不是所有函数库对象的扩展基准对象。 因此,它没有 m_type 变量,也没有返回变量值的虚拟 Type() 方法(该方法存在于 CObject 基准对象当中,而该类尽管继承自它,但仅返回 0,并且在衍生后代中应该重新定义)。 这意味着我们需要添加变量和方法,并在类的构造函数中为所创建变量设置必要的类型

//+------------------------------------------------------------------+
//| Abstract event class                                             |
//+------------------------------------------------------------------+
class CEvent : public CObject
  {
private:
   int               m_event_code;                                   // Event code
//--- Return the index of the array the event's (1) double and (2) string properties are located at
   int               IndexProp(ENUM_EVENT_PROP_DOUBLE property)const { return(int)property-EVENT_PROP_INTEGER_TOTAL;                         }
   int               IndexProp(ENUM_EVENT_PROP_STRING property)const { return(int)property-EVENT_PROP_INTEGER_TOTAL-EVENT_PROP_DOUBLE_TOTAL; }
protected:
   ENUM_TRADE_EVENT  m_trade_event;                                  // Trading event
   bool              m_is_hedge;                                     // Hedge account flag
   long              m_chart_id_main;                                // Control program chart ID
   int               m_type;                                         // Object type
   int               m_digits;                                       // Symbol's Digits()
   int               m_digits_acc;                                   // Number of decimal places for the account currency
   long              m_long_prop[EVENT_PROP_INTEGER_TOTAL];          // Event integer properties
   double            m_double_prop[EVENT_PROP_DOUBLE_TOTAL];         // Event real properties
   string            m_string_prop[EVENT_PROP_STRING_TOTAL];         // Event string properties
//--- return the flag presence in the trading event
   bool              IsPresentEventFlag(const int event_code)  const { return (this.m_event_code & event_code)==event_code;                  }
//--- Return (1) the specified magic number, the ID of (2) the first group, (3) second group, (4) pending request from the magic number value
   ushort            GetMagicID(void)                          const { return ushort(this.Magic() & 0xFFFF);                                 }
   uchar             GetGroupID1(void)                         const { return uchar(this.Magic()>>16) & 0x0F;                                }
   uchar             GetGroupID2(void)                         const { return uchar((this.Magic()>>16) & 0xF0)>>4;                           }
   uchar             GetPendReqID(void)                        const { return uchar(this.Magic()>>24) & 0xFF;                                }
//--- Protected parametric constructor
                     CEvent(const ENUM_EVENT_STATUS event_status,const int event_code,const ulong ticket);
public:
//--- Default constructor
                     CEvent(void){ this.m_type=OBJECT_DE_TYPE_EVENT; }
 
//--- Set event's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_EVENT_PROP_INTEGER property,long value) { this.m_long_prop[property]=value;                            }
   void              SetProperty(ENUM_EVENT_PROP_DOUBLE property,double value){ this.m_double_prop[this.IndexProp(property)]=value;          }
   void              SetProperty(ENUM_EVENT_PROP_STRING property,string value){ this.m_string_prop[this.IndexProp(property)]=value;          }
//--- Return the event's (1) integer, (2) real and (3) string properties from the property array
   long              GetProperty(ENUM_EVENT_PROP_INTEGER property)      const { return this.m_long_prop[property];                           }
   double            GetProperty(ENUM_EVENT_PROP_DOUBLE property)       const { return this.m_double_prop[this.IndexProp(property)];         }
   string            GetProperty(ENUM_EVENT_PROP_STRING property)       const { return this.m_string_prop[this.IndexProp(property)];         }

//--- Return the flag of the event supporting the property
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property)        { return true;       }
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property)         { return true;       }
   virtual bool      SupportProperty(ENUM_EVENT_PROP_STRING property)         { return true;       }
//--- Return an object type
   virtual int       Type(void)                                         const { return this.m_type;}

//--- Decode the event code and set the trading event, (2) return the trading event
   void              SetTypeEvent(void);
   ENUM_TRADE_EVENT  TradeEvent(void)                                   const { return this.m_trade_event;                                   }
//--- Send the event to the chart (implementation in descendant classes)
   virtual void      SendEvent(void) {;}

//--- Compare CEvent objects by a specified property (to sort the lists by a specified event object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CEvent objects by all properties (to search for equal event objects)
   bool              IsEqual(CEvent* compared_event);
//+------------------------------------------------------------------+
//| Methods of simplified access to event object properties          |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CEvent::CEvent(const ENUM_EVENT_STATUS event_status,const int event_code,const ulong ticket) : m_event_code(event_code),m_digits(0)
  {
   this.m_type=OBJECT_DE_TYPE_EVENT;
   this.m_long_prop[EVENT_PROP_STATUS_EVENT]       =  event_status;
   this.m_long_prop[EVENT_PROP_TICKET_ORDER_EVENT] =  (long)ticket;
   this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif;
   this.m_digits_acc=#ifdef __MQL4__ 2 #else (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #endif;
   this.m_chart_id_main=::ChartID();
  }
//+------------------------------------------------------------------+

在抽象事件类对象的衍生后代中,我们需要在它们的构造函数中指定必要的对象类型

\MQL5\Include\DoEasy\Objects\Events\EventBalanceOperation.mqh 中的余额操作事件类:

//+------------------------------------------------------------------+
//| Balance operation event                                          |
//+------------------------------------------------------------------+
class CEventBalanceOperation : public CEvent
  {
public:
//--- Constructor
                     CEventBalanceOperation(const int event_code,const ulong ticket=0) : CEvent(EVENT_STATUS_BALANCE,event_code,ticket)
                       { this.m_type=OBJECT_DE_TYPE_EVENT_BALANCE; }
//--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_STRING property);
//--- (1) Display a brief message about the event in the journal, (2) Send the event to the chart
   virtual void      PrintShort(void);
   virtual void      SendEvent(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Events\EventModify.mqh 中的挂单或仓位修改事件类:

//+------------------------------------------------------------------+
//| Pending order or position modification event                     |
//+------------------------------------------------------------------+
class CEventModify : public CEvent
  {
private:
   double            m_price;                               // Price sent to an event
//--- Create and return a short event message
   string            EventsMessage(void);
public:
//--- Constructor
                     CEventModify(const int event_code,const ulong ticket=0) : CEvent(EVENT_STATUS_MODIFY,event_code,ticket),m_price(0)
                       { this.m_type=OBJECT_DE_TYPE_EVENT_MODIFY; }
//--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property);
//--- (1) Display a brief message about the event in the journal, (2) Send the event to the chart
   virtual void      PrintShort(void);
   virtual void      SendEvent(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Events\EventOrderPlaced.mqh 中放置挂单事件类:

//+------------------------------------------------------------------+
//| Pending order placing event                                      |
//+------------------------------------------------------------------+
class CEventOrderPlased : public CEvent
  {
public:
//--- Constructor
                     CEventOrderPlased(const int event_code,const ulong ticket=0) : CEvent(EVENT_STATUS_MARKET_PENDING,event_code,ticket)
                       { this.m_type=OBJECT_DE_TYPE_EVENT_ORDER_PLASED; }
//--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property);
//--- (1) Display a brief message about the event in the journal, (2) Send the event to the chart
   virtual void      PrintShort(void);
   virtual void      SendEvent(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Events\EventOrderRemoved.mqh 中删除挂单事件类:

//+------------------------------------------------------------------+
//| Pending order removal event                                      |
//+------------------------------------------------------------------+
class CEventOrderRemoved : public CEvent
  {
public:
//--- Constructor
                     CEventOrderRemoved(const int event_code,const ulong ticket=0) : CEvent(EVENT_STATUS_HISTORY_PENDING,event_code,ticket)
                       { this.m_type=OBJECT_DE_TYPE_EVENT_ORDER_REMOVED; }
//--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property);
//--- (1) Display a brief message about the event in the journal, (2) Send the event to the chart
   virtual void      PrintShort(void);
   virtual void      SendEvent(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Events\EventPositionClose.mqh 中的平仓事件类:

//+------------------------------------------------------------------+
//| Position closure event                                           |
//+------------------------------------------------------------------+
class CEventPositionClose : public CEvent
  {
private:
//--- Create and return a short event message
   string            EventsMessage(void);  
public:
//--- Constructor
                     CEventPositionClose(const int event_code,const ulong ticket=0) : CEvent(EVENT_STATUS_HISTORY_POSITION,event_code,ticket)
                       { this.m_type=OBJECT_DE_TYPE_EVENT_POSITION_CLOSE; }
//--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property);
//--- (1) Display a brief message about the event in the journal, (2) Send the event to the chart
   virtual void      PrintShort(void);
   virtual void      SendEvent(void);
  };
//+------------------------------------------------------------------+

\MQL5\Include\DoEasy\Objects\Events\EventPositionOpen.mqh 中的开仓事件类:

//+------------------------------------------------------------------+
//| Position opening event                                           |
//+------------------------------------------------------------------+
class CEventPositionOpen : public CEvent
  {
private:
//--- Create and return a short event message
   string            EventsMessage(void);  
public:
//--- Constructor
                     CEventPositionOpen(const int event_code,const ulong ticket=0) : CEvent(EVENT_STATUS_MARKET_POSITION,event_code,ticket)
                       { this.m_type=OBJECT_DE_TYPE_EVENT_POSITION_OPEN; }
//--- Supported order properties (1) real, (2) integer
   virtual bool      SupportProperty(ENUM_EVENT_PROP_INTEGER property);
   virtual bool      SupportProperty(ENUM_EVENT_PROP_DOUBLE property);
//--- (1) Display a brief message about the event in the journal, (2) Send the event to the chart
   virtual void      PrintShort(void);
   virtual void      SendEvent(void);
  };
//+------------------------------------------------------------------+


正如我们所见,所有旨在改进先前所创建对象类的操作都归结为以下几点:

  • 如果对象派生自所有函数库对象的基准或扩展基准对象,则在其构造函数(默认和参数型构造函数)中,为其设置在 Defines.mqh 中所创建的 ENUM_OBJECT_DE_TYPE 枚举中指定的对象类型。
  • 否则,在类的受保护部分中添加 m_type 变量。 该变量用于存储对象类型。 在公开部分,添加返回 m_type 变量值的虚拟 Type() 方法。 在类的构造函数(默认和参数型构造函数)中,为其设置来自 ENUM_OBJECT_DE_TYPE 枚举中指定对象类型。

所有修改都已在函数库对象类的文件中完成。 讲述类似的动作是没有意义的。

以下是 \MQL5\Include\DoEasy\Objects 函数库目录中改进后的类列表:

  • Chart 文件夹: ChartObj.mqh and ChartWnd.mqh;
  • Indicators 文件夹: Buffer.mqh, BufferArrow.mqh, BufferBars.mqh, BufferCalculate.mqh, BufferCandles.mqh,  BufferFilling.mqh, BufferHistogram.mqh, BufferHistogram2.mqh, BufferLine.mqh, BufferSection.mqh, BufferZigZag.mqh, DataInd.mqh, IndicatorDE.mqh and SeriesDataInd.mqh;
    Standart 文件夹: IndAC.mqh, IndAD.mqh, IndADX.mqh, IndADXW.mqh, IndAlligator.mqh, IndAMA.mqh, IndAO.mqh, IndATR.mqh, IndBands.mqh, IndBears.mqh, IndBulls.mqh, IndBWMFI.mqh, IndCCI.mqh, IndChaikin.mqh, IndCustom.mqh, IndDEMA.mqh, IndDeMarker.mqh, IndEnvelopes.mqh, IndForce.mqh, IndFractals.mqh, IndFRAMA.mqh, IndGator.mqh, IndIchimoku.mqh, IndMA.mqh, IndMACD.mqh, IndMFI.mqh, IndMomentum.mqh, IndOBV.mqh, IndOsMA.mqh, IndRSI.mqh, IndRVI.mqh, IndSAR.mqh, IndStDev.mqh, IndStoch.mqh, IndTEMA.mqh, IndTRIX.mqh, IndVIDYA.mqh, IndVolumes.mqh and IndWPR.mqh;
  • MQLSignalBase 文件夹: MQLSignal.mqh;
  • Orders 文件夹: HistoryBalance.mqh, HistoryDeal.mqh, HistoryOrder.mqh, HistoryPending.mqh, MarketOrder.mqh, MarketPending.mqh, MarketPosition.mqh and Order.mqh;
  • PendRequest 文件夹: PendReqClose.mqh, PendReqModify.mqh, PendReqOpen.mqh, PendReqPlace.mqh, PendReqRemove.mqh, PendReqSLTP.mqh and PendRequest.mqh;
  • Series 文件夹: Bar.mqh, SeriesDE.mqh and TimeSeriesDE.mqh;
  • Symbols 文件夹: Symbol.mqh, SymbolBonds.mqh, SymbolCFD.mqh, SymbolCollateral.mqh, SymbolCommodity.mqh, SymbolCommon.mqh, SymbolCrypto.mqh, SymbolCustom.mqh, SymbolExchange.mqh, SymbolFutures.mqh, SymbolFX.mqh, SymbolFXExotic.mqh, SymbolFXMajor.mqh, SymbolFXMinor.mqh, SymbolFXRub.mqh, SymbolIndex.mqh, SymbolIndicative.mqh, SymbolMetall.mqh, SymbolOption.mqh and SymbolStocks.mqh;
  • Ticks 文件夹: DataTick.mqh, NewTickObj.mqh and TickSeries.mqh;
  • Trade 文件夹: TradeObj.mqh;
  • Graph 文件夹: Form.mqh, GCnvElement.mqh, GraphElmControl.mqh and ShadowObj.mqh;
    Animations 文件夹: Animations.mqh, Frame.mqh, FrameGeometry.mqh, FrameQuad.mqh and FrameText.mqh;

所有这些文件都附于文后。

此外,我们不要忘记 \MQL5\Include\DoEasy\Objects\Graph\GBaseObj.mqh 中所有函数库图形对象的基准对象类。 除了指定对象类型,它还具有“程序/终端隶属关系”属性,允许我们定义图形对象是由函数库管控的程序所创建,亦或是由终端中手工添加到图表当中:

//+------------------------------------------------------------------+
//|                                                     GBaseObj.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 "..\..\Services\DELib.mqh"
#include <Graphics\Graphic.mqh>
//+------------------------------------------------------------------+
//| Class of the base object of the library graphical objects        |
//+------------------------------------------------------------------+
class CGBaseObj : public CObject
  {
private:
   
protected:
   string            m_name_prefix;                      // Object name prefix
   string            m_name;                             // Object name
   long              m_chart_id;                         // Chart ID
   int               m_subwindow;                        // Subwindow index
   int               m_shift_y;                          // Subwindow Y coordinate shift
   int               m_type;                             // Object type
   bool              m_visible;                          // Object visibility
   ENUM_GRAPH_OBJ_BELONG m_belong;                       // Program/terminal affiliation
   
//--- Create (1) the object structure and (2) the object from the structure
   virtual bool      ObjectToStruct(void)                      { return true; }
   virtual void      StructToObject(void){;}

public:
//--- Return the values of class variables
   string            Name(void)                          const { return this.m_name;      }
   long              ChartID(void)                       const { return this.m_chart_id;  }
   int               SubWindow(void)                     const { return this.m_subwindow; }
   ENUM_GRAPH_OBJ_BELONG Belong(void)                    const { return this.m_belong;    }
   
//--- (1) Set and (2) return the object visibility
   void              SetVisible(const bool flag)   
                       { 
                        long value=(flag ? OBJ_ALL_PERIODS : 0);
                        if(::ObjectSetInteger(this.m_chart_id,this.m_name,OBJPROP_TIMEFRAMES,value))
                           this.m_visible=flag;
                       }
   bool              IsVisible(void)                     const { return this.m_visible;   }

//--- The virtual method returning the object type
   virtual int       Type(void)                          const { return this.m_type;      }
//--- Set affiliation
   void              SetBelong(const ENUM_GRAPH_OBJ_BELONG belong){ this.m_belong=belong; }

//--- Constructor/destructor
                     CGBaseObj();
                    ~CGBaseObj();
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CGBaseObj::CGBaseObj() : m_shift_y(0),m_visible(false), m_name_prefix(::MQLInfoString(MQL_PROGRAM_NAME)+"_"),m_belong(GRAPH_OBJ_BELONG_PROGRAM)
  {
   this.m_type=OBJECT_DE_TYPE_GBASE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CGBaseObj::~CGBaseObj()
  {
  }
//+------------------------------------------------------------------+


针对 \MQL5\Include\DoEasy\Collections\ 中的函数库对象集合类文件进行了改进,类似类似于函数库对象类文件中实现的改进。

以下是改进的对象集合类的文件列表:

AccountsCollection.mqh, BookSeriesCollection.mqh, BuffersCollection.mqh, ChartObjCollection.mqh, EventsCollection.mqh, HistoryCollection.mqh, IndicatorsCollection.mqh, MarketCollection.mqh, MQLSignalsCollection.mqh, ResourceCollection.mqh, SymbolsCollection.mqh, TickSeriesCollection.mqh, TimeSeriesCollection.mqh。

所有这些文件都附于文后。

库类的改进至此完结。


图形对象类集合

在上一篇文章中,我制作了函数库图形对象集合类 (\MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh) 的首个作品。 在本文中,我将继续拓展它。

在终端中打开的任何图表上手工创建任何图形对象时,函数库应该能够定义它是什么类型的对象,它是新增亦或删除,以及它是如何创建的 — 从函数库中以编程方式或手工。 以编程方式添加的对象不会自动添加到函数库图形对象的集合当中 — 它们在创建时会被加到集合列表之中(我将在后续文章里做到)。 在手工添加图形对象的情况下,函数库应能识别它们,为它们创建图形对象(元素),并将它们添加到集合列表当中。 从图表中删除图形对象时,函数库应该做同样的事情 — 程序对象在删除过程中亦被从列表中删除。 在手工删除的情况下,函数库应跟踪它们,且从集合列表中把匹配的图形对象元素一并删除。

由于功能超过了一篇文章的容量,所以我将按顺序逐步所有操作。 在本文中,我将在图形对象集合类中实现在任何终端图表上跟踪任何出现的图形对象。 程序化或手工创建图形对象的本质并不重要。 集合类将跟踪其从图表中的出现和删除,并将结果发送到日志(从某些终端图表中添加/删除的图形对象的数量)。

若要获取图表上图形对象的数量,我们可以调用 ObjectsTotal() 函数返回指定图表和子窗口里指定类型的图形对象的数量。 若要获取其任何子窗口(包括主窗口)中指定图表上任何类型的图形对象的数量,我们要将所需图表 ID 传递给函数,而其余参数保留为默认值(-1 )。 这可令我们获得所有图表对象的数量,包括子窗口。

为了定义当前添加对象的数量,我们需要知道它们之前和当前的数量。 这两个值之间的差值就是当前添加对象的数量。 故需要两个变量 — 图表上图形对象的当前数量,以及它们在上次检查期间的数量。 如果数量已变化,则定义图表中已被添加/删除的对象类型。

在这一点上,我们遇到了一个问题,即如何正确计算这个数值。 如果我们回到 ObjectsTotal() 函数说明,很明显它每次只返回单个图表的对象数量,而非一次性返回所有图表的数量。 因此,每个图表都应该有自己的变量来存储当前和以前的图形对象数量。 我们能做的最简单的事情就是创建一个小型类来管理图形对象。 每个打开的图表都应该有自己的类实例。 在此情况下,无论其它图表如何,我们都可以轻松跟踪对象数量的变化。

我们直接在图形对象集合类 \MQL5\Include\DoEasy\Collections\GraphElementsCollection.mqh 的文件中实现这个类:

//+------------------------------------------------------------------+
//|                                      GraphElementsCollection.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"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Graph\Form.mqh"
//+------------------------------------------------------------------+
//| Chart object management class                                    |
//+------------------------------------------------------------------+
class CChartObjectsControl : public CObject
  {
private:
   ENUM_TIMEFRAMES   m_chart_timeframe;         // Chart timeframe
   long              m_chart_id;                // 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_index_object;            //  Index of the last graphical object added to the collection from the terminal object list
   int               m_delta_graph_obj;         // Difference in the number of graphical objects compared to the previous check
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;    }
//--- Check the chart objects
   void              Refresh(void);
//--- Constructors
                     CChartObjectsControl(void)
                       { 
                        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_is_graph_obj_event=false;
                        this.m_total_objects=0;
                        this.m_last_objects=0;
                        this.m_index_object=0;
                        this.m_delta_graph_obj=0;
                       }
                     CChartObjectsControl(const long chart_id)
                       {
                        this.m_chart_id=chart_id;
                        this.m_chart_timeframe=(ENUM_TIMEFRAMES)::ChartPeriod(this.m_chart_id);
                        this.m_chart_symbol=::ChartSymbol(this.m_chart_id);
                        this.m_is_graph_obj_event=false;
                        this.m_total_objects=0;
                        this.m_last_objects=0;
                        this.m_index_object=0;
                        this.m_delta_graph_obj=0;
                       }
                     
//--- Compare CChartObjectsControl objects by a chart ID (for sorting the list by an object property)
   virtual int       Compare(const CObject *node,const int mode=0) const
                       {
                        const CChartObjectsControl *obj_compared=node;
                        return(this.ChartID()>obj_compared.ChartID() ? 1 : this.ChartID()<obj_compared.ChartID() ? -1 : 0);
                       }
  };
//+------------------------------------------------------------------+
//| CChartObjectsControl Check objects on a chart                    |
//+------------------------------------------------------------------+
void CChartObjectsControl::Refresh(void)
  {
//--- Graphical objects on the chart
   this.m_total_objects=::ObjectsTotal(this.ChartID());
   int i=this.m_index_object;
   int delta=this.m_total_objects-this.m_last_objects;
   
//--- If the number of objects has changed
   if(delta!=0)
     {
      //--- Create the string and display it in the journal with the chart ID, its symbol and timeframe
      string txt=", "+(delta>0 ? "Added: " : "Deleted: ")+(string)fabs(delta)+" obj";
      Print(DFUN,"ChartID=",this.ChartID(),", ",this.Symbol(),", ",TimeframeDescription(this.Timeframe()),txt);
     }

//--- save the index of the last added order and the difference with the last check
   this.m_delta_graph_obj=i-this.m_index_object;
   this.m_index_object=i;
   this.m_last_objects=this.m_total_objects;
   this.m_is_graph_obj_event=(bool)this.m_delta_graph_obj;
  }
//+------------------------------------------------------------------+

通常,此处的一切都很清晰:有两个变量,分别保存“现在”和“上次”检查期间的图形对象数量。 保存当前循环索引值的变量:为了避免每次都从头开始不断地运行循环,我们需记住当前的索引值,下次不应再从头开始,而是从保存的值开始循环。 这就是订单、交易和仓位管理循环的工作方式。 此处也是一样。 有两个构造函数。 第一个为当前图表创建对象,而第二个依据其 ID 为指定的图表执行相同的操作。 Compare() 方法依据图表 ID 比较两个对象。 它允许我们为具有指定 ID 的图表定义该对象是否已经存在。

在 Refresh() 方法中,只需检查现在和上次检查期间的对象数量。 如果数量已变化,则在日志里显示一条记录。 接下来,从保存在 m_index_object 变量中的循环索引开始循环遍历对象,从而跟踪所有新对象,并创建事件对象。 在该时刻,循环索引已经保存在变量里,后续从该值启动循环,从而节省资源计算。 这是未来操作的地基。

现在,如果我们在集合类的终端中为每个已打开图表创建这样的对象,我们就能够独立跟踪每个图表的对象数量变化。

往先前创建的 CGraphElementsCollection 类添加新变量和方法。

在类的私密部分,声明指向图表管理对象指针的列表在图表上添加/删除图形对象的事件标志变量存储所有已打开图表上对象数量的变量,和存储所有已打开终端图表上添加/删除对象总数的变量

//+------------------------------------------------------------------+
//| Collection of graphical objects                                  |
//+------------------------------------------------------------------+
class CGraphElementsCollection : public CBaseObj
  {
private:
   CArrayObj         m_list_charts_control;     // List of chart management objects
   CListObj          m_list_all_graph_obj;      // List of all graphical objects
   bool              m_is_graph_obj_event;      // Event flag in the list of graphical objects
   int               m_total_objects;           // Number of graphical objects
   int               m_delta_graph_obj;         // Difference in the number of graphical objects compared to the previous check
   
//--- Return the flag indicating the graphical element object in the list of graphical objects
   bool              IsPresentGraphElmInList(const int id,const ENUM_GRAPH_ELEMENT_TYPE type_obj);

在同一部分里声明返回管理指定图表的图形对象指针的方法创建管理指定图表图形对象的新对象,并添加到列表的方法,和依据图表 ID 更新图形对象列表的方法

//--- Return the flag indicating the graphical element object in the list of graphical objects
   bool              IsPresentGraphElmInList(const int id,const ENUM_GRAPH_ELEMENT_TYPE type_obj);
//--- Return the pointer to the object of managing objects of the specified chart
   CChartObjectsControl *GetChartObjectCtrlObj(const long chart_id);
//--- Create a new object of managing graphical objects of a specified chart and add it to the list
   CChartObjectsControl *CreateChartObjectCtrlObj(const long chart_id);
//--- Update the list of graphical objects by chart ID
   void              RefreshByChartID(const long chart_id);

public:

在公开部分,添加返回图形对象列表中已发生变化的标志的方法声明创建图表管理对象列表的方法,和更新终端图表上图形对象列表的两种方法

public:
//--- Return itself
   CGraphElementsCollection *GetObject(void)                                                             { return &this;                        }
   //--- Return the full collection list 'as is'
   CArrayObj        *GetList(void)                                                                       { return &this.m_list_all_graph_obj;   }
   //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion
   CArrayObj        *GetList(ENUM_CANV_ELEMENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByGraphCanvElementProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_CANV_ELEMENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByGraphCanvElementProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_CANV_ELEMENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByGraphCanvElementProperty(this.GetList(),property,value,mode);  }
   //--- Return the number of new graphical objects, (3) the flag of the occurred change in the list of graphical objects
   int               NewObjects(void)   const                                                            { return this.m_delta_graph_obj;       }
   bool              IsEvent(void) const                                                                 { return this.m_is_graph_obj_event;    }
   //--- Constructor
                     CGraphElementsCollection();
//--- Display the description of the object properties in the journal (full_prop=true - all properties, false - supported ones only - implemented in descendant classes)
   virtual void      Print(const bool full_prop=false,const bool dash=false);
//--- Display a short description of the object in the journal
   virtual void      PrintShort(const bool dash=false,const bool symbol=false);

//--- Create the list of chart management objects and return the number of charts
   int               CreateChartControlList(void);
//--- Update the list of (1) all graphical objects, (2) on the specified chart, fill in the data on the number of new ones and set the event flag
   void              Refresh(void);
   void              Refresh(const long chart_id);
  };
//+------------------------------------------------------------------+

在类的构造函数中,为对象分配相应的类型为指定图表管理对象的指针列表设置排序列表标志,并清除列表将所有图表上的对象总数设置为零,并重置图形对象集合的事件标志

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CGraphElementsCollection::CGraphElementsCollection()
  {
   this.m_type=COLLECTION_GRAPH_OBJ_ID;
   ::ChartSetInteger(::ChartID(),CHART_EVENT_MOUSE_MOVE,true);
   ::ChartSetInteger(::ChartID(),CHART_EVENT_MOUSE_WHEEL,true);
   this.m_list_all_graph_obj.Type(COLLECTION_GRAPH_OBJ_ID);
   this.m_list_all_graph_obj.Sort(SORT_BY_CANV_ELEMENT_ID);
   this.m_list_all_graph_obj.Clear();
   this.m_list_charts_control.Sort();
   this.m_list_charts_control.Clear();
   this.m_total_objects=0;
   this.m_is_graph_obj_event=false;
  }
//+------------------------------------------------------------------+

我们来研究一下所声明方法的实现。

创建管理指定图表的图形对象的新对象,并将其添加到列表的方法:

//+------------------------------------------------------------------+
//| Create a new graphical object management object                  |
//| for a specified and add it to the list                           |
//+------------------------------------------------------------------+
CChartObjectsControl *CGraphElementsCollection::CreateChartObjectCtrlObj(const long chart_id)
  {
//--- Create a new object for managing chart objects by ID
   CChartObjectsControl *obj=new CChartObjectsControl(chart_id);
//--- If the object is not created, inform of the error and return NULL
   if(obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_CHART_OBJ_COLLECTION_ERR_FAILED_CREATE_CTRL_OBJ),(string)chart_id);
      return NULL;
     }
//--- If failed to add the object to the list, inform of the error, remove the object and return NULL
   if(!this.m_list_charts_control.Add(obj))
     {
      CMessage::ToLog(DFUN,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
      delete obj;
      return NULL;
     }
//--- Return the pointer to the object that was created and added to the list
   return obj;
  }
//+------------------------------------------------------------------+

返回指定图表管理对象指针的方法:

//+------------------------------------------------------------------+
//| Return the pointer to the object                                 |
//| for managing objects of a specified chart                        |
//+------------------------------------------------------------------+
CChartObjectsControl *CGraphElementsCollection::GetChartObjectCtrlObj(const long chart_id)
  {
//--- In the loop by the total number of objects in the list
   for(int i=0;i<this.m_list_charts_control.Total();i++)
     {
      //--- Get the pointer to the next object
      CChartObjectsControl *obj=this.m_list_charts_control.At(i);
      //--- If failed to get the pointer, move on to the next one
      if(obj==NULL)
         continue;
      //--- If the object chart ID is equal to the required one, return the pointer to the object in the list
      if(obj.ChartID()==chart_id)
         return obj;
     }
//--- Failed to find the object - return NULL
   return NULL;
  }
//+------------------------------------------------------------------+

创建图表管理对象列表的方法:

//+------------------------------------------------------------------+
//| Create the list of chart management objects                      |
//+------------------------------------------------------------------+
int CGraphElementsCollection::CreateChartControlList(void)
  {
   //--- Clear the list of chart management objects and set the sorted list flag to it
   this.m_list_charts_control.Clear();
   this.m_list_charts_control.Sort();
   //--- Declare variables to search for charts
   long chart_id=0;
   int i=0;
//--- In the loop by all open charts in the terminal (no more than 100)
   while(i<CHARTS_MAX)
     {
      //--- Get the chart ID
      chart_id=::ChartNext(chart_id);
      if(chart_id<0)
         break;
      //--- Create the object for managing chart objects based on the current chart ID in the loop and add it to the list
      CChartObjectsControl *chart_control=new CChartObjectsControl(chart_id);
      if(chart_control==NULL)
         continue;
      //--- If such an object is already present in the list, inform of that, delete the object and move on to the next chart
      if(this.m_list_charts_control.Search(chart_control)>WRONG_VALUE)
        {
         ::Print(DFUN,CMessage::Text(MSG_CHART_OBJ_COLLECTION_ERR_OBJ_ALREADY_EXISTS),(string)chart_id);
         delete chart_control;
         continue;
        }
      //--- If failed to add the object to the list, inform of that, remove the object and move on to the next chart
      if(!this.m_list_charts_control.Add(chart_control))
        {
         CMessage::ToLog(DFUN_ERR_LINE,MSG_LIB_SYS_FAILED_OBJ_ADD_TO_LIST);
         delete chart_control;
         continue;
        }
      //--- Increase the loop index
      i++;
     }
   //--- The list filled in successfully - return the number of its elements
   return this.m_list_charts_control.Total();
  }
//+------------------------------------------------------------------+

依据图表 ID 更新图形对象列表的方法:

//+------------------------------------------------------------------+
//| Update the list of graphical objects by chart ID                 |
//+------------------------------------------------------------------+
void CGraphElementsCollection::RefreshByChartID(const long chart_id)
  {
//--- Get the pointer to the object for managing graphical objects
   CChartObjectsControl *obj=GetChartObjectCtrlObj(chart_id);
//--- If there is no such an object in the list, create a new one and add it to the list
   if(obj==NULL)
      obj=this.CreateChartObjectCtrlObj(chart_id);
//--- If the pointer to the object is valid, update the list of graphical objects on a specified chart
   if(obj!=NULL)
      obj.Refresh();
  }
//+------------------------------------------------------------------+

更新指定图表上图形对象列表的方法:

//+------------------------------------------------------------------+
//| Update the list of graphical objects on a specified chart        |
//+------------------------------------------------------------------+
void CGraphElementsCollection::Refresh(const long chart_id)
  {
//--- Get the pointer to the object for managing graphical objects
   CChartObjectsControl *obj=GetChartObjectCtrlObj(chart_id);
//--- If failed to get the pointer, exit the method
   if(obj==NULL)
      return;
//--- Update the list of graphical objects on a specified chart
   obj.Refresh();
  }
//+------------------------------------------------------------------+

更新所有已打开终端图表上所有图形对象列表的方法:

//+------------------------------------------------------------------+
//| Update the list of all graphical objects                         |
//+------------------------------------------------------------------+
void CGraphElementsCollection::Refresh(void)
  {
//--- Declare variables to search for charts
   long chart_id=0;
   int i=0;
//--- In the loop by all open charts in the terminal (no more than 100)
   while(i<CHARTS_MAX)
     {
      //--- Get the chart ID
      chart_id=::ChartNext(chart_id);
      if(chart_id<0)
         break;
      //--- Update the list of graphical objects by chart ID
      this.RefreshByChartID(chart_id);
      //--- Increase the loop index
      i++;
     }
  }
//+------------------------------------------------------------------+

提供的每个方法的逻辑在相应的代码注释中均有详述。 如果您有任何问题,请随时在评论板块咨询。

现在我们需要将新创建的图形对象集合包含到 CEngine 库的主对象当中,从而我们能够从程序访问集合功能。

在 \MQL5\Include\DoEasy\Engine.mqh 中类的私密部分,声明图形对象集合类的实例,及在图形对象列表中声明事件标志变量,并声明管理图形对象事件的方法

//+------------------------------------------------------------------+
//| Library basis class                                              |
//+------------------------------------------------------------------+
class CEngine
  {
private:
   CHistoryCollection   m_history;                       // Collection of historical orders and deals
   CMarketCollection    m_market;                        // Collection of market orders and deals
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CSymbolsCollection   m_symbols;                       // Symbol collection
   CTimeSeriesCollection m_time_series;                  // Timeseries collection
   CBuffersCollection   m_buffers;                       // Collection of indicator buffers
   CIndicatorsCollection m_indicators;                   // Indicator collection
   CTickSeriesCollection m_tick_series;                  // Collection of tick series
   CMBookSeriesCollection m_book_series;                 // Collection of DOM series
   CMQLSignalsCollection m_signals_mql5;                 // Collection of MQL5.com Signals service signals
   CChartObjCollection  m_charts;                        // Chart collection
   CGraphElementsCollection m_graph_objects;             // Collection of graphical objects
   CResourceCollection  m_resource;                      // Resource list
   CTradingControl      m_trading;                       // Trading management object
   CPause               m_pause;                         // Pause object
   CArrayObj            m_list_counters;                 // List of timer counters
   int                  m_global_error;                  // Global error code
   bool                 m_first_start;                   // First launch flag
   bool                 m_is_hedge;                      // Hedge account flag
   bool                 m_is_tester;                     // Flag of working in the tester
   bool                 m_is_market_trade_event;         // Account trading event flag
   bool                 m_is_history_trade_event;        // Account history trading event flag
   bool                 m_is_account_event;              // Account change event flag
   bool                 m_is_symbol_event;               // Symbol change event flag
   bool                 m_is_graph_obj_event;            // Event flag in the list of graphical objects
   ENUM_TRADE_EVENT     m_last_trade_event;              // Last account trading event
   int                  m_last_account_event;            // Last event in the account properties
   int                  m_last_symbol_event;             // Last event in the symbol properties
   ENUM_PROGRAM_TYPE    m_program;                       // Program type
   string               m_name;                          // Program name
//--- Return the counter index by id
   int                  CounterIndex(const int id) const;
//--- Return the first launch flag
   bool                 IsFirstStart(void);
//--- Handling events of (1) orders, deals and positions, (2) accounts and (3) graphical objects
   void                 TradeEventsControl(void);
   void                 AccountEventsControl(void);
   void                 GraphObjEventsControl(void);
//--- (1) Working with a symbol collection and (2) symbol list events in the market watch window
   void                 SymbolEventsControl(void);
   void                 MarketWatchEventsControl(void);
//--- Return the last (1) market pending order, (2) market order, (3) last position, (4) position by ticket
   COrder              *GetLastMarketPending(void);
   COrder              *GetLastMarketOrder(void);
   COrder              *GetLastPosition(void);
   COrder              *GetPosition(const ulong ticket);
//--- Return the last (1) removed pending order, (2) historical market order, (3) historical order (market or pending one) by its ticket
   COrder              *GetLastHistoryPending(void);
   COrder              *GetLastHistoryOrder(void);
   COrder              *GetHistoryOrder(const ulong ticket);
//--- Return the (1) first and the (2) last historical market orders from the list of all position orders, (3) the last deal
   COrder              *GetFirstOrderPosition(const ulong position_id);
   COrder              *GetLastOrderPosition(const ulong position_id);
   COrder              *GetLastDeal(void);
//--- Retrieve a necessary 'ushort' number from the packed 'long' value
   ushort               LongToUshortFromByte(const long source_value,const uchar index) const;
   
public:

在类构造函数中,创建图形对象集合的计数器

//+------------------------------------------------------------------+
//| CEngine constructor                                              |
//+------------------------------------------------------------------+
CEngine::CEngine() : m_first_start(true),
                     m_last_trade_event(TRADE_EVENT_NO_EVENT),
                     m_last_account_event(WRONG_VALUE),
                     m_last_symbol_event(WRONG_VALUE),
                     m_global_error(ERR_SUCCESS)
  {
   this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif;
   this.m_is_tester=::MQLInfoInteger(MQL_TESTER);
   this.m_program=(ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE);
   this.m_name=::MQLInfoString(MQL_PROGRAM_NAME);
   
   this.m_list_counters.Sort();
   this.m_list_counters.Clear();
   this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE);
   this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE);
   this.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1);
   this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2);
   this.CreateCounter(COLLECTION_REQ_COUNTER_ID,COLLECTION_REQ_COUNTER_STEP,COLLECTION_REQ_PAUSE);
   this.CreateCounter(COLLECTION_TS_COUNTER_ID,COLLECTION_TS_COUNTER_STEP,COLLECTION_TS_PAUSE);
   this.CreateCounter(COLLECTION_IND_TS_COUNTER_ID,COLLECTION_IND_TS_COUNTER_STEP,COLLECTION_IND_TS_PAUSE);
   this.CreateCounter(COLLECTION_TICKS_COUNTER_ID,COLLECTION_TICKS_COUNTER_STEP,COLLECTION_TICKS_PAUSE);
   this.CreateCounter(COLLECTION_CHARTS_COUNTER_ID,COLLECTION_CHARTS_COUNTER_STEP,COLLECTION_CHARTS_PAUSE);
   this.CreateCounter(COLLECTION_GRAPH_OBJ_COUNTER_ID,COLLECTION_GRAPH_OBJ_COUNTER_STEP,COLLECTION_GRAPH_OBJ_PAUSE);
   
   ::ResetLastError();
   #ifdef __MQL5__
      if(!::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TIMER),(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   //---__MQL4__
   #else 
      if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TIMER),(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   #endif 
   //---
  }
//+------------------------------------------------------------------+

在计时器类中,添加处理图形对象集合的计时器

//+------------------------------------------------------------------+
//| CEngine timer                                                    |
//+------------------------------------------------------------------+
void CEngine::OnTimer(SDataCalculate &data_calculate)
  {
//--- If this is not a tester, work with collection events by timer
   if(!this.IsTester())
     {
   //--- Timer of the collections of historical orders and deals, as well as of market orders and positions
      int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID);
      CTimerCounter* cnt1=this.m_list_counters.At(index);
      if(cnt1!=NULL)
        {
         //--- If unpaused, work with the order, deal and position collections events
         if(cnt1.IsTimeDone())
            this.TradeEventsControl();
        }
   //--- Account collection timer
      index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID);
      CTimerCounter* cnt2=this.m_list_counters.At(index);
      if(cnt2!=NULL)
        {
         //--- If unpaused, work with the account collection events
         if(cnt2.IsTimeDone())
            this.AccountEventsControl();
        }
   //--- Timer 1 of the symbol collection (updating symbol quote data in the collection)
      index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1);
      CTimerCounter* cnt3=this.m_list_counters.At(index);
      if(cnt3!=NULL)
        {
         //--- If the pause is over, update quote data of all symbols in the collection
         if(cnt3.IsTimeDone())
            this.m_symbols.RefreshRates();
        }
   //--- Timer 2 of the symbol collection (updating all data of all symbols in the collection and tracking symbl and symbol search events in the market watch window)
      index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2);
      CTimerCounter* cnt4=this.m_list_counters.At(index);
      if(cnt4!=NULL)
        {
         //--- If the pause is over
         if(cnt4.IsTimeDone())
           {
            //--- update data and work with events of all symbols in the collection
            this.SymbolEventsControl();
            //--- When working with the market watch list, check the market watch window events
            if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH)
               this.MarketWatchEventsControl();
           }
        }
   //--- Trading class timer
      index=this.CounterIndex(COLLECTION_REQ_COUNTER_ID);
      CTimerCounter* cnt5=this.m_list_counters.At(index);
      if(cnt5!=NULL)
        {
         //--- If unpaused, work with the list of pending requests
         if(cnt5.IsTimeDone())
            this.m_trading.OnTimer();
        }
   //--- Timeseries collection timer
      index=this.CounterIndex(COLLECTION_TS_COUNTER_ID);
      CTimerCounter* cnt6=this.m_list_counters.At(index);
      if(cnt6!=NULL)
        {
         //--- If the pause is over, work with the timeseries list (update all except the current one)
         if(cnt6.IsTimeDone())
            this.SeriesRefreshAllExceptCurrent(data_calculate);
        }
        
   //--- Timer of timeseries collection of indicator buffer data
      index=this.CounterIndex(COLLECTION_IND_TS_COUNTER_ID);
      CTimerCounter* cnt7=this.m_list_counters.At(index);
      if(cnt7!=NULL)
        {
         //--- If the pause is over, work with the timeseries list of indicator data (update all except for the current one)
         if(cnt7.IsTimeDone()) 
            this.IndicatorSeriesRefreshAll();
        }
   //--- Tick series collection timer
      index=this.CounterIndex(COLLECTION_TICKS_COUNTER_ID);
      CTimerCounter* cnt8=this.m_list_counters.At(index);
      if(cnt8!=NULL)
        {
         //--- If the pause is over, work with the tick series list (update all except the current one)
         if(cnt8.IsTimeDone())
            this.TickSeriesRefreshAllExceptCurrent();
        }
   //--- Chart collection timer
      index=this.CounterIndex(COLLECTION_CHARTS_COUNTER_ID);
      CTimerCounter* cnt9=this.m_list_counters.At(index);
      if(cnt9!=NULL)
        {
         //--- If unpaused, work with the chart list
         if(cnt9.IsTimeDone())
            this.ChartsRefreshAll();
        }
        
   //--- Graphical objects collection timer
      index=this.CounterIndex(COLLECTION_GRAPH_OBJ_COUNTER_ID);
      CTimerCounter* cnt10=this.m_list_counters.At(index);
      if(cnt10!=NULL)
        {
         //--- If unpaused, work with the list of graphical objects
         if(cnt10.IsTimeDone())
            this.GraphObjEventsControl();
        }
        
     }
//--- If this is a tester, work with collection events by tick
   else
     {
      //--- work with events of collections of orders, deals and positions by tick
      this.TradeEventsControl();
      //--- work with events of collections of accounts by tick
      this.AccountEventsControl();
      //--- update quote data of all collection symbols by tick
      this.m_symbols.RefreshRates();
      //--- work with events of all symbols in the collection by tick
      this.SymbolEventsControl();
      //--- work with the list of pending orders by tick
      this.m_trading.OnTimer();
      //--- work with the timeseries list by tick
      this.SeriesRefresh(data_calculate);
      //--- work with the timeseries list of indicator buffers by tick
      this.IndicatorSeriesRefreshAll();
      //--- work with the list of tick series by tick
      this.TickSeriesRefreshAll();
      //--- work with the list of graphical objects by tick
      this.GraphObjEventsControl();
     }
  }
//+------------------------------------------------------------------+

在类的主体之外,实现检查图形对象事件的方法:

//+------------------------------------------------------------------+
//| Check the events of graphical objects                            |
//+------------------------------------------------------------------+
void CEngine::GraphObjEventsControl(void)
  {
//--- Check the changes in the list of graphical objects and set the flag of their events
   this.m_graph_objects.Refresh();
   this.m_is_graph_obj_event=this.m_graph_objects.IsEvent();
//--- If there are changes in the list of graphical objects
   if(this.m_is_graph_obj_event)
     {
      Print(DFUN,"Graph obj is event. NewObjects: ",m_graph_objects.NewObjects());
      //--- Get the last event of the graphical object property change
      // ...
     }
  }
//+------------------------------------------------------------------+

此处,我们简单地调用更新所有已打开终端图表的方法,以防其中的图形对象数量发生任何变化

高亮显示之后的所有后续方法代码,均尚未处理。 相应的功能将在后续的文章里实现。 与此同时,图形对象集合类的 Refresh() 方法通过上述图形对象管理对象的相应 Refresh() 方法,来交替调用搜索所有图表事件的方法。 该方法(每个已打开图表的唯一方法)通过日志记录通知相应图表上图形对象的数量变化。 我们来测试一下这个行为。


测试

为了执行测试,我们沿用上一篇文章中的 EA,并将其保存在 \MQL5\Experts\TestDoEasy\Part82\ 中,命名为 TestDoEasyPart82.mq5

在此我们需要做一些细微的改动。

添加 OnTimer() 处理程序,调用函数库计时器,以防操作在测试器之外执行

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Launch the library timer (only not in the tester)
   if(!MQLInfoInteger(MQL_TESTER))
      engine.OnTimer(rates_data);
  }
//+------------------------------------------------------------------+

OnChartEvent() 处理程序中,添加按下 Ctrl 同时,禁止鼠标右键调用关联菜单,因为在这种情况下我们会创建带有柱线类型值的柱线对象(这是在上一篇文章中完成的),并稍微增加所创建对象的宽度,如此令其能够容纳冗长的柱线描述(“Candle with zero body ”):

//+------------------------------------------------------------------+
//| 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();
           }
         //--- Redraw the chart
         ChartRedraw();
        }
     }
  }
//+------------------------------------------------------------------+

这些就是 EA 的全部改进。

在某个品种图表(应该有多个已打开的图表)上启动它,并在每个图表上添加图形对象 — 日志将显示相应的消息。 接下来,在每个图表上单击删除,把所有高亮显示的图形对象删除掉。 日志中会再次显示相应的消息:



下一步是什么?

在下一篇文章中,我将继续细化图形对象集合。

并非所有图形对象都已准备就绪。 这会令创建图形对象集合更加合理,因为我们必须在集合列表中存储指向对象的指针,以供进一步开发。 我将在处理集合后立即实现指针。

以下是该函数库当前版本的所有文件,以及 MQL5 的测试 EA 文件,供您测试和下载。
请您在评论中留下问题和建议。

返回内容目录

*该系列的前几篇文章:

DoEasy 函数库中的图形(第七十三部分):图形元素的交互窗对象
DoEasy 函数库中的图形(第七十四部分):由 CCanvas 类提供强力支持的基本图形元素
DoEasy 函数库中的图形(第七十五部分):处理基本图形元素图元和文本的方法
DoEasy 函数库中的图形(第七十六部分):会话窗对象和预定义的颜色主题
DoEasy 函数库中的图形(第七十七部分):阴影对象类
DoEasy 函数库中的图形(第七十八部分):函数库中的动画原理 图像切片
DoEasy 函数库中的图形(第七十九部分):“动画框”对象类及其衍生对象
DoEasy 函数库中的图形(第八十部分):“几何动画框”对象类
DoEasy 函数库中的图形(第八十一部分):将图形集成到函数库对象之中

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/9850

附加的文件 |
MQL5.zip (4043.48 KB)
MetaTrader 5 中的出价/要价(Bid/Ask)点差分析 MetaTrader 5 中的出价/要价(Bid/Ask)点差分析
一款能为您报告经纪商平台出价/要价(Bid/Ask)水平的指标。 现在我们可以利用 MT5 的即时报价数据来分析近期的历史真实平均买卖点差是多少。 您不需要查看当前点差,因为若您同时显示出价和要价指示线时,该值已出示。
更好的程序员(第 04 部分):如何成为更迅捷的开发人员 更好的程序员(第 04 部分):如何成为更迅捷的开发人员
每位开发人员都希望能够更快地编写代码,且能够更快、更有效地编写代码并非只是少数人与生俱来的特殊能力。 无论有多少年的敲键盘经验,这项技能每位编码员都可以学习。
探索创建多彩烛条的选项 探索创建多彩烛条的选项
在本文中,我将探讨创建烛条自定义指标的可能性,并指出它们的优缺点。
更好的程序员(第 03 部分):放弃做这 5 件事成为一名成功的 MQL5 程序员 更好的程序员(第 03 部分):放弃做这 5 件事成为一名成功的 MQL5 程序员
这是任何想要提高编程职业生涯的从业者必读文章。 本系列文章旨在尽最大可能令您成为最佳程序员,无论您有多少经验。 研讨的思路适用于 MQL5 编程萌新和专业人士。