
DoEasy 函数库中的图形(第八十二部分):函数库对象重构和图形对象集合
内容
概述
在上一篇文章中,我开始将图形处理与函数库对象集成在一起。 每个函数库对象都有自己的对象实例,用于处理图形对象,允许它构建相应的图形对象(标准和基于 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 Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/9850


