我已在函数库论述的第三部分当中定义了构造对象集合类的概念。 在此,我坚持采用这种数据存储结构。 这意味着我们需要为品种集合创建一个列表。 该列表用于存储在上一篇文章中创建的“品种”类的衍生对象。 抽象品种的后代会阐明品种数据,并在程序中定义基本品种对象属性的可用性。 此类品种对象应按其分组的隶属关系(品种状态)加以区分。
为了定义一个品种所属的分组(品种状态),我们将创建自定义数据集 — 品种名称的数组,其中首先是所要搜索的类别。 如果在自定义类别中找不到品种(在任何用户定义的品种名称数组中均不存在其名称),则该类别按“保证金计算方法”(ENUM_SYMBOL_CALC_MODE)品种定义属性,令我们可以定义品种是否属于上面列出的某些类别。 换言之,我们将搜索分为两次检查:第一次按自定义类别中执行。 如果定义类别失败,则使用保证金计算方法搜索品种。 以前,我计划运用另一种方法 — 按照服务器上品种目录树的文件夹名称来定义。 但是此方法实在不可靠,因为文件夹可含有任意名称,并且同一品种可能位于不同的服务器上。 因此,我决定弃用它。
自定义类别将具有更高的优先级 — 如果用户希望将品种(例如,USDUSC)放置在“主要”类别中,那么尽管它是指导性的,但也没有什么理由可以阻止他/她这样做。
现在我们已经决定了类别,我们来为它们创建必要的抽象品种衍生类。 抽象品种本身已在上一篇文章中创建。
为了保存所有品种对象,我们需要用到自 CArrayObj标准库类继承的 CListObj 类,我们在第五篇文章中重新组织函数库类时已研究过它。 在基于函数库的程序中,可以选择要操控的品种列表:
所以,为了访问操控品种,我们需要涵盖大多数必要的编程任务。
在此,我要提到两件事:
最初,在选择这种工作方法时,至少要警告用户有关集合初始化所需花费时间的信息。
我们会这样做的,并在后续文章中实现跟踪品种事件和市场观察窗口事件。 现在,我们来创建一个集合列表。
首先,我们创建另一个包含文件,其中将存储函数库所需的所有数据 — 自定义品种分组、文件、图像的数组,以及该函数库随后所需的其他数据集。
在函数的 \MQL5\Include\DoEasy\ 文件夹,创建一个新的 Datas.mqh 包含文件,并在其中添加一些我已经预先为若干个帐户准备好的数组,同时从市场观察窗口的树形结构中收集不同服务器上的品种分组数据:
//+------------------------------------------------------------------+ //| Datas.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" //+------------------------------------------------------------------+ //| Data sets | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Major Forex symbols | //+------------------------------------------------------------------+ string DataSymbolsFXMajors[]= { "AUDCAD","AUDCHF","AUDJPY","AUDNZD","AUDUSD","CADCHF","CADJPY","CHFJPY","EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD", "EURUSD","GBPAUD","GBPCAD","GBPCHF","GBPJPY","GBPNZD","GBPUSD","NZDCAD","NZDCHF","NZDJPY","NZDUSD","USDCAD","USDCHF","USDJPY" }; //+------------------------------------------------------------------+ //| Minor Forex symbols | //+------------------------------------------------------------------+ string DataSymbolsFXMinors[]= { "EURCZK","EURDKK","EURHKD","EURNOK","EURPLN","EURSEK","EURSGD","EURTRY","EURZAR","GBPSEK","GBPSGD" ,"NZDSGD","USDCZK","USDDKK","USDHKD","USDNOK","USDPLN","USDSEK","USDSGD","USDTRY","USDZAR" }; //+------------------------------------------------------------------+ //| Exotic Forex symbols | //+------------------------------------------------------------------+ string DataSymbolsFXExotics[]= { "EURMXN","USDCNH","USDMXN","EURTRY","USDTRY" }; //+------------------------------------------------------------------+ //| Forex RUB symbols | //+------------------------------------------------------------------+ string DataSymbolsFXRub[]= { "EURRUB","USDRUB" }; //+------------------------------------------------------------------+ //| Indicative Forex symbols | //+------------------------------------------------------------------+ string DataSymbolsFXIndicatives[]= { "EUREUC","USDEUC","USDUSC" }; //+------------------------------------------------------------------+ //| Metal symbols | //+------------------------------------------------------------------+ string DataSymbolsMetalls[]= { "XAGUSD","XAUUSD" }; //+------------------------------------------------------------------+ //| Commodity symbols | //+------------------------------------------------------------------+ string DataSymbolsCommodities[]= { "BRN","WTI","NG" }; //+------------------------------------------------------------------+ //| Indices | //+------------------------------------------------------------------+ string DataSymbolsIndexes[]= { "CAC40","HSI50","ASX200","STOXX50","NQ100","FTSE100","DAX30","IBEX35","SPX500","NIKK225" "Volatility 10 Index","Volatility 25 Index","Volatility 50 Index","Volatility 75 Index","Volatility 100 Index", "HF Volatility 10 Index","HF Volatility 50 Index","Crash 1000 Index","Boom 1000 Index","Step Index" }; //+------------------------------------------------------------------+ //| Cryptocurrency Symbols | //+------------------------------------------------------------------+ string DataSymbolsCrypto[]= { "BCHUSD","BTCEUR","BTCUSD","DSHUSD","EOSUSD","ETHEUR","ETHUSD","LTCUSD","XRPUSD" }; //+------------------------------------------------------------------+ //| Options | //+------------------------------------------------------------------+ string DataSymbolsOptions[]= { "BO Volatility 10 Index","BO Volatility 25 Index","BO Volatility 50 Index","BO Volatility 75 Index","BO Volatility 100 Index" }; //+------------------------------------------------------------------+
我们从清单中可以看出,这只是添加了品种名称的枚举,一个品种分组所需数组在每个数组当中定义。 如果期望并有必要,您可以随意处理这些品种名称数组的内容,譬如将一些名称发送到另一个数组、添加/删除一些名称,等等。
抽象品种对象行为的更多“严格”测试可加深理解,使用 SYMBOL_MARGIN_LONG、SYMBOL_MARGIN_SHORT、SYMBOL_MARGIN_STOP、SYMBOL_MARGIN_LIMIT 和 SYMBOL_MARGIN_STOPLIMIT 常量不会涉及品种属性。 所以,我不得不利用 SymbolInfoMarginRate() 函数来实现接收属性。
由于一笔订单类型已发送到函数,因此我必须在 Defines.mqh 文件里为每种订单类型创建一个实数型自定义常量:
//+------------------------------------------------------------------+ //| Symbol real properties | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_PROP_DOUBLE { SYMBOL_PROP_BID = SYMBOL_PROP_INTEGER_TOTAL, // Bid - the best price at which a symbol can be sold SYMBOL_PROP_BIDHIGH, // The highest Bid price of the day SYMBOL_PROP_BIDLOW, // The lowest Bid price of the day SYMBOL_PROP_ASK, // Ask - best price, at which an instrument can be bought SYMBOL_PROP_ASKHIGH, // The highest Ask price of the day SYMBOL_PROP_ASKLOW, // The lowest Ask price of the day SYMBOL_PROP_LAST, // The price at which the last deal was executed SYMBOL_PROP_LASTHIGH, // The highest Last price of the day SYMBOL_PROP_LASTLOW, // The lowest Last price of the day SYMBOL_PROP_VOLUME_REAL, // Volume of the day SYMBOL_PROP_VOLUMEHIGH_REAL, // Maximum Volume within a day SYMBOL_PROP_VOLUMELOW_REAL, // Minimum Volume within a day SYMBOL_PROP_OPTION_STRIKE, // Option execution price SYMBOL_PROP_POINT, // One point value SYMBOL_PROP_TRADE_TICK_VALUE, // SYMBOL_TRADE_TICK_VALUE_PROFIT value SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT, // Calculated tick value for a winning position SYMBOL_PROP_TRADE_TICK_VALUE_LOSS, // Calculated tick value for a losing position SYMBOL_PROP_TRADE_TICK_SIZE, // Minimum price change SYMBOL_PROP_TRADE_CONTRACT_SIZE, // Trade contract size SYMBOL_PROP_TRADE_ACCRUED_INTEREST, // Accrued interest SYMBOL_PROP_TRADE_FACE_VALUE, // Face value – initial bond value set by an issuer SYMBOL_PROP_TRADE_LIQUIDITY_RATE, // Liquidity rate – the share of an asset that can be used for a margin SYMBOL_PROP_VOLUME_MIN, // Minimum volume for a deal SYMBOL_PROP_VOLUME_MAX, // Maximum volume for a deal SYMBOL_PROP_VOLUME_STEP, // Minimum volume change step for deal execution SYMBOL_PROP_VOLUME_LIMIT, // The maximum allowed total volume of an open position and pending orders in one direction (either buy or sell) SYMBOL_PROP_SWAP_LONG, // Long swap value SYMBOL_PROP_SWAP_SHORT, // Short swap value SYMBOL_PROP_MARGIN_INITIAL, // Initial margin SYMBOL_PROP_MARGIN_MAINTENANCE, // Maintenance margin for an instrument SYMBOL_PROP_MARGIN_LONG_INITIAL, // Initial margin requirement applicable to long positions SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL, // Initial margin requirement applicable to BuyStop orders SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL, // Initial margin requirement applicable to BuyLimit orders SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL, // Initial margin requirement applicable to BuyStopLimit orders SYMBOL_PROP_MARGIN_LONG_MAINTENANCE, // Maintenance margin requirement applicable to long positions SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE, // Maintenance margin requirement applicable to BuyStop orders SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE, // Maintenance margin requirement applicable to BuyLimit orders SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Maintenance margin requirement applicable to BuyStopLimit orders SYMBOL_PROP_MARGIN_SHORT_INITIAL, // Initial margin requirement applicable to short positions SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL, // Initial margin requirement applicable to SellStop orders SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL, // Initial margin requirement applicable to SellLimit orders SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL, // Initial margin requirement applicable to SellStopLimit orders SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE, // Maintenance margin requirement applicable to short positions SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE, // Maintenance margin requirement applicable to SellStop orders SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE, // Maintenance margin requirement applicable to SellLimit orders SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Maintenance margin requirement applicable to SellStopLimit orders SYMBOL_PROP_SESSION_VOLUME, // The total volume of deals in the current session SYMBOL_PROP_SESSION_TURNOVER, // The total turnover in the current session SYMBOL_PROP_SESSION_INTEREST, // The total volume of open positions SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME, // The total volume of Buy orders at the moment SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME, // The total volume of Sell orders at the moment SYMBOL_PROP_SESSION_OPEN, // Open price of the session SYMBOL_PROP_SESSION_CLOSE, // Close price of the session SYMBOL_PROP_SESSION_AW, // The average weighted price of the session SYMBOL_PROP_SESSION_PRICE_SETTLEMENT, // The settlement price of the current session SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN, // Minimum allowable price value for the session SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX, // Maximum allowable price value for the session SYMBOL_PROP_MARGIN_HEDGED // Size of a contract or margin for one lot of hedged positions (oppositely directed positions at one symbol). }; #define SYMBOL_PROP_DOUBLE_TOTAL (58) // Total number of real properties #define SYMBOL_PROP_DOUBLE_SKIP (0) // Number of real symbol properties not used in sorting //+------------------------------------------------------------------+
相应地,实数型属性的总数已增加到 58(替换以前的 47 个)。
我还不得不在枚举中添加相应的可用于品种排序条件的常量:
//+------------------------------------------------------------------+ //| Possible symbol sorting criteria | //+------------------------------------------------------------------+ #define FIRST_SYM_DBL_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP) #define FIRST_SYM_STR_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP+SYMBOL_PROP_DOUBLE_TOTAL-SYMBOL_PROP_DOUBLE_SKIP) enum ENUM_SORT_SYMBOLS_MODE { //--- Sort by integer properties SORT_BY_SYMBOL_STATUS = 0, // Sort by symbol status SORT_BY_SYMBOL_CUSTOM, // Sort by custom symbol property SORT_BY_SYMBOL_CHART_MODE, // Sort by price type for constructing bars – Bid or Last (from the ENUM_SYMBOL_CHART_MODE enumeration) SORT_BY_SYMBOL_EXIST, // Sort by the flag that a symbol with such a name exists SORT_BY_SYMBOL_SELECT, // Sort by the flag indicating that a symbol is selected in Market Watch SORT_BY_SYMBOL_VISIBLE, // Sort by the flag indicating that a selected symbol is displayed in Market Watch SORT_BY_SYMBOL_SESSION_DEALS, // Sort by the number of deals in the current session SORT_BY_SYMBOL_SESSION_BUY_ORDERS, // Sort by the total number of current buy orders SORT_BY_SYMBOL_SESSION_SELL_ORDERS, // Sort by the total number of current sell orders SORT_BY_SYMBOL_VOLUME, // Sort by last deal volume SORT_BY_SYMBOL_VOLUMEHIGH, // Sort by maximum volume for a day SORT_BY_SYMBOL_VOLUMELOW, // Sort by minimum volume for a day SORT_BY_SYMBOL_TIME, // Sort by the last quote time SORT_BY_SYMBOL_DIGITS, // Sort by a number of decimal places SORT_BY_SYMBOL_DIGITS_LOT, // Sort by a number of decimal places in a lot SORT_BY_SYMBOL_SPREAD, // Sort by spread in points SORT_BY_SYMBOL_SPREAD_FLOAT, // Sort by floating spread SORT_BY_SYMBOL_TICKS_BOOKDEPTH, // Sort by a maximum number of requests displayed in the market depth SORT_BY_SYMBOL_TRADE_CALC_MODE, // Sort by contract price calculation method (from the ENUM_SYMBOL_CALC_MODE enumeration) SORT_BY_SYMBOL_TRADE_MODE, // Sort by order execution type (from the ENUM_SYMBOL_TRADE_MODE enumeration) SORT_BY_SYMBOL_START_TIME, // Sort by an instrument trading start date (usually used for futures) SORT_BY_SYMBOL_EXPIRATION_TIME, // Sort by an instrument trading end date (usually used for futures) SORT_BY_SYMBOL_TRADE_STOPS_LEVEL, // Sort by the minimum indent from the current close price (in points) for setting Stop orders SORT_BY_SYMBOL_TRADE_FREEZE_LEVEL, // Sort by trade operation freeze distance (in points) SORT_BY_SYMBOL_TRADE_EXEMODE, // Sort by trade execution mode (from the ENUM_SYMBOL_TRADE_EXECUTION enumeration) SORT_BY_SYMBOL_SWAP_MODE, // Sort by swap calculation model (from the ENUM_SYMBOL_SWAP_MODE enumeration) SORT_BY_SYMBOL_SWAP_ROLLOVER3DAYS, // Sort by week day for accruing a triple swap (from the ENUM_DAY_OF_WEEK enumeration) SORT_BY_SYMBOL_MARGIN_HEDGED_USE_LEG, // Sort by the calculation mode of a hedged margin using the larger leg (Buy or Sell) SORT_BY_SYMBOL_EXPIRATION_MODE, // Sort by flags of allowed order expiration modes SORT_BY_SYMBOL_FILLING_MODE, // Sort by flags of allowed order filling modes SORT_BY_SYMBOL_ORDER_MODE, // Sort by flags of allowed order types SORT_BY_SYMBOL_ORDER_GTC_MODE, // Sort by StopLoss and TakeProfit orders lifetime SORT_BY_SYMBOL_OPTION_MODE, // Sort by option type (from the ENUM_SYMBOL_OPTION_MODE enumeration) SORT_BY_SYMBOL_OPTION_RIGHT, // Sort by option right (Call/Put) (from the ENUM_SYMBOL_OPTION_RIGHT enumeration) //--- Sort by real properties SORT_BY_SYMBOL_BID = FIRST_SYM_DBL_PROP, // Sort by Bid SORT_BY_SYMBOL_BIDHIGH, // Sort by maximum Bid for a day SORT_BY_SYMBOL_BIDLOW, // Sort by minimum Bid for a day SORT_BY_SYMBOL_ASK, // Sort by Ask SORT_BY_SYMBOL_ASKHIGH, // Sort by maximum Ask for a day SORT_BY_SYMBOL_ASKLOW, // Sort by minimum Ask for a day SORT_BY_SYMBOL_LAST, // Sort by the last deal price SORT_BY_SYMBOL_LASTHIGH, // Sort by maximum Last for a day SORT_BY_SYMBOL_LASTLOW, // Sort by minimum Last for a day SORT_BY_SYMBOL_VOLUME_REAL, // Sort by Volume for a day SORT_BY_SYMBOL_VOLUMEHIGH_REAL, // Sort by maximum Volume for a day SORT_BY_SYMBOL_VOLUMELOW_REAL, // Sort by minimum Volume for a day SORT_BY_SYMBOL_OPTION_STRIKE, // Sort by an option execution price SORT_BY_SYMBOL_POINT, // Sort by a single point value SORT_BY_SYMBOL_TRADE_TICK_VALUE, // Sort by SYMBOL_TRADE_TICK_VALUE_PROFIT value SORT_BY_SYMBOL_TRADE_TICK_VALUE_PROFIT, // Sort by a calculated tick price for a profitable position SORT_BY_SYMBOL_TRADE_TICK_VALUE_LOSS, // Sort by a calculated tick price for a loss-making position SORT_BY_SYMBOL_TRADE_TICK_SIZE, // Sort by a minimum price change SORT_BY_SYMBOL_TRADE_CONTRACT_SIZE, // Sort by a trading contract size SORT_BY_SYMBOL_TRADE_ACCRUED_INTEREST, // Sort by accrued interest SORT_BY_SYMBOL_TRADE_FACE_VALUE, // Sort by face value SORT_BY_SYMBOL_TRADE_LIQUIDITY_RATE, // Sort by liquidity rate SORT_BY_SYMBOL_VOLUME_MIN, // Sort by a minimum volume for performing a deal SORT_BY_SYMBOL_VOLUME_MAX, // Sort by a maximum volume for performing a deal SORT_BY_SYMBOL_VOLUME_STEP, // Sort by a minimum volume change step for deal execution SORT_BY_SYMBOL_VOLUME_LIMIT, // Sort by a maximum allowed aggregate volume of an open position and pending orders in one direction SORT_BY_SYMBOL_SWAP_LONG, // Sort by a long swap value SORT_BY_SYMBOL_SWAP_SHORT, // Sort by a short swap value SORT_BY_SYMBOL_MARGIN_INITIAL, // Sort by an initial margin SORT_BY_SYMBOL_MARGIN_MAINTENANCE, // Sort by a maintenance margin for an instrument SORT_BY_SYMBOL_MARGIN_LONG_INITIAL, // Sort by initial margin requirement applicable to Long orders SORT_BY_SYMBOL_MARGIN_BUY_STOP_INITIAL, // Sort by initial margin requirement applicable to BuyStop orders SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_INITIAL, // Sort by initial margin requirement applicable to BuyLimit orders SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_INITIAL, // Sort by initial margin requirement applicable to BuyStopLimit orders SORT_BY_SYMBOL_MARGIN_LONG_MAINTENANCE, // Sort by maintenance margin requirement applicable to Long orders SORT_BY_SYMBOL_MARGIN_BUY_STOP_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyStop orders SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyLimit orders SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyStopLimit orders SORT_BY_SYMBOL_MARGIN_SHORT_INITIAL, // Sort by initial margin requirement applicable to Short orders SORT_BY_SYMBOL_MARGIN_SELL_STOP_INITIAL, // Sort by initial margin requirement applicable to SellStop orders SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_INITIAL, // Sort by initial margin requirement applicable to SellLimit orders SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_INITIAL, // Sort by initial margin requirement applicable to SellStopLimit orders SORT_BY_SYMBOL_MARGIN_SHORT_MAINTENANCE, // Sort by maintenance margin requirement applicable to Short orders SORT_BY_SYMBOL_MARGIN_SELL_STOP_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellStop orders SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellLimit orders SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellStopLimit orders SORT_BY_SYMBOL_SESSION_VOLUME, // Sort by summary volume of the current session deals SORT_BY_SYMBOL_SESSION_TURNOVER, // Sort by the summary turnover of the current session SORT_BY_SYMBOL_SESSION_INTEREST, // Sort by the summary open interest SORT_BY_SYMBOL_SESSION_BUY_ORDERS_VOLUME, // Sort by the current volume of Buy orders SORT_BY_SYMBOL_SESSION_SELL_ORDERS_VOLUME, // Sort by the current volume of Sell orders SORT_BY_SYMBOL_SESSION_OPEN, // Sort by a session Open price SORT_BY_SYMBOL_SESSION_CLOSE, // Sort by a session Close price SORT_BY_SYMBOL_SESSION_AW, // Sort by an average weighted price of the current session SORT_BY_SYMBOL_SESSION_PRICE_SETTLEMENT, // Sort by a settlement price of the current session SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MIN, // Sort by a minimum price of the current session SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MAX, // Sort by a maximum price of the current session SORT_BY_SYMBOL_MARGIN_HEDGED, // Sort by a contract size or a margin value per one lot of hedged positions //--- Sort by string properties SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP, // Sort by a symbol name SORT_BY_SYMBOL_BASIS, // Sort by an underlying asset of a derivative SORT_BY_SYMBOL_CURRENCY_BASE, // Sort by a base currency of a symbol SORT_BY_SYMBOL_CURRENCY_PROFIT, // Sort by a profit currency SORT_BY_SYMBOL_CURRENCY_MARGIN, // Sort by a margin currency SORT_BY_SYMBOL_BANK, // Sort by a feeder of the current quote SORT_BY_SYMBOL_DESCRIPTION, // Sort by a symbol string description SORT_BY_SYMBOL_FORMULA, // Sort by the formula used for custom symbol pricing SORT_BY_SYMBOL_ISIN, // Sort by the name of a symbol in the ISIN system SORT_BY_SYMBOL_PAGE, // Sort by an address of the web page containing symbol information SORT_BY_SYMBOL_PATH // Sort by a path in the symbol tree }; //+------------------------------------------------------------------+
鉴于我们正在编辑 Defines.mqh 文件,我们在添加所有必要内容的同时会解释为什么要这么做。
我们需要一个计时器来刷新集合中所有品种的数据。 注意,我们需要更刷新有品种的报价数据,这也许会令品种事件类中跟踪它们的数据发生变化(在下一篇文章中有更多论述)。 在计时器中,我们还需要检查“市场观察”窗口中的交易品种列表,以便响应其刷新,并及时更新集合列表。
我们需要更频繁地更新报价数据、品种的其余数据、及其在“市场观察”窗口中的列表。 这意味着我们的品种集合需要两个计时器 — 报价数据计时器,和执行其他品种列表操作的计时器。
我们来为这两个品种集合计时器添加必要的宏替换:
//--- Symbol collection timer 1 parameters #define COLLECTION_SYM_PAUSE1 (100) // Pause of the symbol collection timer 1 in milliseconds (for scanning market watch symbols) #define COLLECTION_SYM_COUNTER_STEP1 (16) // Increment of the symbol timer 1 counter #define COLLECTION_SYM_COUNTER_ID1 (3) // Symbol timer 1 counter ID //--- Symbol collection timer 2 parameters #define COLLECTION_SYM_PAUSE2 (300) // Pause of the symbol collection timer 2 in milliseconds (for events of the market watch symbol list) #define COLLECTION_SYM_COUNTER_STEP2 (16) // Increment of the symbol timer 2 counter #define COLLECTION_SYM_COUNTER_ID2 (4) // Symbol timer 2 counter ID
这些数据之间的差异仅在于每个计时器的暂停和它们的 ID — 第一个计时器的暂停时间为 100 毫秒,而第二个计时器的暂停时间为 300 毫秒。
我们为每个集合分配了单独的 ID。 品种集合也不例外。
我们为其列表设置一个自定义的 ID:
//--- Collection list IDs #define COLLECTION_HISTORY_ID (0x7778+1) // Historical collection list ID #define COLLECTION_MARKET_ID (0x7778+2) // Market collection list ID #define COLLECTION_EVENTS_ID (0x7778+3) // Event collection list ID #define COLLECTION_ACCOUNT_ID (0x7778+4) // Account collection list ID #define COLLECTION_SYMBOLS_ID (0x7778+5) // Symbol collection list ID
在上一篇文章里,为了定义用于“市场观察”窗口中高亮的交易品种的背景颜色,和显示其字符串描述的颜色,我们将颜色与 clrWhite 比较 — 如果属性值超过颜色的“长整数”值,则认定未设置背景色:
property==SYMBOL_PROP_BACKGROUND_COLOR ? TextByLanguage("Цвет фона символа в Market Watch","Background color of symbol in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : #ifdef __MQL5__ (this.GetProperty(property)>clrWhite ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true)) #else TextByLanguage(": Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) :
不过i,根据开发者的说法,这是不正确的 — “市场观察”窗口中品种背景的“长整数”值可能会超过“白色”的“长整数”值。 意即在某些情况下,此检查会返回错误的结果。
为了正确识别背景色的缺失,我们需要将属性值与 CLR_DEFAULT 和 CLR_NONE 值进行比较。
我们利用宏替换来设置“默认”颜色(MQL5 和 MQL4 中已经存在“缺失” CLR_NONE 颜色):
//--- Symbol parameters #define CLR_DEFAULT (0xFF000000) // Default color //+------------------------------------------------------------------+
结果就是,Defines 文件里宏替换的部分现在如下所示:
//+------------------------------------------------------------------+ //| Macro substitutions | //+------------------------------------------------------------------+ //--- Describe the function with the error line number #define DFUN_ERR_LINE (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(string)__LINE__+": ") #define DFUN (__FUNCTION__+": ") // "Function description" #define COUNTRY_LANG ("Russian") // Country language #define END_TIME (D'31.12.3000 23:59:59') // End date for account history data requests #define TIMER_FREQUENCY (16) // Minimal frequency of the library timer in milliseconds //--- Parameters of the orders and deals collection timer #define COLLECTION_ORD_PAUSE (250) // Orders and deals collection timer pause in milliseconds #define COLLECTION_ORD_COUNTER_STEP (16) // Increment of the orders and deals collection timer counter #define COLLECTION_ORD_COUNTER_ID (1) // Orders and deals collection timer counter ID //--- Parameters of the account collection timer #define COLLECTION_ACC_PAUSE (1000) // Account collection timer pause in milliseconds #define COLLECTION_ACC_COUNTER_STEP (16) // Account timer counter increment #define COLLECTION_ACC_COUNTER_ID (2) // Account timer counter ID //--- Symbol collection timer 1 parameters #define COLLECTION_SYM_PAUSE1 (100) // Pause of the symbol collection timer 1 in milliseconds (for scanning market watch symbols) #define COLLECTION_SYM_COUNTER_STEP1 (16) // Increment of the symbol timer 1 counter #define COLLECTION_SYM_COUNTER_ID1 (3) // Symbol timer 1 counter ID //--- Symbol collection timer 2 parameters #define COLLECTION_SYM_PAUSE2 (300) // Pause of the symbol collection timer 2 in milliseconds (for events of the market watch symbol list) #define COLLECTION_SYM_COUNTER_STEP2 (16) // Increment of the symbol timer 2 counter #define COLLECTION_SYM_COUNTER_ID2 (4) // Symbol timer 2 counter ID //--- Collection list IDs #define COLLECTION_HISTORY_ID (0x7778+1) // Historical collection list ID #define COLLECTION_MARKET_ID (0x7778+2) // Market collection list ID #define COLLECTION_EVENTS_ID (0x7778+3) // Event collection list ID #define COLLECTION_ACCOUNT_ID (0x7778+4) // Account collection list ID #define COLLECTION_SYMBOLS_ID (0x7778+5) // Symbol collection list ID //--- Data parameters for file operations #define DIRECTORY ("DoEasy\\") // Library directory for storing object folders //--- Symbol parameters #define CLR_DEFAULT (0xFF000000) // Default color //+------------------------------------------------------------------+
我已经提到过操控品种集合的模式:当前品种、程序中预定义的品种列表、“市场观察”窗口、以及服务器上可用品种的完整列表 。
我们在枚举中设置所有这些模式:
//+------------------------------------------------------------------+ //| Data for working with symbols | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+
在上一篇文章中,我们辨别了用于进行品种排序的品种类别。 在本文的最开头,我们实验了一种稍微扩充的品种类别列表,我们将会用到它。
我们添加品种类别(状态)的枚举:
//+------------------------------------------------------------------+ //| Abstract symbol type (status) | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_STATUS { SYMBOL_STATUS_FX, // Forex symbol SYMBOL_STATUS_FX_MAJOR, // Major Forex symbol SYMBOL_STATUS_FX_MINOR, // Minor Forex symbol SYMBOL_STATUS_FX_EXOTIC, // Exotic Forex symbol SYMBOL_STATUS_FX_RUB, // Forex symbol/RUB SYMBOL_STATUS_METAL, // Metal SYMBOL_STATUS_INDEX, // Index SYMBOL_STATUS_INDICATIVE, // Indicative SYMBOL_STATUS_CRYPTO, // Cryptocurrency symbol SYMBOL_STATUS_COMMODITY, // Commodity symbol SYMBOL_STATUS_EXCHANGE, // Exchange symbol SYMBOL_STATUS_FUTURES, // Futures SYMBOL_STATUS_CFD, // CFD SYMBOL_STATUS_STOCKS, // Security SYMBOL_STATUS_BONDS, // Bond SYMBOL_STATUS_OPTION, // Option SYMBOL_STATUS_COLLATERAL, // Non-tradable asset SYMBOL_STATUS_CUSTOM, // Custom symbol SYMBOL_STATUS_COMMON // General category }; //+------------------------------------------------------------------+
我们已为品种集合准备好了数据,并在 Defines.mqh 文件中进行了所有修改。
所做的修改还影响到我们在上一篇文章中创建的 CSymbol 类。
鉴于我们现在利用 SymbolInfoMarginRate() 函数接收有关各种订单类型的保证金比率数据,而通过链接传递给该函数的变量则用于从其返回数值,我们现在需要创建这些变量。
假设我们有八笔定单,且它们当中的每一笔有两个比率类型(初始保证金比率和维持保证金比率),则应有 16 个变量用于接收这些数值。 所以,创建由两个嵌套结构组成的结构会更加便利:在第一个结构中,定义了两个双精度变量以便存储初始保证金和维持保证金的比率,而 第二个包含第一个声明的结构,用于存储按订单类型所获比率的数据。
我们在 Symbol.mqh 品种类文件的 CSymbol 类私有部分中声明这些结构,以及含有第二种结构类型的类成员变量:
//+------------------------------------------------------------------+ //| Abstract symbol class | //+------------------------------------------------------------------+ class CSymbol : public CObject { private: struct SMarginRate { double Initial; // initial margin rate double Maintenance; // maintenance margin rate }; struct SMarginRateMode { SMarginRate Long; // MarginRate of long positions SMarginRate Short; // MarginRate of short positions SMarginRate BuyStop; // MarginRate of BuyStop orders SMarginRate BuyLimit; // MarginRate of BuyLimit orders SMarginRate BuyStopLimit; // MarginRate of BuyStopLimit orders SMarginRate SellStop; // MarginRate of SellStop orders SMarginRate SellLimit; // MarginRate of SellLimit orders SMarginRate SellStopLimit; // MarginRate of SellStopLimit orders }; SMarginRateMode m_margin_rate; // Margin ratio structure
我们在类的私有部分补充为所有品种属性填写比率的方法,所有存储品种比率的结构变量的初始化方法。 还有,我们要添加两个辅助方法来接收当前星期值,和“双精度”数值中的小数位数:
SMarginRateMode m_margin_rate; // Margin ratio structure MqlTick m_tick; // Symbol tick structure MqlBookInfo m_book_info_array[]; // Array of the market depth data structures string m_symbol_name; // Symbol name long m_long_prop[SYMBOL_PROP_INTEGER_TOTAL]; // Integer properties double m_double_prop[SYMBOL_PROP_DOUBLE_TOTAL]; // Real properties string m_string_prop[SYMBOL_PROP_STRING_TOTAL]; // String properties int m_digits_currency; // Number of decimal places in an account currency int m_global_error; // Global error code //--- Return the index of the array the symbol's (1) double and (2) string properties are located at int IndexProp(ENUM_SYMBOL_PROP_DOUBLE property) const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_SYMBOL_PROP_STRING property) const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_DOUBLE_TOTAL; } //--- (1) Fill in all the "margin ratio" symbol properties, (2) initialize the ratios bool MarginRates(void); void InitMarginRates(void); //--- Reset all symbol object data void Reset(void); //--- Return the current day of the week ENUM_DAY_OF_WEEK CurrentDayOfWeek(void) const; //--- Returns the number of decimal places in the 'double' value int GetDigits(const double value) const; public:
在类的同一私有部分当中,声明返回每种定单类型保证金比率数据的方法:
//--- Get and return real properties of a selected symbol from its parameters double SymbolBidHigh(void) const; double SymbolBidLow(void) const; double SymbolVolumeReal(void) const; double SymbolVolumeHighReal(void) const; double SymbolVolumeLowReal(void) const; double SymbolOptionStrike(void) const; double SymbolTradeAccruedInterest(void) const; double SymbolTradeFaceValue(void) const; double SymbolTradeLiquidityRate(void) const; double SymbolMarginHedged(void) const; bool SymbolMarginLong(void); bool SymbolMarginShort(void); bool SymbolMarginBuyStop(void); bool SymbolMarginBuyLimit(void); bool SymbolMarginBuyStopLimit(void); bool SymbolMarginSellStop(void); bool SymbolMarginSellLimit(void); bool SymbolMarginSellStopLimit(void); //--- Get and return string properties of a selected symbol from its parameters
有时,程序需要知道服务器上是否存在某个品种。 这可以按品种名称搜索来完成。 我们已有 Exist() 方法,可按类品种返回此类数据。 重载该方法,令其可以按所传递的品名返回数据。 为此,在类的私有部分中声明另一个方法调用:
//--- Search for a symbol and return the flag indicating its presence on the server bool Exist(void) const; bool Exist(const string name) const;
并且,在类的受保护部分中声明重载方法。 该方法依据 MQL5 或 MQL4 程序类型,按其名称返回品种数值:
protected: //--- Protected parametric constructor CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name); //--- Get and return integer properties of a selected symbol from its parameters bool SymbolExists(const string name) const; long SymbolExists(void) const;
在类的公开部分的描述属性方法的部分中,声明用于显示品种简介的虚方法。
我们在衍生类中实现此虚方法,在衍生类中厘清品种对象的数据设置。
//+------------------------------------------------------------------+ //| Description of symbol object properties | //+------------------------------------------------------------------+ //--- Get description of a symbol (1) integer, (2) real and (3) string properties string GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property); string GetPropertyDescription(ENUM_SYMBOL_PROP_DOUBLE property); string GetPropertyDescription(ENUM_SYMBOL_PROP_STRING property); //--- Send description of symbol properties to the journal (full_prop=true - all properties, false - only supported ones) void Print(const bool full_prop=false); //--- Display a short symbol description in the journal (implementation in the descendants) virtual void PrintShort(void) {;} //--- Compare CSymbol objects by all possible properties (for sorting lists by a specified symbol object property)
在上一篇文章中,我们在实现品种对象时添加了一些服务方法。
我们再来添加一些其他方法,用于返回报价和交易时段的开始和结束时间,以及用于返回时段整点小时、分钟和秒数的私有方法,和返回 “HH:MM:SS” 格式的时段说明方法:
//--- (1) Add, (2) remove a symbol from the Market Watch window, (3) return the data synchronization flag by a symbol bool SetToMarketWatch(void) const { return ::SymbolSelect(this.m_symbol_name,true); } bool RemoveFromMarketWatch(void) const { return ::SymbolSelect(this.m_symbol_name,false); } bool IsSynchronized(void) const { return ::SymbolIsSynchronized(this.m_symbol_name); } //--- Return the (1) start and (2) end time of the week day's quote session, (3) the start and end time of the required quote session long SessionQuoteTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; long SessionQuoteTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; bool GetSessionQuote(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to); //--- Return the (1) start and (2) end time of the week day's trading session, (3) the start and end time of the required trading session long SessionTradeTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; long SessionTradeTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; bool GetSessionTrade(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to); //--- (1) Arrange a (1) subscription to the market depth, (2) close the market depth, (3) fill in the market depth data to the structure array bool BookAdd(void) const; bool BookClose(void) const; //--- Return (1) a session duration description in the hh:mm:ss format, number of (1) hours, (2) minutes and (3) seconds in the session duration time string SessionDurationDescription(const ulong duration_sec) const; private: int SessionHours(const ulong duration_sec) const; int SessionMinutes(const ulong duration_sec) const; int SessionSeconds(const ulong duration_sec) const; public: //+------------------------------------------------------------------+
在公开部分中,用于简化访问品种对象属性的方法分区,添加了第二种形式的调用方法,该方法返回服务器上的品种存在标志( 之前,我们声明了私有重载方法,按其名称在服务器上查找品种,并返回搜索结果的标志)
//+------------------------------------------------------------------+ //| Methods of a simplified access to the order object properties | //+------------------------------------------------------------------+ //--- Integer properties long Status(void) const { return this.GetProperty(SYMBOL_PROP_STATUS); } bool IsCustom(void) const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM); } color ColorBackground(void) const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR); } ENUM_SYMBOL_CHART_MODE ChartMode(void) const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE); } bool IsExist(void) const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST); } bool IsExist(const string name) const { return this.SymbolExists(name); } bool IsSelect(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT); } bool IsVisible(void) const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE); } long SessionDeals(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS); }
在公开部分中,用于简化访问品种实数型属性的方法分区,添加了返回所有保证金比率的方法:
//--- Real properties double Bid(void) const { return this.GetProperty(SYMBOL_PROP_BID); } double BidHigh(void) const { return this.GetProperty(SYMBOL_PROP_BIDHIGH); } double BidLow(void) const { return this.GetProperty(SYMBOL_PROP_BIDLOW); } double Ask(void) const { return this.GetProperty(SYMBOL_PROP_ASK); } double AskHigh(void) const { return this.GetProperty(SYMBOL_PROP_ASKHIGH); } double AskLow(void) const { return this.GetProperty(SYMBOL_PROP_ASKLOW); } double Last(void) const { return this.GetProperty(SYMBOL_PROP_LAST); } double LastHigh(void) const { return this.GetProperty(SYMBOL_PROP_LASTHIGH); } double LastLow(void) const { return this.GetProperty(SYMBOL_PROP_LASTLOW); } double VolumeReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL); } double VolumeHighReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL); } double VolumeLowReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL); } double OptionStrike(void) const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE); } double Point(void) const { return this.GetProperty(SYMBOL_PROP_POINT); } double TradeTickValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE); } double TradeTickValueProfit(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT); } double TradeTickValueLoss(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS); } double TradeTickSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE); } double TradeContractSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE); } double TradeAccuredInterest(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST); } double TradeFaceValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE); } double TradeLiquidityRate(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE); } double LotsMin(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN); } double LotsMax(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX); } double LotsStep(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP); } double VolumeLimit(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT); } double SwapLong(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG); } double SwapShort(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT); } double MarginInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL); } double MarginMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE); } double MarginLongInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL); } double MarginBuyStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL); } double MarginBuyLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL); } double MarginBuyStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL); } double MarginLongMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE); } double MarginBuyStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE); } double MarginBuyLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE); } double MarginBuyStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE); } double MarginShortInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL); } double MarginSellStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL); } double MarginSellLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL); } double MarginSellStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL); } double MarginShortMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE); } double MarginSellStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE); } double MarginSellLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE); } double MarginSellStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE); } double SessionVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME); } double SessionTurnover(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER); } double SessionInterest(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST); } double SessionBuyOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME); } double SessionSellOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME); } double SessionOpen(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN); } double SessionClose(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE); } double SessionAW(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_AW); } double SessionPriceSettlement(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT); } double SessionPriceLimitMin(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN); } double SessionPriceLimitMax(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX); } double MarginHedged(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED); } double NormalizedPrice(const double price) const; //--- String properties
若要获取有关交易品种属性的数据,请确保在“市场观察”窗口中选择了该交易品种。 在某些情况下,可能在窗口中未选择该品种但仍需要其属性的情况。 针对这种情况,我们需要创建标志来指示是否在市场观察窗口中选择该交易品种,然后才能访问其属性。 接着,进行如下操作:如果未选择该交易品种,则选择,获取其属性,并在“市场观察”窗口中隐藏该品种。 如果该品种已被选择,则只需获取其属性。
另外,针对 MQL5,我们需要初始化保证金比率数据,并在类构造函数中为其填写数值。 MQL4 没有此类数据,并且其数值在初始化后保持为零。
另外,添加调用将这些属性保存在类属性字段中的方法。
为达此目的,请在类构造函数中添加必要的代码:
//+------------------------------------------------------------------+ //| Closed parametric constructor | //+------------------------------------------------------------------+ CSymbol::CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name) : m_global_error(ERR_SUCCESS) { this.m_symbol_name=name; if(!this.Exist()) { ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\"",": ",TextByLanguage("Ошибка. Такого символа нет на сервере","Error. There is no such symbol on the server")); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; } bool select=::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT); ::ResetLastError(); if(!select) { if(!this.SetToMarketWatch()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\": ",TextByLanguage("Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in the market watch. Error: "),this.m_global_error); } } ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error); } //--- Initialize data ::ZeroMemory(this.m_tick); this.Reset(); this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif); this.InitMarginRates(); ::ResetLastError(); #ifdef __MQL5__ if(!this.MarginRates()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "),this.m_global_error); return; } #endif //--- Save integer properties this.m_long_prop[SYMBOL_PROP_STATUS] = symbol_status; this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_DIGITS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_DIGITS); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_SPREAD_FLOAT] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD_FLOAT); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_TRADE_MODE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_MODE); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_EXEMODE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_EXEMODE); this.m_long_prop[SYMBOL_PROP_SWAP_ROLLOVER3DAYS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SWAP_ROLLOVER3DAYS); this.m_long_prop[SYMBOL_PROP_EXIST] = this.SymbolExists(); this.m_long_prop[SYMBOL_PROP_CUSTOM] = this.SymbolCustom(); this.m_long_prop[SYMBOL_PROP_MARGIN_HEDGED_USE_LEG] = this.SymbolMarginHedgedUseLEG(); this.m_long_prop[SYMBOL_PROP_ORDER_MODE] = this.SymbolOrderMode(); this.m_long_prop[SYMBOL_PROP_FILLING_MODE] = this.SymbolOrderFillingMode(); this.m_long_prop[SYMBOL_PROP_EXPIRATION_MODE] = this.SymbolExpirationMode(); this.m_long_prop[SYMBOL_PROP_ORDER_GTC_MODE] = this.SymbolOrderGTCMode(); this.m_long_prop[SYMBOL_PROP_OPTION_MODE] = this.SymbolOptionMode(); this.m_long_prop[SYMBOL_PROP_OPTION_RIGHT] = this.SymbolOptionRight(); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); this.m_long_prop[SYMBOL_PROP_CHART_MODE] = this.SymbolChartMode(); this.m_long_prop[SYMBOL_PROP_TRADE_CALC_MODE] = this.SymbolCalcMode(); this.m_long_prop[SYMBOL_PROP_SWAP_MODE] = this.SymbolSwapMode(); //--- Save real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_POINT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_POINT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; //--- Save string properties this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)] = this.m_symbol_name; this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_BASE); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_PROFIT); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_MARGIN); this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_DESCRIPTION); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)] = ::SymbolInfoString(this.m_symbol_name,SYMBOL_PATH); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)] = this.SymbolBasis(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)] = this.SymbolBank(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)] = this.SymbolISIN(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)] = this.SymbolFormula(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)] = this.SymbolPage(); //--- Save additional integer properties this.m_long_prop[SYMBOL_PROP_DIGITS_LOTS] = this.SymbolDigitsLot(); //--- if(!select) this.RemoveFromMarketWatch(); } //+------------------------------------------------------------------+
现在我们需要编写所有已声明方法的实现。
填写所有存储保证金比率变量的方法实现位于类的实体之外:
//+------------------------------------------------------------------+ //| Fill in the margin ratio variables | //+------------------------------------------------------------------+ bool CSymbol::MarginRates(void) { bool res=true; #ifdef __MQL5__ res &=this.SymbolMarginLong(); res &=this.SymbolMarginBuyStop(); res &=this.SymbolMarginBuyLimit(); res &=this.SymbolMarginBuyStopLimit(); res &=this.SymbolMarginShort(); res &=this.SymbolMarginSellStop(); res &=this.SymbolMarginSellLimit(); res &=this.SymbolMarginSellStopLimit(); #else this.InitMarginRates(); res=false; #endif return res; } //+------------------------------------------------------------------+
MQL5 方法仅调用方法从品种属性里读取比率数据,并将其写入相应的结构变量。 累积所有方法返回的结果,并返回给调用程序。 该方法将在下面讨论。 对于 MQL4,所有结构字段都简单地置零。
初始化属性结构里保证金比率字段的方法:
//+------------------------------------------------------------------+ //| Initialize margin ratios | //+------------------------------------------------------------------+ void CSymbol::InitMarginRates(void) { this.m_margin_rate.Long.Initial=0; this.m_margin_rate.Long.Maintenance=0; this.m_margin_rate.BuyStop.Initial=0; this.m_margin_rate.BuyStop.Maintenance=0; this.m_margin_rate.BuyLimit.Initial=0; this.m_margin_rate.BuyLimit.Maintenance=0; this.m_margin_rate.BuyStopLimit.Initial=0; this.m_margin_rate.BuyStopLimit.Maintenance=0; this.m_margin_rate.Short.Initial=0; this.m_margin_rate.Short.Maintenance=0; this.m_margin_rate.SellStop.Initial=0; this.m_margin_rate.SellStop.Maintenance=0; this.m_margin_rate.SellLimit.Initial=0; this.m_margin_rate.SellLimit.Maintenance=0; this.m_margin_rate.SellStopLimit.Initial=0; this.m_margin_rate.SellStopLimit.Maintenance=0; } //+------------------------------------------------------------------+
m_margin_rate 结构的所有字段仅在此处重置。
实现调用方法的第二种形式,该方法返回服务器上品种存在的标志:
//+------------------------------------------------------------------+ //| Return the symbol existence flag | //+------------------------------------------------------------------+ long CSymbol::SymbolExists(void) const { return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXIST) #else this.Exist() #endif); } //+------------------------------------------------------------------+ bool CSymbol::SymbolExists(const string name) const { return(#ifdef __MQL5__ (bool)::SymbolInfoInteger(name,SYMBOL_EXIST) #else this.Exist(name) #endif); } //+------------------------------------------------------------------+
在此,对于 MQL5,返回 SYMBOL_EXIST 品种属性,而对于 MQL4,使用第二种 Exist(const string name) 方法的调用形式,在服务器上搜索一个品种。
填充结构中所有订单类型的保证金比率的方法实现:
//+------------------------------------------------------------------+ //| Fill in the margin ratios for long positions | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginLong(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY,this.m_margin_rate.Long.Initial,this.m_margin_rate.Long.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Fill in the margin ratios for short positions | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginShort(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL,this.m_margin_rate.Short.Initial,this.m_margin_rate.Short.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Fill in the margin ratios for BuyStop orders | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyStop(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_STOP,this.m_margin_rate.BuyStop.Initial,this.m_margin_rate.BuyStop.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Fill in the margin ratios for BuyLimit orders | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_LIMIT,this.m_margin_rate.BuyLimit.Initial,this.m_margin_rate.BuyLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Fill in the margin ratios for BuyStopLimit orders | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyStopLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_STOP_LIMIT,this.m_margin_rate.BuyStopLimit.Initial,this.m_margin_rate.BuyStopLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Fill in the margin ratios for SellStop orders | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellStop(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_STOP,this.m_margin_rate.SellStop.Initial,this.m_margin_rate.SellStop.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Fill in the margin ratios for SellLimit orders | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_LIMIT,this.m_margin_rate.SellLimit.Initial,this.m_margin_rate.SellLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Fill in the margin ratios for SellStopLimit orders | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellStopLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_STOP_LIMIT,this.m_margin_rate.SellStopLimit.Initial,this.m_margin_rate.SellStopLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+
此处,对于 MQL5,调用 SymbolInfoMarginRate() 函数,在其中会填充 m_margin_rate 结构中的必需属性,且该函数返回操作结果。 对于 MQL4,返回 false。
在返回“市场观察”窗口中返回品种背景描述的模块中,修改返回品种属性说明的方法:
property==SYMBOL_PROP_BACKGROUND_COLOR ? TextByLanguage("Цвет фона символа в Market Watch","Background color of symbol in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : #ifdef __MQL5__ (this.GetProperty(property)==CLR_DEFAULT || this.GetProperty(property)==CLR_NONE ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true)) #else TextByLanguage(": Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) :
以前,我们将颜色与白色(clrWhite)进行了比较,如果颜色值超过“白色”值,则认为未设置颜色。 我们已讨论了这种比较方法的缺点。 所以,将颜色与“默认值” 进行比较,或将其与“缺失颜色”进行比较,以便定义“市场观察”窗口中某交易品种是否指定了背景颜色。
将显示所有保证金比率说明的代码添加到返回品种 GetPropertyDescription(ENUM_SYMBOL_PROP_DOUBLE property) 实数型属性的方法中:
//--- Initial margin requirement of a Long position property==SYMBOL_PROP_MARGIN_LONG_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по длинным позициям","Coefficient of margin initial charging for long positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //--- Initial margin requirement of a Short position property==SYMBOL_PROP_MARGIN_SHORT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по коротким позициям","Coefficient of margin initial charging for short positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //--- Maintenance margin requirement of a Long position property==SYMBOL_PROP_MARGIN_LONG_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по длинным позициям","Coefficient of margin maintenance charging for long positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //--- Maintenance margin requirement of a Short position property==SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по коротким позициям","Coefficient of margin maintenance charging for short positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //--- Initial margin requirements of Long orders property==SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по BuyStop ордерам","Coefficient of margin initial charging for BuyStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по BuyLimit ордерам","Coefficient of margin initial charging for BuyLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по BuyStopLimit ордерам","Coefficient of margin initial charging for BuyStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //--- Initial margin requirements of Short orders property==SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по SellStop ордерам","Coefficient of margin initial charging for SellStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по SellLimit ордерам","Coefficient of margin initial charging for SellLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по SellStopLimit ордерам","Coefficient of margin initial charging for SellStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //--- Maintenance margin requirements of Long orders property==SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по BuyStop ордерам","Coefficient of margin maintenance charging for BuyStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по BuyLimit ордерам","Coefficient of margin maintenance charging for BuyLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по BuyStopLimit ордерам","Coefficient of margin maintenance charging for BuyStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //--- Maintenance margin requirements of Short orders property==SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по SellStop ордерам","Coefficient of margin maintenance charging for SellStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по SellLimit ордерам","Coefficient of margin maintenance charging for SellLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по SellStopLimit ордерам","Coefficient of margin maintenance charging for SellStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : //---
实现第二种形式,调用方法在服务器上按名称搜索品种,并返回品种存在标记:
//+-------------------------------------------------------------------------------+ //| Search for a symbol and return the flag indicating its presence on the server | //+-------------------------------------------------------------------------------+ bool CSymbol::Exist(void) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==this.m_symbol_name) return true; return false; } //+------------------------------------------------------------------+ bool CSymbol::Exist(const string name) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==name) return true; return false; } //+------------------------------------------------------------------+
实现计算并返回小数位“双精度”数值的方法:
//+------------------------------------------------------------------+ //| Return the number of decimal places in the 'double' value | //+------------------------------------------------------------------+ int CSymbol::GetDigits(const double value) const { string val_str=(string)value; int len=::StringLen(val_str); int n=len-::StringFind(val_str,".",0)-1; if(::StringSubstr(val_str,len-1,1)=="0") n--; return n; } //+------------------------------------------------------------------+
我们已在上一篇文章中讨论了该方法。 在此可以用一种单独的方法来简单实现,这是出于需要对若干数值进行重复计算 — 最小手数和手数步长。
从一天的开始返回报价时段的开始和结束时间,以及报价时段的开始和结束时间的方法实现:
//+------------------------------------------------------------------+ //| Return the quote session start time | //| in seconds from the beginning of a day | //+------------------------------------------------------------------+ long CSymbol::SessionQuoteTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to) ? from : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return the time in seconds since the day start | //| up to the end of a quote session | //+------------------------------------------------------------------+ long CSymbol::SessionQuoteTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to) ? to : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return the start and end time of a required quote session | //+------------------------------------------------------------------+ bool CSymbol::GetSessionQuote(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to) { ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return ::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to); } //+------------------------------------------------------------------+
时段索引和星期值被传递给前两个方法,而第三个方法要另外接收 'datetime' 类型变量,该变量将存储利用 SymbolInfoSessionQuote() 函数接收的指定时段的开始和结束数据。
为了更加便利,如果选择 -1 作为星期值,则时段数据取自当日。 时段索引应从零开始。 按 day_of_week 参数定义的时间,返回自该日开始至今的秒数。 所以,您可将累加该方法返回的距指定日开始的秒数,计算出实际的请求时间。
接收交易时段的方法以相同的方式实现:
//+------------------------------------------------------------------+ //| Return the trading session start time | //| in seconds from the beginning of a day | //+------------------------------------------------------------------+ long CSymbol::SessionTradeTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to) ? from : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return the time in seconds since the day start | //| up to the end of a trading session | //+------------------------------------------------------------------+ long CSymbol::SessionTradeTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to) ? to : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return the start and end time of a required trading session | //+------------------------------------------------------------------+ bool CSymbol::GetSessionTrade(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to) { ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return ::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to); } //+------------------------------------------------------------------+
这些方法与上述方法类似,不同之处在于,此处利用 SymbolInfoSessionTrade() 函数来接收所需的数据。
按当前星期值返回 ENUM_DAY_OF_WEEK 枚举值的方法实现:
//+------------------------------------------------------------------+ //| Return the current day of the week | //+------------------------------------------------------------------+ ENUM_DAY_OF_WEEK CSymbol::CurrentDayOfWeek(void) const { MqlDateTime time={0}; ::TimeCurrent(time); return(ENUM_DAY_OF_WEEK)time.day_of_week; } //+------------------------------------------------------------------+
这一切都很简单:声明日期和时间结构,访问 TimeCurrent() 函数,该函数的第二个调用形式填充传递给该函数的日期和时间结构,最后返回 已填充结构中的星期值。
返回指定时段持续时间秒数的方法实现:
//+------------------------------------------------------------------+ //| Return the number of seconds in a session duration time | //+------------------------------------------------------------------+ int CSymbol::SessionSeconds(const ulong duration_sec) const { return int(duration_sec % 60); } //+------------------------------------------------------------------+
该方法接收秒数,除以该时间跨度的分钟数,并返回余数。
返回指定时段的持续时间分钟数的方法实现:
//+------------------------------------------------------------------+ //| Return the number of minutes in a session duration time | //+------------------------------------------------------------------+ int CSymbol::SessionMinutes(const ulong duration_sec) const { return int((duration_sec-this.SessionSeconds(duration_sec)) % 3600)/60; } //+------------------------------------------------------------------+
该方法接收秒数,并返回计算出的时间跨度分钟数,排除不足一分钟的秒数。
返回指定时段持续时间小时数的方法实现:
//+------------------------------------------------------------------+ //| Return the number of hours in a session duration time | //+------------------------------------------------------------------+ int CSymbol::SessionHours(const ulong duration_sec) const { return int(duration_sec-this.SessionSeconds(duration_sec)-this.SessionMinutes(duration_sec))/3600; } //+------------------------------------------------------------------+
该方法接收秒数,并返回计算出的时间跨度小时数,排除不足一分钟的秒数,和不足一小时的分钟数。
以 “ HH:MM:SS” 格式返回时段持续时间描述的方法实现:
//+---------------------------------------------------------------------+ //| Return the description of a session duration in the hh:mm:ss format | //+---------------------------------------------------------------------+ string CSymbol::SessionDurationDescription(const ulong duration_sec) const { int sec=this.SessionSeconds(duration_sec); int min=this.SessionMinutes(duration_sec); int hour=this.SessionHours(duration_sec); return ::IntegerToString(hour,2,'0')+":"+::IntegerToString(min,2,'0')+":"+::IntegerToString(sec,2,'0'); } //+------------------------------------------------------------------+
在此,我们只需以秒为单位获取时段持续时间,以及计算出的时段持续时间秒数,分钟数和小时数,然后利用 IntegerToString() 函数 以“小时:分钟:秒钟”的格式显示格式化的消息,时、分、秒的字符串宽度均等于两位,若时、分、秒中只有一位数字,不足两位数字,则以“ 0” 填充。
例如,如果我们得到小时为 2,则显示为 02。
由于我们稍微修改了品种对象的状态,因此需要修改显示品种对象状态说明的方法:
//+------------------------------------------------------------------+ //| Return the status description | //+------------------------------------------------------------------+ string CSymbol::GetStatusDescription() const { return ( this.Status()==SYMBOL_STATUS_FX ? TextByLanguage("Форекс символ","Forex symbol") : this.Status()==SYMBOL_STATUS_FX_MAJOR ? TextByLanguage("Форекс символ-мажор","Forex major symbol") : this.Status()==SYMBOL_STATUS_FX_MINOR ? TextByLanguage("Форекс символ-минор","Forex minor symbol") : this.Status()==SYMBOL_STATUS_FX_EXOTIC ? TextByLanguage("Форекс символ-экзотик","Forex Exotic Symbol") : this.Status()==SYMBOL_STATUS_FX_RUB ? TextByLanguage("Форекс символ/рубль","Forex symbol RUB") : this.Status()==SYMBOL_STATUS_METAL ? TextByLanguage("Металл","Metal") : this.Status()==SYMBOL_STATUS_INDEX ? TextByLanguage("Индекс","Index") : this.Status()==SYMBOL_STATUS_INDICATIVE ? TextByLanguage("Индикатив","Indicative") : this.Status()==SYMBOL_STATUS_CRYPTO ? TextByLanguage("Криптовалютный символ","Crypto symbol") : this.Status()==SYMBOL_STATUS_COMMODITY ? TextByLanguage("Товарный символ","Commodity symbol") : this.Status()==SYMBOL_STATUS_EXCHANGE ? TextByLanguage("Биржевой символ","Exchange symbol") : this.Status()==SYMBOL_STATUS_FUTURES ? TextByLanguage("Фьючерс","Futures") : this.Status()==SYMBOL_STATUS_CFD ? TextByLanguage("Контракт на разницу","Contract For Difference") : this.Status()==SYMBOL_STATUS_STOCKS ? TextByLanguage("Ценная бумага","Stocks") : this.Status()==SYMBOL_STATUS_BONDS ? TextByLanguage("Облигация","Bonds") : this.Status()==SYMBOL_STATUS_OPTION ? TextByLanguage("Опцион","Option") : this.Status()==SYMBOL_STATUS_COLLATERAL ? TextByLanguage("Неторгуемый актив","Collateral") : this.Status()==SYMBOL_STATUS_CUSTOM ? TextByLanguage("Пользовательский символ","Custom symbol") : this.Status()==SYMBOL_STATUS_COMMON ? TextByLanguage("Символ общей группы","Common group symbol") : ::EnumToString((ENUM_SYMBOL_STATUS)this.Status()) ); } //+------------------------------------------------------------------+
在刷新所有品种数据的方法中,对于 MQL5,要给所有定单和持仓类型添加接收保证金比率。
对于 MQL4,由于在 MQL4 中未用到它们,所以在类构造函数中开始初始化之后,它们的值仍为零:
//+------------------------------------------------------------------+ //| Update all symbol data that can change | //+------------------------------------------------------------------+ void CSymbol::Refresh(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); return; } #ifdef __MQL5__ ::ResetLastError(); if(!this.MarginRates()) { this.m_global_error=::GetLastError(); return; } #endif //--- Update integer properties this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); //--- Update real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; } //+------------------------------------------------------------------+
此处针对 MQL5,我们调用 MarginRates() 方法接收保证金比率数据。 如果至少有一个比率没收,方法返回 false,只需将错误代码写入类中存储错误代码的变量里,然后退出该方法且无需消息。
由于该方法工作于计时器当中,因此日志中不会显示错误消息。 万一收到错误的数据,日志会迅速被有关同一错误的垃圾邮件充斥。 鉴于此错误代码始终可在 CEngine 类中得到,因此我们留至该类来负责接收和处理它。
在该方法的最后,将所有获得的比率数据写入相应的品种对象属性字段中。
出于相同的原因,从报价数据刷新方法中删除在日志中显示错误消息的代码:
//+------------------------------------------------------------------+ //| Update quote data by a symbol | //+------------------------------------------------------------------+ void CSymbol::RefreshRates(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error); return; } //--- Update integer properties this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); //--- Update real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); } //+------------------------------------------------------------------+
现在,该方法将如下所示:
//+------------------------------------------------------------------+ //| Update quote data by a symbol | //+------------------------------------------------------------------+ void CSymbol::RefreshRates(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); return; } //--- Update integer properties this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL); //--- Update real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); } //+------------------------------------------------------------------+
抽象 CSymbol 品种类的改进既已完毕。
我们已针对该类方法进行了足够分量的修改,但有些次要修改并未在此进行说明,因为这些基本上只是属性描述方法中的一些拼写和“语义”错误。 您可以在附件中找到它们。
现在,我们需要创建抽象品种基类的衍生对象,将它们按类别划分,然后将其放置到品种对象集合当中。
我们后撤一步看看上述品种类别。 此外,我们要为 CSymbol 基类的相应衍生类设置名称:
在 \MQL5\Include\DoEasy\Objects\Symbols\ 函数库文件夹中,使用名为 SymbolFX.mqh 的文件创建新的类 CSymbolFX。 CSymbol 抽象品种类将用作其基类。
声明类操作所需的所有方法:
//+------------------------------------------------------------------+ //| SymbolFX.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Symbol.mqh" //+------------------------------------------------------------------+ //| Forex symbol | //+------------------------------------------------------------------+ class CSymbolFX : public CSymbol { public: //--- Constructor CSymbolFX(const string name) : CSymbol(SYMBOL_STATUS_FX,name) {} //--- Supported integer properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Supported real properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Supported string properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Display a short symbol description in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+
类构造函数用于接收品种名称,而类构造函数的初始化列表用于发送 “外汇品种“类别(其状态)给其基类,随同创建时传递给 CSymbolFX 类构造函数的品种名称。
在基类中声明了对象可支持的整数型、实数型和字符串型属性的虚拟方法,而它们的实现则是在衍生类中执行。 虚拟的 PrintShort() 方法也在基类中声明,并在衍生类中实现,该方法在日志中显示品种数据的摘要。
几乎所有衍生类方法都是相似的,且可在基类中实现而无需衍生类。 不过,在这种情况下,我们舍弃了为每个品种组的变化制定方法的灵活性。 所以,我决定通过衍生类对类别进行划分,以便能够针对每个衍生类分别定制,这理应更加简单、快捷。
按品种对象返回支持整数型属性标志的方法实现:
//+------------------------------------------------------------------+ //| Return 'true' if a symbol supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_INTEGER property) { if(property==SYMBOL_PROP_EXIST #ifdef __MQL4__ || property==SYMBOL_PROP_CUSTOM || property==SYMBOL_PROP_SESSION_DEALS || property==SYMBOL_PROP_SESSION_BUY_ORDERS || property==SYMBOL_PROP_SESSION_SELL_ORDERS || property==SYMBOL_PROP_VOLUME || property==SYMBOL_PROP_VOLUMEHIGH || property==SYMBOL_PROP_VOLUMELOW || property==SYMBOL_PROP_TICKS_BOOKDEPTH || property==SYMBOL_PROP_OPTION_MODE || property==SYMBOL_PROP_OPTION_RIGHT || property==SYMBOL_PROP_BACKGROUND_COLOR #endif ) return false; return true; } //+------------------------------------------------------------------+
已验证整数型属性被传递到方法。 如果所传递属性是“品种存在”,则返回 false— 如果创建了一个品种,则该品种存在,且我们无需将该属性显示在日志中,也不用于搜索和排序。 所有其他检查仅针对 MQL4。 针对 MQL4,如果已知所传递的品种属性不支持,则返回 False。
如果检查属性时枚举属性中不存在所传递的属性,则不支持该属性。 返回 true。
按品种对象返回支持实数型属性标志的方法实现:
//+------------------------------------------------------------------+ //| Return 'true' if a symbol supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property) { if( #ifdef __MQL5__ (this.ChartMode()==SYMBOL_CHART_MODE_BID && ( property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW ) ) || (this.ChartMode()==SYMBOL_CHART_MODE_LAST && ( property==SYMBOL_PROP_BID || property==SYMBOL_PROP_BIDHIGH || property==SYMBOL_PROP_BIDLOW || property==SYMBOL_PROP_ASK || property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW ) ) //--- __MQL4__ #else property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW || property==SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT || property==SYMBOL_PROP_TRADE_TICK_VALUE_LOSS || property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW || property==SYMBOL_PROP_VOLUME_LIMIT || property==SYMBOL_PROP_MARGIN_LONG_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_LONG_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SHORT_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE || property==SYMBOL_PROP_SESSION_VOLUME || property==SYMBOL_PROP_SESSION_TURNOVER || property==SYMBOL_PROP_SESSION_INTEREST || property==SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME || property==SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME || property==SYMBOL_PROP_SESSION_OPEN || property==SYMBOL_PROP_SESSION_CLOSE || property==SYMBOL_PROP_SESSION_AW || property==SYMBOL_PROP_SESSION_PRICE_SETTLEMENT || property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN || property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX || property==SYMBOL_PROP_VOLUME_REAL || property==SYMBOL_PROP_VOLUMEHIGH_REAL || property==SYMBOL_PROP_VOLUMELOW_REAL || property==SYMBOL_PROP_OPTION_STRIKE || property==SYMBOL_PROP_TRADE_ACCRUED_INTEREST || property==SYMBOL_PROP_TRADE_FACE_VALUE || property==SYMBOL_PROP_TRADE_LIQUIDITY_RATE #endif ) return false; return true; } //+------------------------------------------------------------------+
这里的逻辑与前面的方法相同。 但首先,针对 MQL5 检查获得的属性。 如果它是最后成交价格属性(最后)之一,而图表基于出价(Bid),则在这种情况下所有这些属性均不支持且等于零。
如果图表基于最后价格(Last),则按出价(Bid)属性同样操作 — 所有出价(Bid)属性均不支持。
对于 MQL4,与上一个方法完全相同 — 将已知不支持的品种属性传递给该方法时,返回 false。
按品种对象返回支持字符串型属性标志的方法实现:
//+------------------------------------------------------------------+ //| Return 'true' if a symbol supports a passed | //| string property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_STRING property) { if( #ifdef __MQL5__ property==SYMBOL_PROP_FORMULA && !this.IsCustom() #else property==SYMBOL_PROP_BASIS || property==SYMBOL_PROP_BANK || property==SYMBOL_PROP_ISIN || property==SYMBOL_PROP_FORMULA || property==SYMBOL_PROP_PAGE #endif ) return false; return true; } //+------------------------------------------------------------------+
此处的一切都是相似的:对于 MQL5 — 如果所传递的属性是“用于自定义品种计算的公式”,而品种并非自定义 ,返回 false— 不支持该属性。 接下来,我们检查已知不支持的 MQL4 品种属性,如果传递了 MQL4 不支持的属性,则返回 false。
在日志里显示品种简要说明的方法:
//+------------------------------------------------------------------+ //| Display a short symbol description in the journal | //+------------------------------------------------------------------+ void CSymbolFX::PrintShort(void) { ::Print(this.GetStatusDescription()+" "+this.Name()); } //+------------------------------------------------------------------+
该方法仅在一行里显示品种状态文字描述和其名称。
其余的衍生类以相同的方式构造,且拥有相同的方法和相同的实现。
区别在于自定义品种类 — MQL4 中不存在此品种类型,因此所有检查仅针对 MQL5:
//+------------------------------------------------------------------+ //| SymbolCustom.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Symbol.mqh" //+------------------------------------------------------------------+ //| Custom symbol | //+------------------------------------------------------------------+ class CSymbolCustom : public CSymbol { public: //--- Constructor CSymbolCustom(const string name) : CSymbol(SYMBOL_STATUS_CUSTOM,name) {} //--- Supported integer properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Supported real properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Supported string properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Display a short symbol description in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Return 'true' if a symbol supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_INTEGER property) { if(property==SYMBOL_PROP_EXIST) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if a symbol supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property) { if( (this.ChartMode()==SYMBOL_CHART_MODE_BID && ( property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW ) ) || (this.ChartMode()==SYMBOL_CHART_MODE_LAST && ( property==SYMBOL_PROP_BID || property==SYMBOL_PROP_BIDHIGH || property==SYMBOL_PROP_BIDLOW || property==SYMBOL_PROP_ASK || property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW ) ) ) return false; return true; } //+------------------------------------------------------------------+ //| Return 'true' if a symbol supports a passed | //| string property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Display a short symbol description in the journal | //+------------------------------------------------------------------+ void CSymbolCustom::PrintShort(void) { ::Print(this.GetStatusDescription()+" "+this.Name()); } //+------------------------------------------------------------------+
CSymbol 衍生类的开发到此完毕。
其余衍生类的实现可在文章末尾和附件中找到。
鉴于我们需要针对品种集合进行搜索和排序,因此我们应该为此创建所有必要的功能。 打开 \MQL5\Include\DoEasy\Services\ 函数库文件夹中的 Select.mqh 文件,并在其内进行增减。
首先,包含抽象品种类:
//+------------------------------------------------------------------+ //| Select.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> #include "..\Objects\Orders\Order.mqh" #include "..\Objects\Events\Event.mqh" #include "..\Objects\Accounts\Account.mqh" #include "..\Objects\Symbols\Symbol.mqh" //+------------------------------------------------------------------+
在类的公开部分中声明所有用于搜索和排序的必要方法:
//+------------------------------------------------------------------+ //| Class for sorting objects meeting the criterion | //+------------------------------------------------------------------+ class CSelect { private: //--- Method for comparing two values template<typename T> static bool CompareValues(T value1,T value2,ENUM_COMPARER_TYPE mode); public: //+------------------------------------------------------------------+ //| Methods of working with orders | //+------------------------------------------------------------------+ //--- Return the list of orders with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the order index with the maximum value of the order's (1) integer, (2) real and (3) string properties static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //--- Return the order index with the minimum value of the order's (1) integer, (2) real and (3) string properties static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //+------------------------------------------------------------------+ //| Methods of working with events | //+------------------------------------------------------------------+ //--- Return the list of events with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the event index with the maximum value of the event's (1) integer, (2) real and (3) string properties static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //--- Return the event index with the minimum value of the event's (1) integer, (2) real and (3) string properties static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //+------------------------------------------------------------------+ //| Methods of working with accounts | //+------------------------------------------------------------------+ //--- Return the list of accounts with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the event index with the maximum value of the event's (1) integer, (2) real and (3) string properties static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //--- Return the event index with the minimum value of the event's (1) integer, (2) real and (3) string properties static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //+------------------------------------------------------------------+ //| Methods of working with symbols | //+------------------------------------------------------------------+ //--- Return the list of symbols with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the symbol index with the maximum value of the order's (1) integer, (2) real and (3) string properties static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //--- Return the symbol index with the minimum value of the order's (1) integer, (2) real and (3) string properties static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //--- }; //+------------------------------------------------------------------+
我们在类的实体之外编写其实现:
//+------------------------------------------------------------------+ //| Methods of working with symbol lists | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Return the list of symbols with one integer | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); int total=list_source.Total(); for(int i=0; i<total; i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; long obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the list of symbols with one real | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; double obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the list of symbols with one string | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; string obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the listed symbol index | //| with the maximum integer property value | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); long obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the listed symbol index | //| with the maximum real property value | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); double obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the listed symbol index | //| with the maximum string property value | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); string obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the listed symbol index | //| with the minimum integer property value | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_INTEGER property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); long obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the listed symbol index | //| with the minimum real property value | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_DOUBLE property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total== 0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); double obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the listed symbol index | //| with the minimum string property value | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_STRING property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); string obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+
每个集合类我们都有类似的方法。 在函数库论述的第三部分中创建 CSelect 类时,已研究过它们。 所以,我们勿需在此赘述。
现在创建品种集合类的一切准备就绪。
程序当中有四种模式可用于处理品种集合:
为了使特征集合类“知晓”所要操控的品种,我们将运用以下方案:
在程序设置中设定操控品种的操作方法。 这可能是四个已声明操作模式之一。
程序还应该遵循相同原理,用函数库函数填充字符串数组:
所有这些都是自动完成的。 用户仅需要选择操控品种集合的必要模式,并在设置中为预定义品种创建至少一个字符串数组,或单个字符串。
在 \MQL5\Include\DoEasy\Collections\ 函数库文件夹中,在 SymbolsCollection.mqh 文件中创建新的 CSymbolsCollection 类。
CObject 标准函数库对象类将作为其基类。
将所有必需的类文件包含到新创建的文件中:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Collection of historical orders and deals | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: public: //--- Constructor CSymbolsCollection(); }; //+------------------------------------------------------------------+
将已经成为函数库集合类标准的类成员值和方法添加进来:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Collection of historical orders and deals | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: CListObj m_list_all_symbols; // The list of all symbol objects public: //--- Return the full collection list 'as is' CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Constructor CSymbolsCollection(); }; //+------------------------------------------------------------------+
以前在创建集合时,我们已研究过所有这些变量和方法。 勿需于此再次讨论它们。
将操控品种集合类的其余变量和方法添加进来:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Collection of historical orders and deals | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: CListObj m_list_all_symbols; // The list of all symbol objects ENUM_SYMBOLS_MODE m_mode_list; // Mode of working with symbol lists int m_delta_symbol; // Difference in the number of symbols compared to the previous check int m_last_num_symbol; // Number of symbols in the Market Watch window during the previous check int m_global_error; // Global error code //--- Return the flag of a symbol object presence by its name in the list of all symbols bool IsPresentSymbolInList(const string symbol_name); //--- Create the symbol object and place it to the list bool CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name); //--- Return the type of a used symbol list (Market watch/Server) ENUM_SYMBOLS_MODE TypeSymbolsList(const string &symbol_used_array[]); //--- Define a symbol affiliation with a group by name and return it ENUM_SYMBOL_STATUS SymbolStatus(const string symbol_name) const; //--- Return a symbol affiliation with a category by custom criteria ENUM_SYMBOL_STATUS StatusByCustomPredefined(const string symbol_name) const; //--- Return a symbol affiliation with categories by margin calculation ENUM_SYMBOL_STATUS StatusByCalcMode(const string symbol_name) const; //--- Return a symbol affiliation with pre-defined (1) majors, (2) minors, (3) exotics, (4) RUB, //--- (5) indicatives, (6) metals, (7) commodities, (8) indices, (9) cryptocurrency, (10) options bool IsPredefinedFXMajor(const string name) const; bool IsPredefinedFXMinor(const string name) const; bool IsPredefinedFXExotic(const string name) const; bool IsPredefinedFXRUB(const string name) const; bool IsPredefinedIndicative(const string name) const; bool IsPredefinedMetall(const string name) const; bool IsPredefinedCommodity(const string name) const; bool IsPredefinedIndex(const string name) const; bool IsPredefinedCrypto(const string name) const; bool IsPredefinedOption(const string name) const; //--- Search for a symbol and return the flag indicating its presence on the server bool Exist(const string name) const; public: //--- Return the full collection list 'as is' CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Return the number of new symbols in the Market Watch window int NewSymbols(void) const { return this.m_delta_symbol; } //--- Return the mode of working with symbol lists ENUM_SYMBOLS_MODE ModeSymbolsList(void) const { return this.m_mode_list; } //--- Constructor CSymbolsCollection(); //--- Set the list of used symbols bool SetUsedSymbol(const string &symbol_used_array[]); //--- Update (1) all, (2) quote data of the collection symbols void Refresh(void); void RefreshRates(void); }; //+------------------------------------------------------------------+
该类应知道要操控哪个品种类:当前品种,指定的品种集合,位于“市场观察”窗口中的品种列表,或服务器上所有品种的完整列表。 m_mode_list 类成员变量保存品种操控模式列表当中之一。
当操控市场观察的品种列表时,我们需要不断跟踪此列表(将在下一篇文章中实现),掌握上次检查期间的品种数量,并相应地关注市场观察列表增减的名单变化数量,以便及时重新排列 m_list_all_symbols 交易品种集合列表,并继续精准地操控所有品种。
与以前的集合一样,我们引入了一个新的类成员变量,该变量保存错误代码,您可以在 CEngine 函数库基类中查看和处理该错误代码。
当创建一个新的品种对象,并将其添加到集合之中时,我们需要确保列表中没有重复的品种。 这是通过 IsPresentSymbolInList() 方法完成的。
CreateNewSymbol() 方法用于创建新品种,并将其添加到集合之中。
鉴于在品种集合已分派了四种品种列表操控模式,因此 TypeSymbolsList() 方法用于定义将会使用的模式。<br14 /> 在创建新品种之前,我们首先要为其定义和设置一个组(或用户为其分配的组)。 SymbolStatus() 方法用于定义品种组(其状态)。
定义品种状态时,首先利用 StatusByCustomPredefined() 方法在指定的自定义数组中搜索其名称。
如果该方法返回的状态是“一般”,则品种状态由 StatusByCalcMode() 方法的保证金计算类型定义。
其他方法用于按用户数组进行搜索,并定义品种所属的自定义类别。 这些方法返回的标志指示品种是否属于主要、次要、指数和其他组。
Exist() 方法返回服务器上存在该品种的标志。
NewSymbols() 方法返回从“市场观察”窗口添加或删除的新交易品种的数量,而 ModeSymbolsList() 方法返回四种操控模式列表之一(当前品种,预定义品种集合,市场观察列表,以及服务器上的品种总数)给调用程序。
SetUsedSymbol() 方法接受品种数组,或操作模式的描述,以及通过数组传递的品种列表,并创建品种集合列表。
Refresh() 方法刷新品种集合之中所有变化的数据,而 RefreshRates() 方法仅更新所有集合品种的引用数据。 这两种方法都从 CEngine 函数库主对象的计时器中调用。
在此阶段,我们定义了使用品种集合类所需的所有方法。 我们观察一下它们的结构。
实现类构造函数:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CSymbolsCollection::CSymbolsCollection(void) : m_last_num_symbol(0),m_delta_symbol(0),m_mode_list(SYMBOLS_MODE_CURRENT) { this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_NAME); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Type(COLLECTION_SYMBOLS_ID); } //+------------------------------------------------------------------+
在构造函数初始化清单中,初始化上一次检查期间的品种数量和当前与之前品种数量的差值,以及设置品种列表操控模式为“操控当前品种”。
在类的实体之中,设置按名称对品种集合列表进行排序,清除列表,并为其分配“品种集合列表” ID。
刷新所有品种集合中所有数据的方法:
//+------------------------------------------------------------------+ //| Update all collection symbol data | //+------------------------------------------------------------------+ void CSymbolsCollection::Refresh(void) { int total=this.m_list_all_symbols.Total(); if(total==0) return; for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.Refresh(); } } //+------------------------------------------------------------------+
按所有集合中品种的数量循环, 从集合列表中获取下一个品种,并调用上一篇文章中研究过的 CSymbol 类的 Refresh() 方法更新其数据。
刷新所有集合中品种报价数据的方法:
//+------------------------------------------------------------------+ //| Update quote data of the collection symbols | //+------------------------------------------------------------------+ void CSymbolsCollection::RefreshRates(void) { int total=this.m_list_all_symbols.Total(); if(total==0) return; for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.RefreshRates(); } } //+------------------------------------------------------------------+
按所有集合中品种的数量循环, 从集合列表中获取下一个品种,并调用 CSymbol 类的 Refresh() 方法更新其数据。
创建新品种对象,并将其放置在品种集合列表中的方法:
//+------------------------------------------------------------------+ //| Create a symbol object and place it to the list | //+------------------------------------------------------------------+ bool CSymbolsCollection::CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name) { if(this.IsPresentSymbolInList(name)) { return true; } if(#ifdef __MQL5__ !::SymbolInfoInteger(name,SYMBOL_EXIST) #else !this.Exist(name) #endif ) { string t1=TextByLanguage("Ошибка входных данных: нет символа ","Input error: no "); string t2=TextByLanguage(" на сервере"," symbol on the server"); ::Print(DFUN,t1,name,t2); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; return false; } CSymbol *symbol=NULL; switch(symbol_status) { case SYMBOL_STATUS_FX : symbol=new CSymbolFX(name); break; // Forex symbol case SYMBOL_STATUS_FX_MAJOR : symbol=new CSymbolFXMajor(name); break; // Major Forex symbol case SYMBOL_STATUS_FX_MINOR : symbol=new CSymbolFXMinor(name); break; // Minor Forex symbol case SYMBOL_STATUS_FX_EXOTIC : symbol=new CSymbolFXExotic(name); break; // Exotic Forex symbol case SYMBOL_STATUS_FX_RUB : symbol=new CSymbolFXRub(name); break; // Forex symbol/RUR case SYMBOL_STATUS_METAL : symbol=new CSymbolMetall(name); break; // Metal case SYMBOL_STATUS_INDEX : symbol=new CSymbolIndex(name); break; // Index case SYMBOL_STATUS_INDICATIVE : symbol=new CSymbolIndicative(name); break; // Indicative case SYMBOL_STATUS_CRYPTO : symbol=new CSymbolCrypto(name); break; // Cryptocurrency symbol case SYMBOL_STATUS_COMMODITY : symbol=new CSymbolCommodity(name); break; // Commodity case SYMBOL_STATUS_EXCHANGE : symbol=new CSymbolExchange(name); break; // Exchange symbol case SYMBOL_STATUS_FUTURES : symbol=new CSymbolFutures(name); break; // Futures case SYMBOL_STATUS_CFD : symbol=new CSymbolCFD(name); break; // CFD case SYMBOL_STATUS_STOCKS : symbol=new CSymbolStocks(name); break; // Stock case SYMBOL_STATUS_BONDS : symbol=new CSymbolBonds(name); break; // Bond case SYMBOL_STATUS_OPTION : symbol=new CSymbolOption(name); break; // Option case SYMBOL_STATUS_COLLATERAL : symbol=new CSymbolCollateral(name); break; // Non-tradable asset case SYMBOL_STATUS_CUSTOM : symbol=new CSymbolCustom(name); break; // Custom symbol default : symbol=new CSymbolCommon(name); break; // The rest } if(symbol==NULL) { ::Print(DFUN,TextByLanguage("Не удалось создать объект-символ ","Failed to create symbol object "),name); return false; } if(!this.m_list_all_symbols.Add(symbol)) { string t1=TextByLanguage("Не удалось добавить символ ","Failed to add "); string t2=TextByLanguage(" в список"," symbol to the list"); ::Print(DFUN,t1,name,t2); delete symbol; return false; } return true; } //+------------------------------------------------------------------+
方法需要传递品种状态和名称。 如果该品种已经存在于品种集合列表之中,则返回 true "silently" —没有 错误,但由于该品种已存在,因此无需再次添加该品种。
接着,通过品种名称在服务器上检查是否存在该品种。 如果没有这个品种,则显示品种缺失消息,将“未知符号”值分配给错误代码,然后返回 false。
如果该品种存在,则根据传递给方法的状态创建一个新的品种对象。 为了创建品种对象,要利用与所传递的状态相对应的抽象品种的衍生类。 若对象创建错误的情况下,则显示相应的消息并返回 false。
如果新品种对象创建成功,将其添加到品种集合列表,并在添加成功的情况下返回 true ,或在不成功时,显示一条错误消息,然后返回 false。
返回品种在集合列表中存标志的方法实现:
//+------------------------------------------------------------------+ //| Return the symbol object presence flag | //| by its name in the list of all symbols | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPresentSymbolInList(const string symbol_name) { CArrayObj *list=dynamic_cast<CListObj*>(&this.m_list_all_symbols); list.Sort(SORT_BY_SYMBOL_NAME); list=CSelect::BySymbolProperty(list,SYMBOL_PROP_NAME,symbol_name,EQUAL); return(list==NULL || list.Total()==0 ? false : true); } //+------------------------------------------------------------------+
将所需品种的名称传递给方法,然后列表按品种名称和所传递的名称进行排序。 如果列表不为空,意即发现含有该名称的品种 — 返回 true。 否则,返回 false — 列表中没有该品种。
设置品种集合列表的方法实现:
//+------------------------------------------------------------------+ //| Set the list of used symbols | //+------------------------------------------------------------------+ bool CSymbolsCollection::SetUsedSymbol(const string &symbol_used_array[]) { this.m_mode_list=this.TypeSymbolsList(symbol_used_array); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_NAME); //--- Use only the current symbol if(this.m_mode_list==SYMBOLS_MODE_CURRENT) { string name=::Symbol(); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); return this.CreateNewSymbol(status,name); } else { bool res=true; //--- Use the pre-defined symbol list if(this.m_mode_list==SYMBOLS_MODE_DEFINES) { int total=::ArraySize(symbol_used_array); for(int i=0;i<total;i++) { string name=symbol_used_array[i]; ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } //--- Use the full list of the server symbols else if(this.m_mode_list==SYMBOLS_MODE_ALL) { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) { string name=::SymbolName(i,false); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } //--- Use the symbol list from the Market Watch window else if(this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH) { int total=::SymbolsTotal(true); for(int i=0;i<total;i++) { string name=::SymbolName(i,true); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } } return false; } //+------------------------------------------------------------------+
该方法根据传递给它的品种数组 的内容来创建品种集合列表。 首先,定义操控品种列表的方法(“品种/一组自定义品种/市场观察/完整列表”之一),然后清除列表并 按名称排序。
若是 仅用当前品种,
若是 使用预定义品种列表,
其余两种模式的处理方式类似于使用预定义列表的方式。 不过,代替将数组传递给该方法,品种即可取自市场观察,或者取自服务器上的完整品种列表。
返回品种列表操控模式的方法实现:
//+------------------------------------------------------------------+ //|Return the type of a used symbol list (Market watch/Server) | //+------------------------------------------------------------------+ ENUM_SYMBOLS_MODE CSymbolsCollection::TypeSymbolsList(const string &symbol_used_array[]) { int total=::ArraySize(symbol_used_array); if(total<1) return SYMBOLS_MODE_CURRENT; string type=::StringSubstr(symbol_used_array[0],13); return ( type=="MARKET_WATCH" ? SYMBOLS_MODE_MARKET_WATCH : type=="ALL" ? SYMBOLS_MODE_ALL : (total==1 && symbol_used_array[0]==::Symbol() ? SYMBOLS_MODE_CURRENT : SYMBOLS_MODE_DEFINES) ); } //+------------------------------------------------------------------+
方法接收品种名称数组,或操控模式列表。
如果传递了一个空数组,则返回的操作模式仅用当前品种。
接下来,自其零号单元接收数组内容,然后,
按名称返回携带品种从属分组关系的方法实现:
//+------------------------------------------------------------------+ //| Define a symbol affiliation with a group by name and return it | //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::SymbolStatus(const string symbol_name) const { ENUM_SYMBOL_STATUS status=this.StatusByCustomPredefined(symbol_name); return(status==SYMBOL_STATUS_COMMON ? this.StatusByCalcMode(symbol_name) : status); } //+------------------------------------------------------------------+
将品种名称传递给方法。 接着,检查与指定自定义组的隶属关系。 如果返回“一般组”状态,按“保证金计算模式”品种属性搜索分组。 结果则为,返回获得的状态。 顺便说一下,根据利润和保证金计算模式,它可以等于分组之一,或其可以保留在一般品种组之中。
结果就是,该品种的状态为自定义组。 如果自定义组中不存在该品种,则可按保证金计算方法将其分配至一个组。 如果为其定义分组失败,它将保留在一般组中。
返回品种从属某个自定义组标志的方法实现:
//+------------------------------------------------------------------+ //| Return a symbol affiliation with majors | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXMajor(const string name) const { int total=::ArraySize(DataSymbolsFXMajors); for(int i=0;i<total;i++) if(name==DataSymbolsFXMajors[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with minors | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXMinor(const string name) const { int total=::ArraySize(DataSymbolsFXMinors); for(int i=0;i<total;i++) if(name==DataSymbolsFXMinors[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with exotic symbols | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXExotic(const string name) const { int total=::ArraySize(DataSymbolsFXExotics); for(int i=0;i<total;i++) if(name==DataSymbolsFXExotics[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with RUB symbols | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXRUB(const string name) const { int total=::ArraySize(DataSymbolsFXRub); for(int i=0;i<total;i++) if(name==DataSymbolsFXRub[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with indicative symbols | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedIndicative(const string name) const { int total=::ArraySize(DataSymbolsFXIndicatives); for(int i=0;i<total;i++) if(name==DataSymbolsFXIndicatives[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with metals | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedMetall(const string name) const { int total=::ArraySize(DataSymbolsMetalls); for(int i=0;i<total;i++) if(name==DataSymbolsMetalls[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with commodities | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedCommodity(const string name) const { int total=::ArraySize(DataSymbolsCommodities); for(int i=0;i<total;i++) if(name==DataSymbolsCommodities[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with indices | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedIndex(const string name) const { int total=::ArraySize(DataSymbolsIndexes); for(int i=0;i<total;i++) if(name==DataSymbolsIndexes[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with a cryptocurrency | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedCrypto(const string name) const { int total=::ArraySize(DataSymbolsCrypto); for(int i=0;i<total;i++) if(name==DataSymbolsCrypto[i]) return true; return false; } //+------------------------------------------------------------------+ //| Return a symbol affiliation with options | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedOption(const string name) const { int total=::ArraySize(DataSymbolsOptions); for(int i=0;i<total;i++) if(name==DataSymbolsOptions[i]) return true; return false; } //+------------------------------------------------------------------+
依据(已检查的自定义组)方法名称,在所对应的自定义数组中搜索传递给该方法的品种名称。 如果在数组中找到这个品种,返回 true。 否则 — false。
该方法依据其在自定义组中存在与否返回品种状态:
//+------------------------------------------------------------------+ //| Return a category by custom criteria | //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCustomPredefined(const string symbol_name) const { return ( this.IsPredefinedFXMajor(symbol_name) ? SYMBOL_STATUS_FX_MAJOR : this.IsPredefinedFXMinor(symbol_name) ? SYMBOL_STATUS_FX_MINOR : this.IsPredefinedFXExotic(symbol_name) ? SYMBOL_STATUS_FX_EXOTIC : this.IsPredefinedFXRUB(symbol_name) ? SYMBOL_STATUS_FX_RUB : this.IsPredefinedOption(symbol_name) ? SYMBOL_STATUS_OPTION : this.IsPredefinedCommodity(symbol_name) ? SYMBOL_STATUS_COMMODITY : this.IsPredefinedCrypto(symbol_name) ? SYMBOL_STATUS_CRYPTO : this.IsPredefinedMetall(symbol_name) ? SYMBOL_STATUS_METAL : this.IsPredefinedIndex(symbol_name) ? SYMBOL_STATUS_INDEX : this.IsPredefinedIndicative(symbol_name) ? SYMBOL_STATUS_INDICATIVE : SYMBOL_STATUS_COMMON ); } //+------------------------------------------------------------------+
将品种名称传递给,并使用上述方法在每个自定义组中逐一检查是否存在。 一旦品种出现在任何组中,则返回发现该品种所对应的分组状态。 如果在任何组中均未找到该品种,则返回“一般品种组”状态。
该方法按保证金计算方法返回品种隶属关系分组:
//+------------------------------------------------------------------+ //|Return affiliation with a margin calculation category | //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCalcMode(const string symbol_name) const { ENUM_SYMBOL_CALC_MODE calc_mode=(ENUM_SYMBOL_CALC_MODE)::SymbolInfoInteger(symbol_name,SYMBOL_TRADE_CALC_MODE); return ( calc_mode==SYMBOL_CALC_MODE_EXCH_OPTIONS_MARGIN ? SYMBOL_STATUS_OPTION : calc_mode==SYMBOL_CALC_MODE_SERV_COLLATERAL ? SYMBOL_STATUS_COLLATERAL : calc_mode==SYMBOL_CALC_MODE_FUTURES ? SYMBOL_STATUS_FUTURES : calc_mode==SYMBOL_CALC_MODE_CFD || calc_mode==SYMBOL_CALC_MODE_CFDINDEX || calc_mode==SYMBOL_CALC_MODE_CFDLEVERAGE ? SYMBOL_STATUS_CFD : calc_mode==SYMBOL_CALC_MODE_FOREX || calc_mode==SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE ? SYMBOL_STATUS_FX : calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS || calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX ? SYMBOL_STATUS_STOCKS : calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS || calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS_MOEX ? SYMBOL_STATUS_BONDS : calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES || calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS ? SYMBOL_STATUS_FUTURES : SYMBOL_STATUS_COMMON ); } //+------------------------------------------------------------------+
方法接收品种名称,接着我们接收品种的保证金计算方法,然后根据获得的值返回品种状态。 如果未能识别任何计算方法,则返回“一般品种组”状态。
该方法在服务器上查找品种,并返回其存在标志:
//+---------------------------------------------------------------------------------+ //| Search for a symbol and return the flag indicating its presence on the server | //+---------------------------------------------------------------------------------+ bool CSymbolsCollection::Exist(const string name) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==name) return true; return false; } //+------------------------------------------------------------------+
品种集合类已准备就绪。 现在我们需要启用它。 与往常一样,在 CEngine 类中执行启动并处理。 我们要对其进行必要的修改。
将品种集合类文件包含到 CEngine 类文件中,并声明品种集合对象,以及必要的方法:
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Services\TimerCounter.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\EventsCollection.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" //+------------------------------------------------------------------+ //| Library basis class | //+------------------------------------------------------------------+ class CEngine : public CObject { 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 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 ENUM_TRADE_EVENT m_last_trade_event; // Last account trading event ENUM_ACCOUNT_EVENT m_last_account_event; // Last event in the account properties //--- Return the counter index by id int CounterIndex(const int id) const; //--- Return the (1) first launch flag, (2) presence of the flag in the trading event bool IsFirstStart(void); //--- Work with (1) order, deal and position, (2) account events void TradeEventsControl(void); void AccountEventsControl(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); public: //--- Return the list of market (1) positions, (2) pending orders and (3) market orders CArrayObj *GetListMarketPosition(void); CArrayObj *GetListMarketPendings(void); CArrayObj *GetListMarketOrders(void); //--- Return the list of historical (1) orders, (2) removed pending orders, (3) deals, (4) all position market orders by its id CArrayObj *GetListHistoryOrders(void); CArrayObj *GetListHistoryPendings(void); CArrayObj *GetListDeals(void); CArrayObj *GetListAllOrdersByPosID(const ulong position_id); //--- Return the list of (1) accounts, (2) account events, (3) account change event by its index in the list //--- (4) the current account, (5) event description CArrayObj *GetListAllAccounts(void) { return this.m_accounts.GetList(); } CArrayInt *GetListAccountEvents(void) { return this.m_accounts.GetListChanges(); } ENUM_ACCOUNT_EVENT GetAccountEventByIndex(const int index) { return this.m_accounts.GetEvent(index); } CAccount *GetAccountCurrent(void); string GetAccountEventDescription(ENUM_ACCOUNT_EVENT event); //--- Return the list of used symbols CArrayObj *GetListAllUsedSymbols(void) { return this.m_symbols.GetList(); } //--- Return the list of order, deal and position events CArrayObj *GetListAllOrdersEvents(void) { return this.m_events.GetList(); } //--- Reset the last trading event void ResetLastTradeEvent(void) { this.m_events.ResetLastTradeEvent(); } //--- Return the (1) last trading event, (2) the last event in the account properties, (3) hedging account flag, (4) flag of working in the tester ENUM_TRADE_EVENT LastTradeEvent(void) const { return this.m_last_trade_event; } ENUM_ACCOUNT_EVENT LastAccountEvent(void) const { return this.m_last_account_event; } bool IsHedge(void) const { return this.m_is_hedge; } bool IsTester(void) const { return this.m_is_tester; } bool IsAccountsEvent(void) const { return this.m_accounts.IsAccountEvent(); } //--- Return an account event code int GetAccountEventsCode(void) const { return this.m_accounts.GetEventCode(); } //--- Return CEngine global error code int GetError(void) const { return this.m_global_error; } //--- Create the timer counter void CreateCounter(const int id,const ulong frequency,const ulong pause); //--- Timer void OnTimer(void); //--- Set the list of used symbols bool SetUsedSymbols(const string &array_symbols[]) { return this.m_symbols.SetUsedSymbol(array_symbols); } //--- Constructor/destructor CEngine(); ~CEngine(); }; //+------------------------------------------------------------------+
SymbolEventsControl() 方法用于更新所有集合之中品种的报价数据,而 MarketWatchEventsControl() 方法用于更新所有集合之中品种的其余数据,并跟踪“市场观察”窗口中的事件(将在下一篇文章的品种集合事件类中研究)。
GetListAllUsedSymbols() 方法利用 CSymbolsCollection 类的 GetList() 方法将品种集合的完整列表返回给调用程序。
SetUsedSymbols() 方法调用 CSymbolsCollection 类的同名 SetUsedSymbol() 方法,其中会把程序中用到的所有品种按顺序将其品种对象填充到集合列表。
我们来研究这些方法的结构。
在类构造函数中,创建 first 和 second 品种集合计时器的计数器。在前一个计时器中,我们将刷新所有集合内品种的报价数据,而在第二个当中,我们将更新其余的品种数据,并管理市场观察窗口事件。
//+------------------------------------------------------------------+ //| CEngine constructor | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT),m_last_account_event(ACCOUNT_EVENT_NO_EVENT),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_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); ::ResetLastError(); #ifdef __MQL5__ if(!::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } //---__MQL4__ #else if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } #endif } //+------------------------------------------------------------------+
将操控两个品种集合的计时器代码添加到类 OnTimer() 处理程序中:
//+------------------------------------------------------------------+ //| CEngine timer | //+------------------------------------------------------------------+ void CEngine::OnTimer(void) { //--- 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); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If unpaused, work with the order, deal and position collections events if(counter.IsTimeDone()) this.TradeEventsControl(); } //--- If this is a tester, work with collection events by tick else this.TradeEventsControl(); } } //--- Account collection timer index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If unpaused, work with the account collection events if(counter.IsTimeDone()) this.AccountEventsControl(); } //--- If this is a tester, work with collection events by tick else this.AccountEventsControl(); } } //--- Timer 1 of the symbol collection (updating symbol quote data in the collection) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If the pause is over, update quote data of all symbols in the collection if(counter.IsTimeDone()) this.SymbolEventsControl(); } //--- In case of a tester, update quote data of all collection symbols by tick else this.SymbolEventsControl(); } } //--- Timer 2 of the symbol collection (updating all data of all symbols in the collection and track symbol search events in the market watch window) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If the pause is over if(counter.IsTimeDone()) { //--- update data of all symbols in the collection this.m_symbols.Refresh(); //--- When workign with the market watch list, check the market watch window events if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH) this.MarketWatchEventsControl(); } } //--- In case of a tester, update data of all collection symbols by tick else this.m_symbols.Refresh(); } } } //+------------------------------------------------------------------+
整个逻辑在代码注释中均已提供。 在这里啰嗦没有任何意义。
在目前的实现中,操控品种集合的方法仅调用 CSymbolsCollection 类的 RefreshRates 方法来刷新所有集合内品种的报价数据:
//+------------------------------------------------------------------+ //| Working with a symbol collection | //+------------------------------------------------------------------+ void CEngine::SymbolEventsControl(void) { this.m_symbols.RefreshRates(); } //+------------------------------------------------------------------+
在目前的实现中,调用“市场观察”窗口事件的方法仅检查它是否已从策略测试器中调用,如果是在策略测试器运行则退出(在策略测试器中跟踪市场观察窗口事件没有意义):
//+------------------------------------------------------------------+ //| Working with symbol list events in the market watch window | //+------------------------------------------------------------------+ void CEngine::MarketWatchEventsControl(void) { if(this.IsTester()) return; //--- Tracking Market Watch window events //--- } //+------------------------------------------------------------------+
在下一篇文章中,我们将完成所有与品种集合事件相关的工作。
所有这些都必须修改 CEngine 类。
鉴于我们需要将所需用到的品种模式传递给品种集合类,因此我们需要定义操作模式并正确填充品种数组的函数,以便将其传递给 CEngine 函数库的主要对象。
从 \MQL5\Include\DoEasy\Services\ 打开 DELib.mqh 服务函数文件,并在其中添加所需的函数:
//+------------------------------------------------------------------+ //| Prepare the symbol array for a symbol collection | //+------------------------------------------------------------------+ bool CreateUsedSymbolsArray(const ENUM_SYMBOLS_MODE mode_used_symbols,string defined_used_symbols,string &used_symbols_array[]) { //--- When working with the current symbol if(mode_used_symbols==SYMBOLS_MODE_CURRENT) { //--- Write the name of the current symbol to the only array cell ArrayResize(used_symbols_array,1); used_symbols_array[0]=Symbol(); return true; } //--- If working with a predefined symbol set (from the defined_used_symbols string) else if(mode_used_symbols==SYMBOLS_MODE_DEFINES) { //--- Set a comma as a separator string separator=","; //--- Replace erroneous separators with correct ones if(StringFind(defined_used_symbols,";")>WRONG_VALUE) StringReplace(defined_used_symbols,";",separator); if(StringFind(defined_used_symbols,":")>WRONG_VALUE) StringReplace(defined_used_symbols,":",separator); if(StringFind(defined_used_symbols,"|")>WRONG_VALUE) StringReplace(defined_used_symbols,"|",separator); if(StringFind(defined_used_symbols,"/")>WRONG_VALUE) StringReplace(defined_used_symbols,"/",separator); if(StringFind(defined_used_symbols,"\\")>WRONG_VALUE) StringReplace(defined_used_symbols,"\\",separator); if(StringFind(defined_used_symbols,"'")>WRONG_VALUE) StringReplace(defined_used_symbols,"'",separator); if(StringFind(defined_used_symbols,"-")>WRONG_VALUE) StringReplace(defined_used_symbols,"-",separator); if(StringFind(defined_used_symbols,"`")>WRONG_VALUE) StringReplace(defined_used_symbols,"`",separator); //--- Delete as long as there are spaces while(StringFind(defined_used_symbols," ")>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols," ",""); //--- As soon as there are double separators (after removing spaces between them), replace them with a separator while(StringFind(defined_used_symbols,separator+separator)>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols,separator+separator,separator); //--- If a single separator remains before the first symbol in the string, replace it with a space if(StringFind(defined_used_symbols,separator)==0) StringSetCharacter(defined_used_symbols,0,32); //--- If a single separator remains after the last symbol in the string, replace it with a space if(StringFind(defined_used_symbols,separator)==StringLen(defined_used_symbols)-1) StringSetCharacter(defined_used_symbols,StringLen(defined_used_symbols)-1,32); //--- Remove all redundant things to the left and right #ifdef __MQL5__ StringTrimLeft(defined_used_symbols); StringTrimRight(defined_used_symbols); //--- __MQL4__ #else defined_used_symbols=StringTrimLeft(defined_used_symbols); defined_used_symbols=StringTrimRight(defined_used_symbols); #endif //--- Prepare the array ArrayResize(used_symbols_array,0); ResetLastError(); //--- divide the string by separators (comma) and add all found substrings to the array int n=StringSplit(defined_used_symbols,StringGetCharacter(separator,0),used_symbols_array); //--- if nothing is found, display the appropriate message (working with the current symbol is selected automatically) if(n<1) { string err= (n==0 ? DFUN_ERR_LINE+TextByLanguage("Ошибка. Строка предопределённых символов пустая, будет использоваться ","Error. String of predefined symbols empty, symbol will be used: ")+Symbol() : DFUN_ERR_LINE+TextByLanguage("Не удалось подготовить массив используемых символов. Ошибка ","Failed to create array of used characters. Error ")+(string)GetLastError() ); Print(err); return false; } } //--- If working with the Market Watch window or the full list else { //--- Add the (mode_used_symbols) working mode to the only array cell ArrayResize(used_symbols_array,1); used_symbols_array[0]=EnumToString(mode_used_symbols); } return true; } //+------------------------------------------------------------------+
该方法接收操控品种集合的模式,该模式可以在程序配置中设定,也可以硬性定义(如果不需要选择模式),用逗号分隔的品种列表(您打算处理的,或空字符串),和添加品种列表的数组或操控模式(用于操控市场观察和服务器上完整品种列表),将其发送到 CEngine 类,以便设置操控品种的函数库模式。
函数的所有动作,以及数组作用均直接在清单中有所详述了。 单独研究它们没有意义。
品种集合类的开发既已完毕。 一切准备就绪,可以进行测试。
为了测试集合,我们将利用来自上一篇文章 中的 EA,并将其保存在 \MQL5\Experts\TestDoEasy\ 下,命名为 Part15\TestDoEasyPart15_1.mq5。
在输入中,加入选择操控品种集合模式和一个存储自定义品种列表的字符串变量,如果令您可在设置中选择操控模式:
//--- input variables input ulong InpMagic = 123; // Magic number input double InpLots = 0.1; // Lots input uint InpStopLoss = 50; // StopLoss in points input uint InpTakeProfit = 50; // TakeProfit in points input uint InpDistance = 50; // Pending orders distance (points) input uint InpDistanceSL = 50; // StopLimit orders distance (points) input uint InpSlippage = 0; // Slippage in points input double InpWithdrawal = 10; // Withdrawal funds (in tester) input uint InpButtShiftX = 40; // Buttons X shift input uint InpButtShiftY = 10; // Buttons Y shift input uint InpTrailingStop = 50; // Trailing Stop (points) input uint InpTrailingStep = 20; // Trailing Step (points) input uint InpTrailingStart = 0; // Trailing Start (points) input uint InpStopLossModify = 20; // StopLoss for modification (points) input uint InpTakeProfitModify = 60; // TakeProfit for modification (points) input ENUM_SYMBOLS_MODE InpModeUsedSymbols = SYMBOLS_MODE_CURRENT; // Mode of used symbols list input string InpUsedSymbols = "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY"; // List of used symbols (comma - separator) //--- global variables
在全局变量列表中,添加保存自定义品种列表的变量和保存传递给函数库的品种列表的字符串数组:
//--- global variables CEngine engine; #ifdef __MQL5__ CTrade trade; #endif SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ulong magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint slippage; bool trailing_on; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; string used_symbols; string array_used_symbols[]; //+------------------------------------------------------------------+
在 EA 的 OnInit() 处理程序中,将自定义列表分配给用于存储它的变量,填写已用过品种数组,然后将其发送到函数库:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Calling the function displays the list of enumeration constants in the journal //--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity //EnumNumbersTest(); //--- Set EA global variables prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_"; for(int i=0;i<TOTAL_BUTT;i++) { butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i); butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i); } lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0)); magic_number=InpMagic; stoploss=InpStopLoss; takeprofit=InpTakeProfit; distance_pending=InpDistance; distance_stoplimit=InpDistanceSL; slippage=InpSlippage; trailing_stop=InpTrailingStop*Point(); trailing_step=InpTrailingStep*Point(); trailing_start=InpTrailingStart; stoploss_to_modify=InpStopLossModify; takeprofit_to_modify=InpTakeProfitModify; //--- Fill in the array of used symbols used_symbols=InpUsedSymbols; CreateUsedSymbolsArray(InpModeUsedSymbols,used_symbols,array_used_symbols); //--- Set the type of the used symbol list in the symbol collection engine.SetUsedSymbols(array_used_symbols); //--- Check and remove remaining EA graphical objects
上面已研究过的 SetUsedSymbols() 函数创建要发送到品种集合类的品种数组。 根据所选模式,数组含有当前品种或自定义品种列表,或含有操控“市场观察”窗口,或服务器上完整品种列表模式的字符串描述。
在 OnInit() 处理程序的末尾,添加代码以便快速查验由品种集合类创建的品种列表:
//--- Set CTrade trading class parameters #ifdef __MQL5__ trade.SetDeviationInPoints(slippage); trade.SetExpertMagicNumber(magic_number); trade.SetTypeFillingBySymbol(Symbol()); trade.SetMarginMode(); trade.LogLevel(LOG_LEVEL_NO); #endif //--- Fast check of the symbol object collection CArrayObj *list=engine.GetListAllUsedSymbols(); CSymbol *symbol=NULL; if(list!=NULL) { int total=list.Total(); for(int i=0;i<total;i++) { symbol=list.At(i); if(symbol==NULL) continue; symbol.Refresh(); symbol.RefreshRates(); symbol.PrintShort(); if(InpModeUsedSymbols<SYMBOLS_MODE_MARKET_WATCH) symbol.Print(); } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
至此,我们得到所有集合内的完整品种列表。 按所获列表的循环中,从中获取下一个品种,更新所有数据,并在日志中打印出该品种的说明。 首先,显示简要。 然后,如果未选择“操控市场观察窗口”或“操控服务器上的完整品种列表”模式,则在日志中显示品种属性的完整描述。。
在终端窗口中启动 EA,然后在配置中选择“操控市场观察窗口中品种”模式。 结果就是,由品种集合类创建的所有集合列表内品种的简述均显示在日志中:
2019.06.27 10:01:52.756 Stock ALNU 2019.06.27 10:01:52.756 Stock SU25075RMFS1 2019.06.27 10:01:52.756 Bond SU46022RMFS8 2019.06.27 10:01:52.756 Bond SU26214RMFS5 2019.06.27 10:01:52.756 Stock AESL 2019.06.27 10:01:52.756 Stock 123456.bin 2019.06.27 10:01:52.756 Stock ARMD 2019.06.27 10:01:52.757 Bond SU46018RMFS6 2019.06.27 10:01:52.757 Stock GAZP 2019.06.27 10:01:52.757 Metal XAUUSD 2019.06.27 10:01:52.757 Stock EURRUB_TOD 2019.06.27 10:01:52.757 Stock GBPRUB_TOM 2019.06.27 10:01:52.757 Futures Si-9.19 2019.06.27 10:01:52.757 Futures RTS-3.20 2019.06.27 10:01:52.758 Minor Forex symbol USDNOK 2019.06.27 10:01:52.758 Major Forex symbol USDJPY 2019.06.27 10:01:52.758 Major Forex symbol EURUSD 2019.06.27 10:01:52.758 Minor Forex symbol USDCZK 2019.06.27 10:01:52.758 Major Forex symbol USDCAD 2019.06.27 10:01:52.758 Minor Forex symbol USDZAR 2019.06.27 10:01:52.758 Minor Forex symbol USDSEK 2019.06.27 10:01:52.758 Major Forex symbol AUDUSD 2019.06.27 10:01:52.758 Minor Forex symbol USDDKK 2019.06.27 10:01:52.758 Major Forex symbol NZDUSD 2019.06.27 10:01:52.759 Minor Forex symbol USDPLN 2019.06.27 10:01:52.759 Major Forex symbol GBPUSD 2019.06.27 10:01:52.759 Forex symbol USDRUR 2019.06.27 10:01:52.759 Exotic Forex symbol USDMXN 2019.06.27 10:01:52.759 Forex symbol USDHUF 2019.06.27 10:01:52.759 Minor Forex symbol USDTRY 2019.06.27 10:01:52.759 Minor Forex symbol USDHKD 2019.06.27 10:01:52.760 Major Forex symbol USDCHF 2019.06.27 10:01:52.760 Minor Forex symbol USDSGD
现在,我们检查一下品种集合中按指定值搜索。
重命名 EA 并将其保存在 \MQL5\Experts\TestDoEasy\ 之下,名称为 Part15\TestDoEasyPart15_2.mq5。
修改 OnInit() 处理程序中集合内品种列表的快速检查代码。 将品种列表移至日志,仅保留更新集合内品种数据,并添加用于接收集合内品种多头和空头持仓的最大/最小持仓利率,和最大/最小点差。 将获得的数据输入日志:
//--- Set CTrade trading class parameters #ifdef __MQL5__ trade.SetDeviationInPoints(slippage); trade.SetExpertMagicNumber(magic_number); trade.SetTypeFillingBySymbol(Symbol()); trade.SetMarginMode(); trade.LogLevel(LOG_LEVEL_NO); #endif //--- Fast check of the symbol object collection CArrayObj *list=engine.GetListAllUsedSymbols(); CSymbol *symbol=NULL; if(list!=NULL) { int total=list.Total(); for(int i=0;i<total;i++) { symbol=list.At(i); if(symbol==NULL) continue; symbol.Refresh(); symbol.RefreshRates(); } } //--- Get the minimum and maximum values //--- get the current account properties (we need the number of decimal places for the account currency) CAccount *account=engine.GetAccountCurrent(); if(account!=NULL) { int index_min=0, index_max=0, dgc=(int)account.CurrencyDigits(); //--- If working with the Market Watch window, leave only visible symbols in the list if(InpModeUsedSymbols==SYMBOLS_MODE_MARKET_WATCH) list=CSelect::BySymbolProperty(list,SYMBOL_PROP_VISIBLE,true,EQUAL); //--- min/max swap long index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SWAP_LONG); // symbol index in the collection list with the minimum swap long index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SWAP_LONG); // symbol index in the collection list with the maximum swap long if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Minimum swap long for a symbol ",symbol.Name()," = ",NormalizeDouble(symbol.SwapLong(),dgc)); symbol=list.At(index_max); if(symbol!=NULL) Print("Maximum swap long for a symbol ",symbol.Name()," = ",NormalizeDouble(symbol.SwapLong(),dgc)); } //--- min/max swap short index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SWAP_SHORT); // symbol index in the collection list with the minimum swap short index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SWAP_SHORT); // symbol index in the collection list with the maximum swap short if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Minimum swap short for a symbol ",symbol.Name()," = ",NormalizeDouble(symbol.SwapShort(),dgc)); symbol=list.At(index_max); if(symbol!=NULL) Print("Maximum swap short for a symbol ",symbol.Name()," = ",NormalizeDouble(symbol.SwapShort(),dgc)); } //--- min/max spread index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SPREAD); // symbol index in the collection list with the minimum spread index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SPREAD); // symbol index in the collection list with the maximum spread if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Minimum symbol spread ",symbol.Name()," = ",symbol.Spread()); symbol=list.At(index_max); if(symbol!=NULL) Print("Maximum symbol spread ",symbol.Name()," = ",symbol.Spread()); } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
在终端图表上编译并启动 EA。 在配置中选择操控服务器上的完整品种列表。 当创建服务器上所有品种集合列表之后(需要花费一些时间),有关集合内所有品种的多头与空头的最大/最小持仓利率,以及最大/最小点差的数据将显示在日志当中:
2019.06.27 10:36:28.885 Minimum long position swap for USDZAR = -192.9 2019.06.27 10:36:28.885 Maximum long position swap for USDMXN = 432.7 2019.06.27 10:36:28.886 Minimum short position swap for XAUUSD = -17.8 2019.06.27 10:36:28.886 Maximum short position swap for USDMXN = 200.0 2019.06.27 10:36:28.886 Minimum spread for SU52001RMFS3 = 0 2019.06.27 10:36:28.886 Maximum spread for GBPRUB_TOM = 3975
在下一篇文章中,我们将开发品种集合事件类。
文后附有当前版本含糊库的所有文件,以及测试 EA 文件,供您测试和下载。
请在评论中留下您的问题、意见和建议。
返回目录
系列中的前几篇文章:
第一部分 概念,数据管理
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程