内容
- 帐户事件的概念
- 处理帐户事件的方法
- 测试帐户事件
- 下一步是什么?
帐户事件的概念
以前,我们曾创建了一个单独的类来跟踪订单和持仓事件(第四部分 - 第六部分),并将检测到的变更数据发送到 CEngine 主体函数库对象。
为了跟踪帐户事件,我们将运用另一种方法:由于我们只能跟踪单个帐户(终端当前连接的帐户)上的事件,因此单独的类就是多余的。 代之,我们将直接在帐户集合类中创建处理事件的方法。
要检测帐户属性中的任何更改,我们将比较当前帐户属性与其先前的状态。 如果检测到变化,则会将事件发送到控制程序所在图表。
在创建帐户对象集合时,我们已开发了一些用来跟踪上一篇文章中所述帐户事件的功能。 在本文中,我们将改进现有功能,令其完整可用。
处理帐户事件的方法
我们首先在 Defines.mqh 文件中创建必要的枚举和宏替换。 由于收到开发人员关于为账户的字符串型属性分配的实际大小(以字节为单位)的回应,我们将在 CAccount 类代码中严格设置它们,因此取消了设置存储帐户对象字符串型属性 uchar 数组大小的宏替换。 从 Defines.mqh 清单中删除宏替换
#define UCHAR_ARRAY_SIZE (64) // Size of uchar arrays for storing string properties
我还决定将处理帐户对象的所有必要枚举和宏替换添加到文件的最末端 — 在处理交易事件的数据之后,因为我们不仅要发送帐户事件代码,而且还要为程序实现交易事件。 这意味着帐户事件代码的编号将从最后一个交易事件代码 +1 开始。 如果交易事件的数量增加,我们将声明包含所有交易事件总数的宏替换,如此即可勿需重写账户事件代码的编号。 此外,我们将设置宏替换,指定帐户事件的总数,应对我们实现其他一些事件(比如品种事件)。 在这种情况下,这些新事件的编号自帐户事件的总数 +1 开始。
在帐户可能的交易事件列表的末尾,插入宏替换,指定对应于上次交易事件 +1 的编号:
//+------------------------------------------------------------------+ //| List of possible trading events on the account | //+------------------------------------------------------------------+ enum ENUM_TRADE_EVENT { TRADE_EVENT_NO_EVENT = 0, // No trading event TRADE_EVENT_PENDING_ORDER_PLASED, // Pending order placed TRADE_EVENT_PENDING_ORDER_REMOVED, // Pending order removed //--- enumeration members matching the ENUM_DEAL_TYPE enumeration members //--- (constant order below should not be changed, no constants should be added/deleted) TRADE_EVENT_ACCOUNT_CREDIT = DEAL_TYPE_CREDIT, // Accruing credit (3) TRADE_EVENT_ACCOUNT_CHARGE, // Additional charges TRADE_EVENT_ACCOUNT_CORRECTION, // Correcting entry TRADE_EVENT_ACCOUNT_BONUS, // Accruing bonuses TRADE_EVENT_ACCOUNT_COMISSION, // Additional commissions TRADE_EVENT_ACCOUNT_COMISSION_DAILY, // Commission charged at the end of a trading day TRADE_EVENT_ACCOUNT_COMISSION_MONTHLY, // Commission charged at the end of a trading month TRADE_EVENT_ACCOUNT_COMISSION_AGENT_DAILY, // Agent commission charged at the end of a trading day TRADE_EVENT_ACCOUNT_COMISSION_AGENT_MONTHLY, // Agent commission charged at the end of a month TRADE_EVENT_ACCOUNT_INTEREST, // Accrued interest on free funds TRADE_EVENT_BUY_CANCELLED, // Canceled buy deal TRADE_EVENT_SELL_CANCELLED, // Canceled sell deal TRADE_EVENT_DIVIDENT, // Accruing dividends TRADE_EVENT_DIVIDENT_FRANKED, // Accruing franked dividends TRADE_EVENT_TAX = DEAL_TAX, // Tax //--- constants related to the DEAL_TYPE_BALANCE deal type from the DEAL_TYPE_BALANCE enumeration TRADE_EVENT_ACCOUNT_BALANCE_REFILL = DEAL_TAX+1, // Replenishing account balance TRADE_EVENT_ACCOUNT_BALANCE_WITHDRAWAL = DEAL_TAX+2, // Withdrawing funds from an account //--- Remaining possible trading events//--- (constant order below can be changed, constants can be added/deleted) TRADE_EVENT_PENDING_ORDER_ACTIVATED = DEAL_TAX+3, // Pending order activated by price TRADE_EVENT_PENDING_ORDER_ACTIVATED_PARTIAL, // Pending order partially activated by price TRADE_EVENT_POSITION_OPENED, // Position opened TRADE_EVENT_POSITION_OPENED_PARTIAL, // Position opened partially TRADE_EVENT_POSITION_CLOSED, // Position closed TRADE_EVENT_POSITION_CLOSED_BY_POS, // Position closed by an opposite one TRADE_EVENT_POSITION_CLOSED_BY_SL, // Position closed by StopLoss TRADE_EVENT_POSITION_CLOSED_BY_TP, // Position closed by TakeProfit TRADE_EVENT_POSITION_REVERSED_BY_MARKET, // Position reversal by a new deal (netting) TRADE_EVENT_POSITION_REVERSED_BY_PENDING, // Position reversal by activating a pending order (netting) TRADE_EVENT_POSITION_REVERSED_BY_MARKET_PARTIAL, // Position reversal by partial market order execution (netting) TRADE_EVENT_POSITION_REVERSED_BY_PENDING_PARTIAL, // Position reversal by partial pending order activation (netting) TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET, // Added volume to a position by a new deal (netting) TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET_PARTIAL, // Added volume to a position by partial activation of an order (netting) TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING, // Added volume to a position by activating a pending order (netting) TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING_PARTIAL, // Added volume to a position by partial activation of a pending order (netting) TRADE_EVENT_POSITION_CLOSED_PARTIAL, // Position closed partially TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_POS, // Position closed partially by an opposite one TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_SL, // Position closed partially by StopLoss TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_TP, // Position closed partially by TakeProfit TRADE_EVENT_TRIGGERED_STOP_LIMIT_ORDER, // StopLimit order activation TRADE_EVENT_MODIFY_ORDER_PRICE, // Changing order price TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS, // Changing order and StopLoss price TRADE_EVENT_MODIFY_ORDER_PRICE_TAKE_PROFIT, // Changing order and TakeProfit price TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT, // Changing order, StopLoss and TakeProfit price TRADE_EVENT_MODIFY_ORDER_STOP_LOSS_TAKE_PROFIT, // Changing order's StopLoss and TakeProfit price TRADE_EVENT_MODIFY_ORDER_STOP_LOSS, // Changing order Stop Loss TRADE_EVENT_MODIFY_ORDER_TAKE_PROFIT, // Changing order Take Profit TRADE_EVENT_MODIFY_POSITION_STOP_LOSS_TAKE_PROFIT, // Changing position StopLoss and TakeProfit TRADE_EVENT_MODIFY_POSITION_STOP_LOSS, // Changing position StopLoss TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT, // Changing position TakeProfit }; #define TRADE_EVENTS_NEXT_CODE (TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT+1)// The code of the next event after the last trading event code //+------------------------------------------------------------------+
这是帐户事件代码的起始代码。
在上一篇文章中,我们设置了帐户整数型、实数型和字符串型属性,以及可能的帐户排序条件,并将它们置于处理帐户事件的数据之前。 现在我们将它们移到最后,并附加处理帐户事件的其他数据 — 帐户事件标记列表和可能的帐户事件:
//+------------------------------------------------------------------+ //| Data for working with accounts | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| List of account event flags | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_EVENT_FLAGS { ACCOUNT_EVENT_FLAG_NO_EVENT = 0, // No event ACCOUNT_EVENT_FLAG_LEVERAGE = 1, // Changing the leverage ACCOUNT_EVENT_FLAG_LIMIT_ORDERS = 2, // Changing the maximum allowed number of active pending orders ACCOUNT_EVENT_FLAG_TRADE_ALLOWED = 4, // Changing permission to trade for the account ACCOUNT_EVENT_FLAG_TRADE_EXPERT = 8, // Changing permission for auto trading for the account ACCOUNT_EVENT_FLAG_BALANCE = 16, // The balance exceeds the specified change value +/- ACCOUNT_EVENT_FLAG_EQUITY = 32, // The equity exceeds the specified change value +/- ACCOUNT_EVENT_FLAG_PROFIT = 64, // The profit exceeds the specified change value +/- ACCOUNT_EVENT_FLAG_CREDIT = 128, // Changing the credit in a deposit currency ACCOUNT_EVENT_FLAG_MARGIN = 256, // The reserved margin on an account in the deposit currency exceeds the specified change value +/- ACCOUNT_EVENT_FLAG_MARGIN_FREE = 512, // The free funds available for opening a position in a deposit currency exceed the specified change value +/- ACCOUNT_EVENT_FLAG_MARGIN_LEVEL = 1024, // The margin level on an account in % exceeds the specified change value +/- ACCOUNT_EVENT_FLAG_MARGIN_INITIAL = 2048, // The funds reserved on an account to ensure a guarantee amount for all pending orders exceed the specified change value +/- ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE = 4096, // The funds reserved on an account to ensure a minimum amount for all open positions exceed the specified change value +/- ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL = 8192, // Changing the Margin Call level ACCOUNT_EVENT_FLAG_MARGIN_SO_SO = 16384, // Changing the Stop Out level ACCOUNT_EVENT_FLAG_ASSETS = 32768, // The current assets on an account exceed the specified change value +/- ACCOUNT_EVENT_FLAG_LIABILITIES = 65536, // The current liabilities on an account exceed the specified change value +/- ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED = 131072, // The current sum of blocked commissions on an account exceeds the specified change value +/- }; //+------------------------------------------------------------------+ //| List of possible account events | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_EVENT { ACCOUNT_EVENT_NO_EVENT = TRADE_EVENTS_NEXT_CODE, // No event ACCOUNT_EVENT_LEVERAGE_INC, // Increasing the leverage ACCOUNT_EVENT_LEVERAGE_DEC, // Decreasing the leverage ACCOUNT_EVENT_LIMIT_ORDERS_INC, // Increasing the maximum allowed number of active pending orders ACCOUNT_EVENT_LIMIT_ORDERS_DEC, // Decreasing the maximum allowed number of active pending orders ACCOUNT_EVENT_TRADE_ALLOWED_ON, // Enabling trading for the account ACCOUNT_EVENT_TRADE_ALLOWED_OFF, // Disabling trading for the account ACCOUNT_EVENT_TRADE_EXPERT_ON, // Enabling auto trading for the account ACCOUNT_EVENT_TRADE_EXPERT_OFF, // Disabling auto trading for the account ACCOUNT_EVENT_BALANCE_INC, // The balance exceeds the specified value ACCOUNT_EVENT_BALANCE_DEC, // The balance falls below the specified value ACCOUNT_EVENT_EQUITY_INC, // The equity exceeds the specified value ACCOUNT_EVENT_EQUITY_DEC, // The equity falls below the specified value ACCOUNT_EVENT_PROFIT_INC, // The profit exceeds the specified value ACCOUNT_EVENT_PROFIT_DEC, // The profit falls below the specified value ACCOUNT_EVENT_CREDIT_INC, // The credit exceeds the specified value ACCOUNT_EVENT_CREDIT_DEC, // The credit falls below the specified value ACCOUNT_EVENT_MARGIN_INC, // Increasing the reserved margin on an account in the deposit currency ACCOUNT_EVENT_MARGIN_DEC, // Decreasing the reserved margin on an account in the deposit currency ACCOUNT_EVENT_MARGIN_FREE_INC, // Increasing the free funds available for opening a position in a deposit currency ACCOUNT_EVENT_MARGIN_FREE_DEC, // Decreasing the free funds available for opening a position in a deposit currency ACCOUNT_EVENT_MARGIN_LEVEL_INC, // Increasing the margin level on an account in % ACCOUNT_EVENT_MARGIN_LEVEL_DEC, // Decreasing the margin level on an account in % ACCOUNT_EVENT_MARGIN_INITIAL_INC, // Increasing the funds reserved on an account to ensure a guarantee amount for all pending orders ACCOUNT_EVENT_MARGIN_INITIAL_DEC, // Decreasing the funds reserved on an account to ensure a guarantee amount for all pending orders ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC, // Increasing the funds reserved on an account to ensure a minimum amount for all open positions ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC, // Decreasing the funds reserved on an account to ensure a minimum amount for all open positions ACCOUNT_EVENT_MARGIN_SO_CALL_INC, // Increasing the Margin Call level ACCOUNT_EVENT_MARGIN_SO_CALL_DEC, // Decreasing the Margin Call level ACCOUNT_EVENT_MARGIN_SO_SO_INC, // Increasing the Stop Out level ACCOUNT_EVENT_MARGIN_SO_SO_DEC, // Decreasing the Stop Out level ACCOUNT_EVENT_ASSETS_INC, // Increasing the current asset size on the account ACCOUNT_EVENT_ASSETS_DEC, // Decreasing the current asset size on the account ACCOUNT_EVENT_LIABILITIES_INC, // Increasing the current liabilities on the account ACCOUNT_EVENT_LIABILITIES_DEC, // Decreasing the current liabilities on the account ACCOUNT_EVENT_COMISSION_BLOCKED_INC, // Increasing the current sum of blocked commissions on an account ACCOUNT_EVENT_COMISSION_BLOCKED_DEC, // Decreasing the current sum of blocked commissions on an account< }; #define ACCOUNT_EVENTS_NEXT_CODE (ACCOUNT_EVENT_COMISSION_BLOCKED_DEC+1) // The code of the next event after the last account event code //+------------------------------------------------------------------+ //| Account integer properties | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_PROP_INTEGER { ACCOUNT_PROP_LOGIN, // Account number ACCOUNT_PROP_TRADE_MODE, // Trading account type ACCOUNT_PROP_LEVERAGE, // Provided leverage ACCOUNT_PROP_LIMIT_ORDERS, // Maximum allowed number of active pending orders ACCOUNT_PROP_MARGIN_SO_MODE, // Mode of setting the minimum available margin level ACCOUNT_PROP_TRADE_ALLOWED, // Permission to trade for the current account from the server side ACCOUNT_PROP_TRADE_EXPERT, // Permission to trade for an EA from the server side ACCOUNT_PROP_MARGIN_MODE, // Margin calculation mode ACCOUNT_PROP_CURRENCY_DIGITS, // Number of digits for an account currency necessary for accurate display of trading results ACCOUNT_PROP_SERVER_TYPE // Trade server type (MetaTrader 5, MetaTrader 4) }; #define ACCOUNT_PROP_INTEGER_TOTAL (10) // Total number of account's integer properties #define ACCOUNT_PROP_INTEGER_SKIP (0) // Number of account's integer properties not used in sorting //+------------------------------------------------------------------+ //| Account real properties | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_PROP_DOUBLE { ACCOUNT_PROP_BALANCE = ACCOUNT_PROP_INTEGER_TOTAL, // Account balance in a deposit currency ACCOUNT_PROP_CREDIT, // Credit in a deposit currency ACCOUNT_PROP_PROFIT, // Current profit on an account in the account currency ACCOUNT_PROP_EQUITY, // Equity on an account in the deposit currency ACCOUNT_PROP_MARGIN, // Reserved margin on an account in a deposit currency ACCOUNT_PROP_MARGIN_FREE, // Free funds available for opening a position in a deposit currency ACCOUNT_PROP_MARGIN_LEVEL, // Margin level on an account in % ACCOUNT_PROP_MARGIN_SO_CALL, // Margin Call level ACCOUNT_PROP_MARGIN_SO_SO, // Stop Out level ACCOUNT_PROP_MARGIN_INITIAL, // Funds reserved on an account to ensure a guarantee amount for all pending orders ACCOUNT_PROP_MARGIN_MAINTENANCE, // Funds reserved on an account to ensure a minimum amount for all open positions ACCOUNT_PROP_ASSETS, // Current assets on an account ACCOUNT_PROP_LIABILITIES, // Current liabilities on an account ACCOUNT_PROP_COMMISSION_BLOCKED // Current sum of blocked commissions on an account }; #define ACCOUNT_PROP_DOUBLE_TOTAL (14) // Total number of account's real properties #define ACCOUNT_PROP_DOUBLE_SKIP (0) // Number of account's real properties not used in sorting //+------------------------------------------------------------------+ //| Account string properties | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_PROP_STRING { ACCOUNT_PROP_NAME = (ACCOUNT_PROP_INTEGER_TOTAL+ACCOUNT_PROP_DOUBLE_TOTAL), // Client name ACCOUNT_PROP_SERVER, // Trade server name ACCOUNT_PROP_CURRENCY, // Deposit currency ACCOUNT_PROP_COMPANY // Name of a company serving an account }; #define ACCOUNT_PROP_STRING_TOTAL (4) // Total number of account's string properties #define ACCOUNT_PROP_STRING_SKIP (0) // Number of account string properties not used in sorting //+------------------------------------------------------------------+ //| Possible account sorting criteria | //+------------------------------------------------------------------+ #define FIRST_ACC_DBL_PROP (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP) #define FIRST_ACC_STR_PROP (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP+ACCOUNT_PROP_DOUBLE_TOTAL-ACCOUNT_PROP_DOUBLE_SKIP) enum ENUM_SORT_ACCOUNT_MODE { SORT_BY_ACCOUNT_LOGIN = 0, // Sort by account number SORT_BY_ACCOUNT_TRADE_MODE = 1, // Sort by trading account type SORT_BY_ACCOUNT_LEVERAGE = 2, // Sort by leverage SORT_BY_ACCOUNT_LIMIT_ORDERS = 3, // Sort by maximum acceptable number of existing pending orders SORT_BY_ACCOUNT_MARGIN_SO_MODE = 4, // Sort by mode for setting the minimum acceptable margin level SORT_BY_ACCOUNT_TRADE_ALLOWED = 5, // Sort by permission to trade for the current account SORT_BY_ACCOUNT_TRADE_EXPERT = 6, // Sort by permission to trade for an EA SORT_BY_ACCOUNT_MARGIN_MODE = 7, // Sort by margin calculation mode SORT_BY_ACCOUNT_CURRENCY_DIGITS = 8, // Sort by number of digits for an account currency SORT_BY_ACCOUNT_SERVER_TYPE = 9, // Sort by trade server type (MetaTrader 5, MetaTrader 4) SORT_BY_ACCOUNT_BALANCE = FIRST_ACC_DBL_PROP, // Sort by an account balance in the deposit currency SORT_BY_ACCOUNT_CREDIT = FIRST_ACC_DBL_PROP+1, // Sort by credit in a deposit currency SORT_BY_ACCOUNT_PROFIT = FIRST_ACC_DBL_PROP+2, // Sort by the current profit on an account in the deposit currency SORT_BY_ACCOUNT_EQUITY = FIRST_ACC_DBL_PROP+3, // Sort by an account equity in the deposit currency SORT_BY_ACCOUNT_MARGIN = FIRST_ACC_DBL_PROP+4, // Sort by an account reserved margin in the deposit currency SORT_BY_ACCOUNT_MARGIN_FREE = FIRST_ACC_DBL_PROP+5, // Sort by account free funds available for opening a position in the deposit currency SORT_BY_ACCOUNT_MARGIN_LEVEL = FIRST_ACC_DBL_PROP+6, // Sort by account margin level in % SORT_BY_ACCOUNT_MARGIN_SO_CALL = FIRST_ACC_DBL_PROP+7, // Sort by margin level requiring depositing funds to an account (Margin Call) SORT_BY_ACCOUNT_MARGIN_SO_SO = FIRST_ACC_DBL_PROP+8, // Sort by margin level, at which the most loss-making position is closed (Stop Out) SORT_BY_ACCOUNT_MARGIN_INITIAL = FIRST_ACC_DBL_PROP+9, // Sort by funds reserved on an account to ensure a guarantee amount for all pending orders SORT_BY_ACCOUNT_MARGIN_MAINTENANCE = FIRST_ACC_DBL_PROP+10, // Sort by funds reserved on an account to ensure a minimum amount for all open positions SORT_BY_ACCOUNT_ASSETS = FIRST_ACC_DBL_PROP+11, // Sort by the amount of the current assets on an account SORT_BY_ACCOUNT_LIABILITIES = FIRST_ACC_DBL_PROP+12, // Sort by the current liabilities on an account SORT_BY_ACCOUNT_COMMISSION_BLOCKED = FIRST_ACC_DBL_PROP+13, // Sort by the current amount of blocked commissions on an account SORT_BY_ACCOUNT_NAME = FIRST_ACC_STR_PROP, // Sort by a client name SORT_BY_ACCOUNT_SERVER = FIRST_ACC_STR_PROP+1, // Sort by a trade server name SORT_BY_ACCOUNT_CURRENCY = FIRST_ACC_STR_PROP+2, // Sort by a deposit currency SORT_BY_ACCOUNT_COMPANY = FIRST_ACC_STR_PROP+3 // Sort by a name of a company serving an account }; //+------------------------------------------------------------------+
由于多个帐户属性可以一次性变更,故我们将利用一组事件标志,以免错过任何一个已发生的变化。 标志将添加到事件代码变量中。 然后应检查变量中是否存在某个标志。 根据事件代码中的标志,我们将定义帐户属性中发生的确切情况。 所有检测到的事件都将存储在数组中。 在 CEngine 类中提供了访问它的能力,稍后,会在程序里实现。
如您所见,帐户整数型属性列表还有另一个属性 — 交易服务器类型。 相应地,整数型属性的总数已从 9 更改为 10。
此帐户属性用于定义帐户是属于 MetaTrader 5 还是 MetaTrader 4。 我已决定添加该属性,因为程序会收到所连接的所有帐户列表 — 只要终端中启动的程序是基于本函数库,则 MetaTrader 5 或 MetaTrader 4 会同时在列。 该属性可令我们区分交易服务器类型。 它将通过 CAccount 类的 PrintShort() 方法在日志中显示帐户描述。 此外,我们能够按照它们所属的平台对帐户对象进行排序。
我们转到 Acount.mqh 文件。 在帐户数据结构的私有部分中添加新属性,并为存储帐户字符串型属性的数组设置确切大小:
//+------------------------------------------------------------------+ //| Account class | //+------------------------------------------------------------------+ class CAccount : public CObject { private: struct SData { //--- Account integer properties long login; // ACCOUNT_LOGIN (Account number) int trade_mode; // ACCOUNT_TRADE_MODE (Trading account type) long leverage; // ACCOUNT_LEVERAGE (Leverage) int limit_orders; // ACCOUNT_LIMIT_ORDERS (Maximum allowed number of active pending orders) int margin_so_mode; // ACCOUNT_MARGIN_SO_MODE (Mode of setting the minimum available margin level) bool trade_allowed; // ACCOUNT_TRADE_ALLOWED (Permission to trade for the current account from the server side) bool trade_expert; // ACCOUNT_TRADE_EXPERT (Permission to trade for an EA from the server side) int margin_mode; // ACCOUNT_MARGIN_MODE (Margin calculation mode) int currency_digits; // ACCOUNT_CURRENCY_DIGITS (Number of digits for an account currency) int server_type; // Trade server type (MetaTrader 5, MetaTrader 4) //--- Account real properties double balance; // ACCOUNT_BALANCE (Account balance in the deposit currency) double credit; // ACCOUNT_CREDIT (Credit in the deposit currency) double profit; // ACCOUNT_PROFIT (Current profit on an account in the deposit currency) double equity; // ACCOUNT_EQUITY (Equity on an account in the deposit currency) double margin; // ACCOUNT_MARGIN (Reserved margin on an account in the deposit currency) double margin_free; // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in the deposit currency) double margin_level; // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %) double margin_so_call; // ACCOUNT_MARGIN_SO_CALL (Margin Call level) double margin_so_so; // ACCOUNT_MARGIN_SO_SO (Stop Out level) double margin_initial; // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders) double margin_maintenance; // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions) double assets; // ACCOUNT_ASSETS (Current assets on an account) double liabilities; // ACCOUNT_LIABILITIES (Current liabilities on an account) double comission_blocked; // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account) //--- Account string properties uchar name[128]; // ACCOUNT_NAME (Client name) uchar server[64]; // ACCOUNT_SERVER (Trade server name) uchar currency[32]; // ACCOUNT_CURRENCY (Deposit currency) uchar company[128]; // ACCOUNT_COMPANY (Name of a company serving an account) }; SData m_struct_obj; // Account object structure uchar m_uchar_array[]; // uchar array of the account object structure
在类的公有部分中,添加另一个简单地访问返回的交易服务器类型的方法:
//+------------------------------------------------------------------+ //| Methods of a simplified access to the account object properties | //+------------------------------------------------------------------+ //--- Return the account's integer propertie ENUM_ACCOUNT_TRADE_MODE TradeMode(void) const { return (ENUM_ACCOUNT_TRADE_MODE)this.GetProperty(ACCOUNT_PROP_TRADE_MODE); } ENUM_ACCOUNT_STOPOUT_MODE MarginSOMode(void) const { return (ENUM_ACCOUNT_STOPOUT_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_SO_MODE); } ENUM_ACCOUNT_MARGIN_MODE MarginMode(void) const { return (ENUM_ACCOUNT_MARGIN_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_MODE); } long Login(void) const { returnthis.GetProperty(ACCOUNT_PROP_LOGIN); } long Leverage(void) const { returnthis.GetProperty(ACCOUNT_PROP_LEVERAGE); } long LimitOrders(void) const { returnthis.GetProperty(ACCOUNT_PROP_LIMIT_ORDERS); } long TradeAllowed(void) const { returnthis.GetProperty(ACCOUNT_PROP_TRADE_ALLOWED); } long TradeExpert(void) const { returnthis.GetProperty(ACCOUNT_PROP_TRADE_EXPERT); } long CurrencyDigits(void) const { returnthis.GetProperty(ACCOUNT_PROP_CURRENCY_DIGITS); } long ServerType(void) const { returnthis.GetProperty(ACCOUNT_PROP_SERVER_TYPE); }
在帐户属性描述方法中,添加另一个返回交易服务器类型描述的方法:
//+------------------------------------------------------------------+ //| Descriptions of the account object properties | //+------------------------------------------------------------------+ //--- Return the description of the account's (1) integer, (2) real and (3) string properties string GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property); string GetPropertyDescription(ENUM_ACCOUNT_PROP_DOUBLE property); string GetPropertyDescription(ENUM_ACCOUNT_PROP_STRING property); //--- Return the trading account type name (demo, contest, real) string TradeModeDescription(void) const; //--- Return the trade server type name (MetaTrader 5, MetaTrader 4) string ServerTypeDescription(void) const; //--- Return the description of the mode for setting the minimum available margin level string MarginSOModeDescription(void) const; //--- Return the description of the margin calculation mode string MarginModeDescription(void) const; //--- Display the description of the account properties in the journal (full_prop=true - all properties, false - supported ones only) void Print(constbool full_prop=false); //--- Display a short account description in the journal void PrintShort(void);
在类构造函数中,填充存储交易服务器类型的属性:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CAccount::CAccount(void) { //--- Save integer properties this.m_long_prop[ACCOUNT_PROP_LOGIN] = ::AccountInfoInteger(ACCOUNT_LOGIN); this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = ::AccountInfoInteger(ACCOUNT_TRADE_MODE); this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = ::AccountInfoInteger(ACCOUNT_LEVERAGE); this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED); this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT); this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING#endif ; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2#endif ; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4); //--- Save real properties this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)] = ::AccountInfoDouble(ACCOUNT_BALANCE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)] = ::AccountInfoDouble(ACCOUNT_CREDIT); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)] = ::AccountInfoDouble(ACCOUNT_PROFIT); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)] = ::AccountInfoDouble(ACCOUNT_EQUITY); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)] = ::AccountInfoDouble(ACCOUNT_MARGIN); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)] = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)] = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)] = ::AccountInfoDouble(ACCOUNT_ASSETS); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)] = ::AccountInfoDouble(ACCOUNT_LIABILITIES); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED); //--- Save string properties this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)] = ::AccountInfoString(ACCOUNT_NAME); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)] = ::AccountInfoString(ACCOUNT_SERVER); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)] = ::AccountInfoString(ACCOUNT_CURRENCY); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)] = ::AccountInfoString(ACCOUNT_COMPANY); } //+-------------------------------------------------------------------+
在此,只需读取终端名称即可。 如果这是 MetaTrader 5,则设置为 5,否则设置为 4。
在 ObjectToStruct() 方法里填充新属性,及创建对象结构:
//+------------------------------------------------------------------+ //| Create the account object structure | //+------------------------------------------------------------------+ bool CAccount::ObjectToStruct(void) { //--- Save the integer properties this.m_struct_obj.login=this.Login(); this.m_struct_obj.trade_mode=this.TradeMode(); this.m_struct_obj.leverage=this.Leverage(); this.m_struct_obj.limit_orders=(int)this.LimitOrders(); this.m_struct_obj.margin_so_mode=this.MarginSOMode(); this.m_struct_obj.trade_allowed=this.TradeAllowed(); this.m_struct_obj.trade_expert=this.TradeExpert(); this.m_struct_obj.margin_mode=this.MarginMode(); this.m_struct_obj.currency_digits=(int)this.CurrencyDigits(); this.m_struct_obj.server_type=(int)this.ServerType(); //--- Save the real properties this.m_struct_obj.balance=this.Balance(); this.m_struct_obj.credit=this.Credit(); this.m_struct_obj.profit=this.Profit(); this.m_struct_obj.equity=this.Equity(); this.m_struct_obj.margin=this.Margin(); this.m_struct_obj.margin_free=this.MarginFree(); this.m_struct_obj.margin_level=this.MarginLevel(); this.m_struct_obj.margin_so_call=this.MarginSOCall(); this.m_struct_obj.margin_so_so=this.MarginSOSO(); this.m_struct_obj.margin_initial=this.MarginInitial(); this.m_struct_obj.margin_maintenance=this.MarginMaintenance(); this.m_struct_obj.assets=this.Assets(); this.m_struct_obj.liabilities=this.Liabilities(); this.m_struct_obj.comission_blocked=this.ComissionBlocked(); //--- Save the string properties ::StringToCharArray(this.Name(),this.m_struct_obj.name); ::StringToCharArray(this.Server(),this.m_struct_obj.server); ::StringToCharArray(this.Currency(),this.m_struct_obj.currency); ::StringToCharArray(this.Company(),this.m_struct_obj.company); //--- Save the structure to the uchar array ::ResetLastError(); if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array)) { ::Print(DFUN,TextByLanguage("Не удалось сохранить структуру объекта в uchar-массив, ошибка ","Failed to save object structure to uchar array, error "),(string)::GetLastError()); returnfalse; } returntrue; } //+------------------------------------------------------------------+
而 StructToObject() 方法接收属性结构,并据其创建对象:
//+------------------------------------------------------------------+ //| Create the account object from the structure | //+------------------------------------------------------------------+ void CAccount::StructToObject(void) { //--- Save integer properties this.m_long_prop[ACCOUNT_PROP_LOGIN] = this.m_struct_obj.login; this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = this.m_struct_obj.trade_mode; this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = this.m_struct_obj.leverage; this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = this.m_struct_obj.limit_orders; this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = this.m_struct_obj.margin_so_mode; this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = this.m_struct_obj.trade_allowed; this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = this.m_struct_obj.trade_expert; this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = this.m_struct_obj.margin_mode; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = this.m_struct_obj.currency_digits; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = this.m_struct_obj.server_type; //--- Save real properties this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)] = this.m_struct_obj.balance; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)] = this.m_struct_obj.credit; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)] = this.m_struct_obj.profit; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)] = this.m_struct_obj.equity; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)] = this.m_struct_obj.margin; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)] = this.m_struct_obj.margin_free; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)] = this.m_struct_obj.margin_level; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)] = this.m_struct_obj.margin_so_call; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)] = this.m_struct_obj.margin_so_so; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)] = this.m_struct_obj.margin_initial; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=this.m_struct_obj.margin_maintenance; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)] = this.m_struct_obj.assets; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)] = this.m_struct_obj.liabilities; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=this.m_struct_obj.comission_blocked; //--- Save string properties this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)] = ::CharArrayToString(this.m_struct_obj.name); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)] = ::CharArrayToString(this.m_struct_obj.server); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)] = ::CharArrayToString(this.m_struct_obj.currency); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)] = ::CharArrayToString(this.m_struct_obj.company); } //+------------------------------------------------------------------+
现在,在显示帐户属性简要描述的方法中加入交易服务器类型:
//+------------------------------------------------------------------+ //| Display a short account description in the journal | //+------------------------------------------------------------------+ void CAccount::PrintShort(void) { string mode=(this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ? ", Hedge" : this.MarginMode()==ACCOUNT_MARGIN_MODE_EXCHANGE ? ", Exhange" : ""); string names=TextByLanguage("Счёт ","Account ")+(string)this.Login()+": "+this.Name()+" ("+this.Company()+" "; string values=::DoubleToString(this.Balance(),(int)this.CurrencyDigits())+" "+this.Currency()+", 1:"+(string)+this.Leverage()+mode+", "+this.TradeModeDescription()+" "+this.ServerTypeDescription()+")"; ::Print(names,values); } //+------------------------------------------------------------------+
将新属性描述添加到返回帐户整数型属性描述的方法中:
//+------------------------------------------------------------------+ //| Display a description of an account integer property | //+------------------------------------------------------------------+ string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property) { return ( property==ACCOUNT_PROP_LOGIN ? TextByLanguage("Номер счёта","Account number")+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_TRADE_MODE ? TextByLanguage("Тип торгового счета","Account trade mode")+": "+this.TradeModeDescription() : property==ACCOUNT_PROP_LEVERAGE ? TextByLanguage("Размер предоставленного плеча","Account leverage")+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_LIMIT_ORDERS ? TextByLanguage("Максимально допустимое количество действующих отложенных ордеров","Maximum allowed number of active pending orders")+": "+ (string)this.GetProperty(property) : property==ACCOUNT_PROP_MARGIN_SO_MODE ? TextByLanguage("Режим задания минимально допустимого уровня залоговых средств","Mode for setting the minimal allowed margin")+": "+ this.MarginSOModeDescription() : property==ACCOUNT_PROP_TRADE_ALLOWED ? TextByLanguage("Разрешенность торговли для текущего счета","Allowed trade for the current account")+": "+ (this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) : property==ACCOUNT_PROP_TRADE_EXPERT ? TextByLanguage("Разрешенность торговли для эксперта","Allowed trade for an Expert Advisor")+": "+ (this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) : property==ACCOUNT_PROP_MARGIN_MODE ? TextByLanguage("Режим расчета маржи","Margin calculation mode")+": "+ this.MarginModeDescription() : property==ACCOUNT_PROP_CURRENCY_DIGITS ? TextByLanguage("Количество знаков после запятой для валюты счета","Number of decimal places in account currency")+": "+ (string)this.GetProperty(property) : property==ACCOUNT_PROP_SERVER_TYPE ? TextByLanguage("Тип торгового сервера","Type of trading server")+": "+ (string)this.GetProperty(property) : "" ); } //+------------------------------------------------------------------+
实现返回交易服务器类型名称的方法:
//+------------------------------------------------------------------+ //| Return the trading server type name | //+------------------------------------------------------------------+ string CAccount::ServerTypeDescription(void) const { return(this.ServerType()==5 ? "MetaTrader5" : "MetaTrader4"); } //+------------------------------------------------------------------+
CAccount类 的改既已完毕。
现在我们介绍对帐户集合类的必要修改,因为我们决定跟踪 CAccountCollection 类中的事件。 同时发生的所有可察觉变化都将写入 int 数组。 为了实现此目的,利用标准库当中现成的 int 或 uint 类型变量的动态数组 CArrayInt 类。
若要使用它,将类文件包含在 AccountsCollection.mqh 库文件中:
//+------------------------------------------------------------------+ //| AccountsCollection.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\ArrayInt.mqh> #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Accounts\Account.mqh" //+------------------------------------------------------------------+ //| Account collection | //+------------------------------------------------------------------+ class CAccountsCollection : public CListObj {
我们来确定我们想要得到什么。 我们需要知道某些帐户属性发生变化的时刻。 可以启用或禁用属性 — 例如,允许在一般帐户上进行交易,或允许使用 EA 进行交易。 我们需要知道这个属性是否已有变化。 同样,更改 MarginCall(追加资金) 或 StopOut(爆仓) 级别可能会影响 EA 承受回撤的效果,等等。 此外,我们还需要跟踪资金的增加和减少,以及余饿,以便制定某些与 EA 相关的决策。
例如,有一定数量的持仓,我们希望在达到正或负资金时平掉其中一些持仓。 首先,我们需要设置一个特定的阈值,超过该阈值时会产生一个事件。 接下来,根据资金增长或下降是否面临高于/低于指定阈值,我们需要做出某些决断。 同样的逻辑适用于账户当前利润、余额、可用保证金和存款压力。
所以,对于某些属性,我们需要增长/下降值和当前属性值的阈值,而对于其他属性,我们只需要可以启用/禁用或变化/未变化的值。
将所有必需的类成员变量添加到类的私有部分,以便存储跟踪属性的增长/减少值,及其当前值,删除已证明是多余的 SavePrevValues() 方法,并添加初始化跟踪 和受控账户数据的方法,该方法检查账户变化,并返回一个变化代码,该方法设置事件类型,并填充事件列表,最后该方法返回存在账户事件的标志:
//--- Save the current data status values of the current account as previous ones void SavePrevValues(void) //+------------------------------------------------------------------+ //| Account collection | //+------------------------------------------------------------------+ class CAccountsCollection : public CListObj { private: struct MqlDataAccount { double hash_sum; // Account data hash sum //--- Account integer properties long login; // ACCOUNT_LOGIN (Account number) long leverage; // ACCOUNT_LEVERAGE (Leverage) int limit_orders; // ACCOUNT_LIMIT_ORDERS (Maximum allowed number of active pending orders) bool trade_allowed; // ACCOUNT_TRADE_ALLOWED (Permission to trade for the current account from the server side) bool trade_expert; // ACCOUNT_TRADE_EXPERT (Permission to trade for an EA from the server side) //--- Account real properties double balance; // ACCOUNT_BALANCE (Account balance in a deposit currency) double credit; // ACCOUNT_CREDIT (Credit in a deposit currency) double profit; // ACCOUNT_PROFIT (Current profit on an account in the account currency) double equity; // ACCOUNT_EQUITY (Equity on an account in the deposit currency) double margin; // ACCOUNT_MARGIN (Reserved margin on an account in a deposit currency) double margin_free; // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in a deposit currency) double margin_level; // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %) double margin_so_call; // ACCOUNT_MARGIN_SO_CALL (Margin Call) double margin_so_so; // ACCOUNT_MARGIN_SO_SO (Stop Out) double margin_initial; // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders) double margin_maintenance; // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions) double assets; // ACCOUNT_ASSETS (Current assets on an account) double liabilities; // ACCOUNT_LIABILITIES (Current liabilities on an account) double comission_blocked; // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account) }; MqlDataAccount m_struct_curr_account; // Account current data MqlDataAccount m_struct_prev_account; // Account previous data MqlTick m_tick; // Tick structure string m_symbol; // Current symbol long m_chart_id; // Control program chart ID CListObj m_list_accounts; // Account object list CArrayInt m_list_changes; // Account change list string m_folder_name; // Name of the folder storing the account objects int m_index_current; // Index of an account object featuring the current account data //--- Tracking account changes bool m_is_account_event; // Event flag in the account data int m_change_code; // Account change code //--- Leverage long m_changed_leverage_value; // Leverage change value bool m_is_change_leverage_inc; // Leverage increase flag bool m_is_change_leverage_dec; // Leverage decrease flag //--- Number of active pending orders int m_changed_limit_orders_value; // Change value of the maximum allowed number of active pending orders bool m_is_change_limit_orders_inc; // Increase flag of the maximum allowed number of active pending orders bool m_is_change_limit_orders_dec; // Decrease flag of the maximum allowed number of active pending orders //--- Trading on an account bool m_is_change_trade_allowed_on; // The flag allowing to trade for the current account from the server side bool m_is_change_trade_allowed_off; // The flag prohibiting trading for the current account from the server side //--- Auto trading on an account bool m_is_change_trade_expert_on; // The flag allowing to trade for an EA from the server side bool m_is_change_trade_expert_off; //The flag prohibiting trading for an EA from the server side //--- Balance double m_control_balance_inc; // Tracked balance growth value double m_control_balance_dec; // Tracked balance decrease value double m_changed_balance_value; // Balance change value bool m_is_change_balance_inc; // The flag of the balance change exceeding the growth value bool m_is_change_balance_dec; // The flag of the balance change exceeding the decrease value //--- Credit double m_changed_credit_value; // Credit change value bool m_is_change_credit_inc; // Credit increase flag bool m_is_change_credit_dec; // Credit decrease flag //--- Profit double m_control_profit_inc; // Tracked profit growth value double m_control_profit_dec; // Tracked profit decrease value double m_changed_profit_value; // Profit change value bool m_is_change_profit_inc; // The flag of the profit change exceeding the growth value bool m_is_change_profit_dec; // The flag of the profit change exceeding the decrease value //--- Funds (equity) double m_control_equity_inc; // Tracked funds growth value double m_control_equity_dec; // Tracked funds decrease value double m_changed_equity_value; // Funds change value bool m_is_change_equity_inc; // The flag of the funds change exceeding the growth value bool m_is_change_equity_dec; // The flag of the funds change exceeding the decrease value //--- Margin double m_control_margin_inc; // Tracked margin growth value double m_control_margin_dec; // Tracked margin decrease value double m_changed_margin_value; // Margin change value bool m_is_change_margin_inc; // The flag of the margin change exceeding the growth value bool m_is_change_margin_dec; // The flag of the margin change exceeding the decrease value //--- Free margin double m_control_margin_free_inc; // Tracked free margin growth value double m_control_margin_free_dec; // Tracked free margin decrease value< double m_changed_margin_free_value; // Free margin change value bool m_is_change_margin_free_inc; // The flag of the free margin change exceeding the growth value bool m_is_change_margin_free_dec; // The flag of the free margin change exceeding the decrease value //--- Margin level double m_control_margin_level_inc; // Tracked margin level growth value double m_control_margin_level_dec; // Tracked margin level decrease value double m_changed_margin_level_value; // Margin level change value bool m_is_change_margin_level_inc; // The flag of the margin level change exceeding the growth value bool m_is_change_margin_level_dec; // The flag of the margin level change exceeding the decrease value //--- Margin Call double m_changed_margin_so_call_value; // Margin Call level change value bool m_is_change_margin_so_call_inc; // Margin Call level increase value bool m_is_change_margin_so_call_dec; // Margin Call level decrease value //--- MarginStopOut double m_changed_margin_so_so_value; // Margin StopOut level change value bool m_is_change_margin_so_so_inc; // Margin StopOut level increase flag bool m_is_change_margin_so_so_dec; // Margin StopOut level decrease flag //--- Guarantee sum for pending orders double m_control_margin_initial_inc; // Tracked growth value of the reserved funds for providing the guarantee sum for pending orders double m_control_margin_initial_dec; // Tracked decrease value of the reserved funds for providing the guarantee sum for pending orders double m_changed_margin_initial_value; // The change value of the reserved funds for providing the guarantee sum for pending orders bool m_is_change_margin_initial_inc; // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the growth value bool m_is_change_margin_initial_dec; // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the decrease value //--- Guarantee sum for open positions double m_control_margin_maintenance_inc; // The tracked increase value of the funds reserved on an account to ensure a minimum amount for all open positions double m_control_margin_maintenance_dec; // The tracked decrease value of the funds reserved on an account to ensure a minimum amount for all open positions double m_changed_margin_maintenance_value; // The change value of the funds reserved on an account to ensure a minimum amount for all open positions bool m_is_change_margin_maintenance_inc; // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the growth value bool m_is_change_margin_maintenance_dec; // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the decrease value //--- Assets double m_control_assets_inc; // Tracked assets growth value double m_control_assets_dec; // Tracked assets decrease value double m_changed_assets_value; // Assets change value bool m_is_change_assets_inc; // The flag of the assets change exceeding the growth value bool m_is_change_assets_dec; // The flag of the assets change exceeding the decrease value //--- Liabilities double m_control_liabilities_inc; // Tracked liabilities growth value double m_control_liabilities_dec; // Tracked liabilities decrease value double m_changed_liabilities_value; // Liabilities change values bool m_is_change_liabilities_inc; // The flag of the liabilities change exceeding the growth value bool m_is_change_liabilities_dec; // The flag of the liabilities change exceeding the decrease value //--- Blocked commissions double m_control_comission_blocked_inc; // Tracked blocked commissions growth value double m_control_comission_blocked_dec; // Tracked blocked commissions decrease value double m_changed_comission_blocked_value; // Blocked commissions changed value bool m_is_change_comission_blocked_inc; // The flag of the tracked commissions change exceeding the growth value bool m_is_change_comission_blocked_dec; // The flag of the tracked commissions change exceeding the decrease value //--- Initialize the variables of (1) tracked, (2) controlled account data void InitChangesParams(void); void InitControlsParams(void); //--- Check account changes, return a change code int SetChangeCode(void); //--- Set an event type and fill in the event list void SetTypeEvent(void); //--- return the flag presence in the account event bool IsPresentEventFlag(constint change_code) const { return (this.m_change_code & change_code)==change_code; } //--- Write the current account data to the account object properties void SetAccountsParams(CAccount* account); //--- Check the account object presence in the collection list bool IsPresent(CAccount* account); //--- Find and return the account object index with the current account data int Index(void); public:
SavePrevValues() 方法已被证明是多余的。 当定义帐户属性变化时,我们需要立即在存储先前状态的结构里将新属性值数据写入结构。 其余属性应保持与上一次检查之前的实际变化相同。 SavePrevValues() 方法将所有帐户属性保存为先前的属性,但因此而违反了必须利用特定方法分别设置每个跟踪属性值的约定。
我们在类的实体体外部编写初始化跟踪数据的方法:
//+------------------------------------------------------------------+ //| Initialize the variables of tracked account data | //+------------------------------------------------------------------+ void CAccountsCollection::InitChangesParams(void) { //--- List and code of changes this.m_list_changes.Clear(); // Clear the change list this.m_list_changes.Sort(); // Sort the change list //--- Leverage this.m_changed_leverage_value=0; // Leverage change value this.m_is_change_leverage_inc=false; // Leverage increase flag this.m_is_change_leverage_dec=false; // Leverage decrease flag //--- Number of active pending orders this.m_changed_limit_orders_value=0; // Change value of the maximum allowed number of active pending orders this.m_is_change_limit_orders_inc=false; // Increase flag of the maximum allowed number of active pending orders this.m_is_change_limit_orders_dec=false; // Decrease flag of the maximum allowed number of active pending orders //--- Trading on an account this.m_is_change_trade_allowed_on=false; // The flag allowing to trade for the current account from the server side this.m_is_change_trade_allowed_off=false; // The flag prohibiting trading for the current account from the server side //--- Auto trading on an account this.m_is_change_trade_expert_on=false; // The flag allowing to trade for an EA from the server side this.m_is_change_trade_expert_off=false; // The flag prohibiting trading for an EA from the server side //--- Balance this.m_changed_balance_value=0; // Balance change value this.m_is_change_balance_inc=false; // The flag of the balance change exceeding the growth value this.m_is_change_balance_dec=false; // The flag of the balance change exceeding the decrease value //--- Credit this.m_changed_credit_value=0; // Credit change value this.m_is_change_credit_inc=false; // Credit increase flag this.m_is_change_credit_dec=false; // Credit decrease flag //--- Profit this.m_changed_profit_value=0; // Profit change value this.m_is_change_profit_inc=false; // The flag of the profit change exceeding the growth value this.m_is_change_profit_dec=false; // The flag of the profit change exceeding the decrease value //--- Funds this.m_changed_equity_value=0; // Funds change value this.m_is_change_equity_inc=false; // The flag of the funds change exceeding the growth value this.m_is_change_equity_dec=false; // The flag of the funds change exceeding the decrease value //--- Margin this.m_changed_margin_value=0; // Margin change value this.m_is_change_margin_inc=false; // The flag of the margin change exceeding the growth value this.m_is_change_margin_dec=false; // The flag of the margin change exceeding the decrease value //--- Free margin this.m_changed_margin_free_value=0; // Free margin change value this.m_is_change_margin_free_inc=false; // The flag of the free margin change exceeding the growth value this.m_is_change_margin_free_dec=false; // The flag of the free margin change exceeding the decrease value //--- Margin level this.m_changed_margin_level_value=0; // Margin level change value this.m_is_change_margin_level_inc=false; // The flag of the margin level change exceeding the growth value this.m_is_change_margin_level_dec=false; // The flag of the margin level change exceeding the decrease value //--- Margin Call level this.m_changed_margin_so_call_value=0; // Margin Call level change value this.m_is_change_margin_so_call_inc=false; // Margin Call level increase flag this.m_is_change_margin_so_call_dec=false; // Margin Call level decrease flag //--- Margin StopOut level this.m_changed_margin_so_so_value=0; // Margin StopOut level change value this.m_is_change_margin_so_so_inc=false; // Margin StopOut level increase flag this.m_is_change_margin_so_so_dec=false; // Margin StopOut level decrease flag //--- Guarantee sum for pending orders this.m_changed_margin_initial_value=0; // The change value of the reserved funds for providing the guarantee sum for pending orders this.m_is_change_margin_initial_inc=false; // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the growth value this.m_is_change_margin_initial_dec=false; // The flag of the reserved funds for providing the guarantee sum for pending orders exceeding the decrease value //--- Guarantee sum for open positions this.m_changed_margin_maintenance_value=0; // The change value of the funds reserved on an account to ensure a minimum amount for all open positions this.m_is_change_margin_maintenance_inc=false; // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the growth value this.m_is_change_margin_maintenance_dec=false; // The flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the decrease value //--- Assets this.m_changed_assets_value=0; // Assets change value this.m_is_change_assets_inc=false; // The flag of the assets change exceeding the growth value this.m_is_change_assets_dec=false; // The flag of the assets change exceeding the decrease value //--- Liabilities this.m_changed_liabilities_value=0; // Liabilities change value this.m_is_change_liabilities_inc=false; // The flag of the liabilities change exceeding the growth value this.m_is_change_liabilities_dec=false; // The flag of the liabilities change exceeding the decrease value //--- Blocked commissions this.m_changed_comission_blocked_value=0; // Blocked commissions change value this.m_is_change_comission_blocked_inc=false; // The flag of the tracked commissions change exceeding the growth value this.m_is_change_comission_blocked_dec=false; // The flag of the tracked commissions change exceeding the decrease value } //+------------------------------------------------------------------+
初始化受控数据的方法:
//+------------------------------------------------------------------+ //| Initialize the variables of controlled account data | //+------------------------------------------------------------------+ void CAccountsCollection::InitControlsParams(void) { //--- Balance this.m_control_balance_inc=50; // Tracked balance growth value this.m_control_balance_dec=50; // Tracked balance decrease value //--- Profit this.m_control_profit_inc=20; // Tracked profit growth value this.m_control_profit_dec=20; // Tracked profit decrease value //--- Funds (equity) this.m_control_equity_inc=15; // Tracked funds growth value this.m_control_equity_dec=15; // Tracked funds decrease value //--- Margin this.m_control_margin_inc=1000; // Tracked margin growth value this.m_control_margin_dec=1000; // Tracked margin decrease value //--- Free margin this.m_control_margin_free_inc=1000; // Tracked free margin growth value this.m_control_margin_free_dec=1000; // Tracked free margin decrease value //--- Margin level this.m_control_margin_level_inc=10000; // Tracked margin level growth value this.m_control_margin_level_dec=500; // Tracked margin level decrease value //--- Guarantee sum for pending orders this.m_control_margin_initial_inc=1000; // Tracked growth value of the reserved funds for providing the guarantee sum for pending orders this.m_control_margin_initial_dec=1000; // Tracked decrease value of the reserved funds for providing the guarantee sum for pending orders //--- Guarantee sum for open positions this.m_control_margin_maintenance_inc=1000; // The tracked increase value of the funds reserved on an account to ensure a minimum amount for all open positions this.m_control_margin_maintenance_dec=1000; // The tracked decrease value of the funds reserved on an account to ensure a minimum amount for all open positions //--- Assets this.m_control_assets_inc=1000; // Tracked assets growth value this.m_control_assets_dec=1000; // Tracked assets decrease value //--- Liabilities this.m_control_liabilities_inc=1000; // Tracked liabilities growth value this.m_control_liabilities_dec=1000; // Tracked liabilities decrease value //--- Blocked commissions this.m_control_comission_blocked_inc=1000; // Tracked blocked commissions growth value this.m_control_comission_blocked_dec=1000; // Tracked blocked commissions decrease value } //+------------------------------------------------------------------+
在此方法中,我们只是通过默认值初始化变量。 如果属性超过变量中设置的值,则会生成相应的帐户事件。 也可以通过直接调用设置受控帐户属性的相应方法来设置这些属性。
检查帐户属性的方法会更改并利用相应的标志填充事件代码:
//+------------------------------------------------------------------+ //| Check account changes, return the change code | //+------------------------------------------------------------------+ int CAccountsCollection::SetChangeCode(void) { this.m_change_code=ACCOUNT_EVENT_FLAG_NO_EVENT; if(this.m_struct_curr_account.trade_allowed!=this.m_struct_prev_account.trade_allowed) this.m_change_code+=ACCOUNT_EVENT_FLAG_TRADE_ALLOWED; if(this.m_struct_curr_account.trade_expert!=this.m_struct_prev_account.trade_expert) this.m_change_code+=ACCOUNT_EVENT_FLAG_TRADE_EXPERT; if(this.m_struct_curr_account.leverage-this.m_struct_prev_account.leverage!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_LEVERAGE; if(this.m_struct_curr_account.limit_orders-this.m_struct_prev_account.limit_orders!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_LIMIT_ORDERS; if(this.m_struct_curr_account.balance-this.m_struct_prev_account.balance!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_BALANCE; if(this.m_struct_curr_account.credit-this.m_struct_prev_account.credit!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_CREDIT; if(this.m_struct_curr_account.profit-this.m_struct_prev_account.profit!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_PROFIT; if(this.m_struct_curr_account.equity-this.m_struct_prev_account.equity!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_EQUITY; if(this.m_struct_curr_account.margin-this.m_struct_prev_account.margin!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN; if(this.m_struct_curr_account.margin_free-this.m_struct_prev_account.margin_free!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_FREE; if(this.m_struct_curr_account.margin_level-this.m_struct_prev_account.margin_level!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_LEVEL; if(this.m_struct_curr_account.margin_so_call-this.m_struct_prev_account.margin_so_call!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL; if(this.m_struct_curr_account.margin_so_so-this.m_struct_prev_account.margin_so_so!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_SO_SO; if(this.m_struct_curr_account.margin_initial-this.m_struct_prev_account.margin_initial!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_INITIAL; if(this.m_struct_curr_account.margin_maintenance-this.m_struct_prev_account.margin_maintenance!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE; if(this.m_struct_curr_account.assets-this.m_struct_prev_account.assets!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_ASSETS; if(this.m_struct_curr_account.liabilities-this.m_struct_prev_account.liabilities!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_LIABILITIES; if(this.m_struct_curr_account.comission_blocked-this.m_struct_prev_account.comission_blocked!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED; //--- returnthis.m_change_code; } //+------------------------------------------------------------------+
首先,在方法中重置事件代码。 接下来,在当前数据结构和先前数据结构中比较受控帐户参数的值。 如果数据不相似,则在事件代码中添加相应的标志。
该方法设置事件类型,并将事件添加到帐户更改列表中:
//+------------------------------------------------------------------+ //| Set the account object event type | //+------------------------------------------------------------------+ void CAccountsCollection::SetTypeEvent(void) { this.InitChangesParams(); ENUM_ACCOUNT_EVENT event=ACCOUNT_EVENT_NO_EVENT; //--- Changing permission to trade for the account if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_ALLOWED)) { if(!this.m_struct_curr_account.trade_allowed) { this.m_is_change_trade_allowed_off=true; event=ACCOUNT_EVENT_TRADE_ALLOWED_OFF; this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } else { this.m_is_change_trade_allowed_on=true; event=ACCOUNT_EVENT_TRADE_ALLOWED_ON; this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } if(this.m_list_changes.Search(event)==WRONG_VALUE) this.m_list_changes.Add(event); } //--- Changing permission for auto trading for the account if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_EXPERT)) { if(!this.m_struct_curr_account.trade_expert) { this.m_is_change_trade_expert_off=true; event=ACCOUNT_EVENT_TRADE_EXPERT_OFF; this.m_struct_prev_account.trade_expert=false; } else { this.m_is_change_trade_expert_on=true; event=ACCOUNT_EVENT_TRADE_EXPERT_ON; this.m_struct_prev_account.trade_expert=true; } if(this.m_list_changes.Search(event)==WRONG_VALUE) this.m_list_changes.Add(event); } //--- Change the leverage if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LEVERAGE)) { this.m_changed_leverage_value=this.m_struct_curr_account.leverage-this.m_struct_prev_account.leverage; if(this.m_changed_leverage_value>0) { this.m_is_change_leverage_inc=true; event=ACCOUNT_EVENT_LEVERAGE_INC; } else { this.m_is_change_leverage_dec=true; event=ACCOUNT_EVENT_LEVERAGE_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.leverage=this.m_struct_curr_account.leverage; } //--- Changing the maximum allowed number of active pending orders if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LIMIT_ORDERS)) { this.m_changed_limit_orders_value=this.m_struct_curr_account.limit_orders-this.m_struct_prev_account.limit_orders; if(this.m_changed_limit_orders_value>0) { this.m_is_change_limit_orders_inc=true; event=ACCOUNT_EVENT_LIMIT_ORDERS_INC; } else { this.m_is_change_limit_orders_dec=true; event=ACCOUNT_EVENT_LIMIT_ORDERS_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.limit_orders=this.m_struct_curr_account.limit_orders; } //--- Changing the credit in a deposit currency if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_CREDIT)) { this.m_changed_credit_value=this.m_struct_curr_account.credit-this.m_struct_prev_account.credit; if(this.m_changed_credit_value>0) { this.m_is_change_credit_inc=true; event=ACCOUNT_EVENT_CREDIT_INC; } else { this.m_is_change_credit_dec=true; event=ACCOUNT_EVENT_CREDIT_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.credit=this.m_struct_curr_account.credit; } //--- Changing the Margin Call level if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL)) { this.m_changed_margin_so_call_value=this.m_struct_curr_account.margin_so_call-this.m_struct_prev_account.margin_so_call; if(this.m_changed_margin_so_call_value>0) { this.m_is_change_margin_so_call_inc=true; event=ACCOUNT_EVENT_MARGIN_SO_CALL_INC; } else { this.m_is_change_margin_so_call_dec=true; event=ACCOUNT_EVENT_MARGIN_SO_CALL_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_so_call=this.m_struct_curr_account.margin_so_call; } //--- Changing the Stop Out level if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_SO_SO)) { this.m_changed_margin_so_so_value=this.m_struct_curr_account.margin_so_so-this.m_struct_prev_account.margin_so_so; if(this.m_changed_margin_so_so_value>0) { this.m_is_change_margin_so_so_inc=true; event=ACCOUNT_EVENT_MARGIN_SO_SO_INC; } else { this.m_is_change_margin_so_so_dec=true; event=ACCOUNT_EVENT_MARGIN_SO_SO_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_so_so=this.m_struct_curr_account.margin_so_so; } //--- The balance exceeds the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_BALANCE)) { this.m_changed_balance_value=this.m_struct_curr_account.balance-this.m_struct_prev_account.balance; if(this.m_changed_balance_value>this.m_control_balance_inc) { this.m_is_change_balance_inc=true; event=ACCOUNT_EVENT_BALANCE_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.balance=this.m_struct_curr_account.balance; } elseif(this.m_changed_balance_value<-this.m_control_balance_dec) { this.m_is_change_balance_dec=true; event=ACCOUNT_EVENT_BALANCE_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.balance=this.m_struct_curr_account.balance; } } //--- The profit exceeds the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_PROFIT)) { this.m_changed_profit_value=this.m_struct_curr_account.profit-this.m_struct_prev_account.profit; if(this.m_changed_profit_value>this.m_control_profit_inc) { this.m_is_change_profit_inc=true; event=ACCOUNT_EVENT_PROFIT_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.profit=this.m_struct_curr_account.profit; } elseif(this.m_changed_profit_value<-this.m_control_profit_dec) { this.m_is_change_profit_dec=true; event=ACCOUNT_EVENT_PROFIT_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.profit=this.m_struct_curr_account.profit; } } //--- The equity exceeds the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_EQUITY)) { this.m_changed_equity_value=this.m_struct_curr_account.equity-this.m_struct_prev_account.equity; if(this.m_changed_equity_value>this.m_control_equity_inc) { this.m_is_change_equity_inc=true; event=ACCOUNT_EVENT_EQUITY_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.equity=this.m_struct_curr_account.equity; } elseif(this.m_changed_equity_value<-this.m_control_equity_dec) { this.m_is_change_equity_dec=true; event=ACCOUNT_EVENT_EQUITY_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.equity=this.m_struct_curr_account.equity; } } //--- The reserved margin on an account in the deposit currency change exceeds the specified value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN)) { this.m_changed_margin_value=this.m_struct_curr_account.margin-this.m_struct_prev_account.margin; if(this.m_changed_margin_value>this.m_control_margin_inc) { this.m_is_change_margin_inc=true; event=ACCOUNT_EVENT_MARGIN_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin=this.m_struct_curr_account.margin; } elseif(this.m_changed_margin_value<-this.m_control_margin_dec) { this.m_is_change_margin_dec=true; event=ACCOUNT_EVENT_MARGIN_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin=this.m_struct_curr_account.margin; } } //--- The free funds available for opening a position in a deposit currency exceed the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_FREE)) { this.m_changed_margin_free_value=this.m_struct_curr_account.margin_free-this.m_struct_prev_account.margin_free; if(this.m_changed_margin_free_value>this.m_control_margin_free_inc) { this.m_is_change_margin_free_inc=true; event=ACCOUNT_EVENT_MARGIN_FREE_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_free=this.m_struct_curr_account.margin_free; } elseif(this.m_changed_margin_free_value<-this.m_control_margin_free_dec) { this.m_is_change_margin_free_dec=true; event=ACCOUNT_EVENT_MARGIN_FREE_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_free=this.m_struct_curr_account.margin_free; } } //--- The margin level on an account in % exceeds the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_LEVEL)) { this.m_changed_margin_level_value=this.m_struct_curr_account.margin_level-this.m_struct_prev_account.margin_level; if(this.m_changed_margin_level_value>this.m_control_margin_level_inc) { this.m_is_change_margin_level_inc=true; event=ACCOUNT_EVENT_MARGIN_LEVEL_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_level=this.m_struct_curr_account.margin_level; } elseif(this.m_changed_margin_level_value<-this.m_control_margin_level_dec) { this.m_is_change_margin_level_dec=true; event=ACCOUNT_EVENT_MARGIN_LEVEL_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_level=this.m_struct_curr_account.margin_level; } } //--- The funds reserved on an account to ensure a guarantee amount for all pending orders exceed the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_INITIAL)) { this.m_changed_margin_initial_value=this.m_struct_curr_account.margin_initial-this.m_struct_prev_account.margin_initial; if(this.m_changed_margin_initial_value>this.m_control_margin_initial_inc) { this.m_is_change_margin_initial_inc=true; event=ACCOUNT_EVENT_MARGIN_INITIAL_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_initial=this.m_struct_curr_account.margin_initial; } elseif(this.m_changed_margin_initial_value<-this.m_control_margin_initial_dec) { this.m_is_change_margin_initial_dec=true; event=ACCOUNT_EVENT_MARGIN_INITIAL_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_initial=this.m_struct_curr_account.margin_initial; } } //--- The funds reserved on an account to ensure a minimum amount for all open positions exceed the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE)) { this.m_changed_margin_maintenance_value=this.m_struct_curr_account.margin_maintenance-this.m_struct_prev_account.margin_maintenance; if(this.m_changed_margin_maintenance_value>this.m_control_margin_maintenance_inc) { this.m_is_change_margin_maintenance_inc=true; event=ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_maintenance=this.m_struct_curr_account.margin_maintenance; } elseif(this.m_changed_margin_maintenance_value<-this.m_control_margin_maintenance_dec) { this.m_is_change_margin_maintenance_dec=true; event=ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_maintenance=this.m_struct_curr_account.margin_maintenance; } } //--- The current assets on an account exceed the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_ASSETS)) { this.m_changed_assets_value=this.m_struct_curr_account.assets-this.m_struct_prev_account.assets; if(this.m_changed_assets_value>this.m_control_assets_inc) { this.m_is_change_assets_inc=true; event=ACCOUNT_EVENT_ASSETS_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.assets=this.m_struct_curr_account.assets; } elseif(this.m_changed_assets_value<-this.m_control_assets_dec) { this.m_is_change_assets_dec=true; event=ACCOUNT_EVENT_ASSETS_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.assets=this.m_struct_curr_account.assets; } } //--- The current liabilities on an account exceed the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LIABILITIES)) { this.m_changed_liabilities_value=this.m_struct_curr_account.liabilities-this.m_struct_prev_account.liabilities; if(this.m_changed_liabilities_value>this.m_control_liabilities_inc) { this.m_is_change_liabilities_inc=true; event=ACCOUNT_EVENT_LIABILITIES_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.liabilities=this.m_struct_curr_account.liabilities; } elseif(this.m_changed_liabilities_value<-this.m_control_liabilities_dec) { this.m_is_change_liabilities_dec=true; event=ACCOUNT_EVENT_LIABILITIES_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.liabilities=this.m_struct_curr_account.liabilities; } } //--- The current sum of blocked commissions on an account exceeds the specified change value +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED)) { this.m_changed_comission_blocked_value=this.m_struct_curr_account.comission_blocked-this.m_struct_prev_account.comission_blocked; if(this.m_changed_comission_blocked_value>this.m_control_comission_blocked_inc) { this.m_is_change_comission_blocked_inc=true; event=ACCOUNT_EVENT_COMISSION_BLOCKED_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.comission_blocked=this.m_struct_curr_account.comission_blocked; } elseif(this.m_changed_comission_blocked_value<-this.m_control_comission_blocked_dec) { this.m_is_change_comission_blocked_dec=true; event=ACCOUNT_EVENT_COMISSION_BLOCKED_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.comission_blocked=this.m_struct_curr_account.comission_blocked; } } } //+------------------------------------------------------------------+
该方法拥有两种类型的事件定义逻辑:
- 简单的属性权限/变化跟踪,
- 在增加/减少的方向上跟踪超过指定值的变化。
由于该方法非常庞大,我们将使用两种类型的帐户事件定义作为示例:
首先,重置所有变化标志和数据,并将事件类型设置为零。
接下来,对于第一种逻辑类型(使用帐户交易许可):
- 检查事件代码中帐户的交易许可标志
- 如果当前禁止交易,则权限被禁用
- 设置禁止在账户上交易的标志
- 设置“禁用帐户交易”事件
- 在以前的数据结构中保存帐户属性的当前状态以供后续检查
- 否则,如果目前允许交易
- 设置启用帐户交易的标志
- 设置“帐户启用交易”事件
- 在以前的数据结构中保存帐户属性的当前状态以供后续检查
- 如果更改列表中没有此类事件
- 将事件添加到列表中
对于第二种逻辑类型(使用累积佣金的总和作为示例):
- 检查累积佣金总和的变化标志
- 计算累积佣金总和的变化
- 如果变化值超过受控增长值
- 设置累积佣金增长总和的标志
- 设置“累积佣金增加总和超过指定值”事件
- 如果变更列表中没有此类事件,则该事件已成功添加到列表中
- 在以前的数据结构中保存帐户属性的当前状态以供后续检查
- 否则,如果变化值超过受控减少值
- 设置累积佣金总和减少的标志
- 设置“累积佣金减少总和超过指定值”事件
- 如果变更列表中没有此类事件,则该事件已成功添加到列表中
- 在以前的数据结构中保存帐户属性的当前状态以供后续检查
在类的公有部分,添加返回帐户事件代码,帐户事件列表,帐户事件 列表中的索引的方法; 设置和返回品种的方法,返回控制程序所在图表 ID 的方法,和返回帐户事件描述的方法。 另外,添加接收和设置跟踪变化参数的方法:
public: //--- Return the full account collection list "as is" CArrayObj *GetList(void) { return &this.m_list_accounts; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_ACCOUNT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);} CArrayObj *GetList(ENUM_ACCOUNT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);} CArrayObj *GetList(ENUM_ACCOUNT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);} //--- Return the (1) current account object index, (2) the flag of the event occurred in the account data, (3) event type int IndexCurrentAccount(void) const { return this.m_index_current; } bool IsAccountEvent(void) const { return this.m_is_account_event; } //--- Return the (1) object account event code, (2) event list, (3) account event by its number in the list int GetEventCode(void) const { return this.m_change_code; } CArrayInt *GetListChanges(void) { return &this.m_list_changes; } ENUM_ACCOUNT_EVENT GetEvent(constint shift=WRONG_VALUE); //--- (1) Set and (2) return the current symbol void SetSymbol(conststring symbol) { this.m_symbol=symbol; } string GetSymbol(void) const { return this.m_symbol; } //--- Set the control program chart ID void SetChartID(constlong id) { this.m_chart_id=id; } //--- Constructor, destructor CAccountsCollection(); ~CAccountsCollection(); //--- Add the account object to the list bool AddToList(CAccount* account); //--- (1) Save account objects from the list to the files //--- (2) Save account objects from the files to the list bool SaveObjects(void); bool LoadObjects(void); //--- Return the account event description string EventDescription(const ENUM_ACCOUNT_EVENT event); //--- Update the current account data void Refresh(void); //--- Get and set the parameters of tracked changes //--- Leverage: //--- (1) Leverage change value, (2) Leverage increase flag, (3) Leverage decrease flag long GetValueChangedLeverage(void) const { return this.m_changed_leverage_value; } bool IsIncreaseLeverage(void) const { return this.m_is_change_leverage_inc; } bool IsDecreaseLeverage(void) const { return this.m_is_change_leverage_dec; } //--- Number of active pending orders: //--- (1) Change value, (2) Increase flag, (3) Decrease flag int GetValueChangedLimitOrders(void) const { return this.m_changed_limit_orders_value; } bool IsIncreaseLimitOrders(void) const { return this.m_is_change_limit_orders_inc; } bool IsDecreaseLimitOrders(void) const { return this.m_is_change_limit_orders_dec; } //--- Trading on an account: //--- (1) The flag allowing to trade for the current account, (2) The flag prohibiting trading for the current account from the server side bool IsOnTradeAllowed(void) const { return this.m_is_change_trade_allowed_on; } bool IsOffTradeAllowed(void) const { return this.m_is_change_trade_allowed_off; } //--- Auto trading on an account: //--- (1) The flag allowing to trade for an EA, (2) The flag prohibiting trading for an EA from the server side bool IsOnTradeExpert(void) const { return this.m_is_change_trade_expert_on; } bool IsOffTradeExpert(void) const { return this.m_is_change_trade_expert_off; } //--- Balance: //--- setting the tracked value of the balance (1) growth, (2) decrease //--- getting (3) the balance change value, //--- getting the flag of the balance change exceeding the (4) growth value, (5) decrease value void SetControlBalanceInc(const double value) { this.m_control_balance_inc=::fabs(value); } void SetControlBalanceDec(const double value) { this.m_control_balance_dec=::fabs(value); } double GetValueChangedBalance(void) const { return this.m_changed_balance_value; } bool IsIncreaseBalance(void) const { return this.m_is_change_balance_inc; } bool IsDecreaseBalance(void) const { return this.m_is_change_balance_dec; } //--- Credit: //--- getting (1) the credit change value, (2) credit increase flag, (3) decrease flag double GetValueChangedCredit(void) const { return this.m_changed_credit_value; } bool IsIncreaseCredit(void) const { return this.m_is_change_credit_inc; } bool IsDecreaseCredit(void) const { return this.m_is_change_credit_dec; } //--- Profit: //--- setting the tracked profit (1) growth, (2) decrease value //--- getting the (3) profit change value, //--- getting the flag of the profit change exceeding the (4) growth, (5) decrease value void SetControlProfitInc(const double value) { this.m_control_profit_inc=::fabs(value); } void SetControlProfitDec(const double value) { this.m_control_profit_dec=::fabs(value); } double GetValueChangedProfit(void) const { return this.m_changed_profit_value; } bool IsIncreaseProfit(void) const { return this.m_is_change_profit_inc; } bool IsDecreaseProfit(void) const { return this.m_is_change_profit_dec; } //--- Equity: //--- setting the tracked equity (1) growth, (2) decrease value //--- getting the (3) equity change value, //--- getting the flag of the equity change exceeding the (4) growth, (5) decrease value void SetControlEquityInc(const double value) { this.m_control_equity_inc=::fabs(value); } void SetControlEquityDec(const double value) { this.m_control_equity_dec=::fabs(value); } double GetValueChangedEquity(void) const { return this.m_changed_equity_value; } bool IsIncreaseEquity(void) const { return this.m_is_change_equity_inc; } bool IsDecreaseEquity(void) const { return this.m_is_change_equity_dec; } //--- Margin: //--- setting the tracked margin (1) growth, (2) decrease value //--- getting the (3) margin change value, //--- getting the flag of the margin change exceeding the (4) growth, (5) decrease value void SetControlMarginInc(const double value) { this.m_control_margin_inc=::fabs(value); } void SetControlMarginDec(const double value) { this.m_control_margin_dec=::fabs(value); } double GetValueChangedMargin(void) const { return this.m_changed_margin_value; } bool IsIncreaseMargin(void) const { return this.m_is_change_margin_inc; } bool IsDecreaseMargin(void) const { return this.m_is_change_margin_dec; } //--- Free margin: //--- setting the tracked free margin (1) growth, (2) decrease value //--- getting the (3) free margin change value, //--- getting the flag of the free margin change exceeding the (4) growth, (5) decrease value void SetControlMarginFreeInc(const double value) { this.m_control_margin_free_inc=::fabs(value); } void SetControlMarginFreeDec(const double value) { this.m_control_margin_free_dec=::fabs(value); } double GetValueChangedMarginFree(void) const { return this.m_changed_margin_free_value; } bool IsIncreaseMarginFree(void) const { return this.m_is_change_margin_free_inc; } bool IsDecreaseMarginFree(void) const { return this.m_is_change_margin_free_dec; } //--- Margin level: //--- setting the tracked margin level (1) growth, (2) decrease value //--- getting the (3) margin level change value, //--- getting the flag of the margin level change exceeding the (4) growth, (5) decrease value void SetControlMarginLevelInc(const double value) { this.m_control_margin_level_inc=::fabs(value); } void SetControlMarginLevelDec(const double value) { this.m_control_margin_level_dec=::fabs(value); } double GetValueChangedMarginLevel(void) const { return this.m_changed_margin_level_value; } bool IsIncreaseMarginLevel(void) const { return this.m_is_change_margin_level_inc; } bool IsDecreaseMarginLevel(void) const { return this.m_is_change_margin_level_dec; } //--- Margin Call: //--- getting (1) Margin Call change value, (2) increase flag, (3) decrease flag double GetValueChangedMarginCall(void) const { return this.m_changed_margin_so_call_value; } bool IsIncreaseMarginCall(void) const { return this.m_is_change_margin_so_call_inc; } bool IsDecreaseMarginCall(void) const { return this.m_is_change_margin_so_call_dec; } //--- Margin StopOut: //--- getting (1) Margin StopOut change value, (2) increase flag, (3) decrease flag double GetValueChangedMarginStopOut(void) const { return this.m_changed_margin_so_so_value; } bool IsIncreaseMarginStopOut(void) const { return this.m_is_change_margin_so_so_inc; } bool IsDecreasMarginStopOute(void) const { return this.m_is_change_margin_so_so_dec; } //--- Guarantee sum for pending orders: //--- setting the tracked value of the reserved funds for providing the guarantee sum for pending orders (1) growth, (2) decrease //--- getting the change value of the (3) reserved funds for providing the guarantee sum, //--- getting the flag of the reserved funds for providing the guarantee sum for pending orders exceeding the (4) growth, (5) decrease value void SetControlMarginInitialInc(const double value) { this.m_control_margin_initial_inc=::fabs(value); } void SetControlMarginInitialDec(const double value) { this.m_control_margin_initial_dec=::fabs(value); } double GetValueChangedMarginInitial(void) const { return this.m_changed_margin_initial_value; } bool IsIncreaseMarginInitial(void) const { return this.m_is_change_margin_initial_inc; } bool IsDecreaseMarginInitial(void) const { return this.m_is_change_margin_initial_dec; } //--- Guarantee sum for open positions: //--- setting the tracked value of the funds reserved on an account to ensure a minimum amount for all open positions (1) growth, (2) decrease //--- getting the change value of the (3) funds reserved on an account to ensure a minimum amount for all open positions, //--- getting the flag of the funds reserved on an account to ensure a minimum amount for all open positions exceeding the (4) growth, (5) decrease value void SetControlMarginMaintenanceInc(const double value) { this.m_control_margin_maintenance_inc=::fabs(value); } void SetControlMarginMaintenanceDec(const double value) { this.m_control_margin_maintenance_dec=::fabs(value); } double GetValueChangedMarginMaintenance(void) const { return this.m_changed_margin_maintenance_value; } bool IsIncreaseMarginMaintenance(void) const { return this.m_is_change_margin_maintenance_inc; } bool IsDecreaseMarginMaintenance(void) const { return this.m_is_change_margin_maintenance_dec; } //--- Assets: //--- setting the tracked value of the assets (1) growth, (2) decrease //--- getting (3) the assets change value, //--- getting the flag of the change exceeding the (4) growth, (5) decrease value void SetControlAssetsInc(const double value) { this.m_control_assets_inc=::fabs(value); } void SetControlAssetsDec(const double value) { this.m_control_assets_dec=::fabs(value); } double GetValueChangedAssets(void) const { return this.m_changed_assets_value; } bool IsIncreaseAssets(void) const { return this.m_is_change_assets_inc; } bool IsDecreaseAssets(void) const { return this.m_is_change_assets_dec; } //--- Liabilities: //--- setting the tracked value of the liabilities (1) growth, (2) decrease //--- getting (3) the liabilities change value, //--- getting the flag of the liabilities change exceeding the (4) growth, (5) decrease value void SetControlLiabilitiesInc(const double value) { this.m_control_liabilities_inc=::fabs(value); } void SetControlLiabilitiesDec(const double value) { this.m_control_liabilities_dec=::fabs(value); } double GetValueChangedLiabilities(void) const { return this.m_changed_liabilities_value; } bool IsIncreaseLiabilities(void) const { return this.m_is_change_liabilities_inc; } bool IsDecreaseLiabilities(void) const { return this.m_is_change_liabilities_dec; } //--- Blocked commissions: //--- setting the tracked blocked commissions (1) growth, (2) decrease value //--- getting (3) the blocked commissions change value, //--- getting the flag of the tracked commissions change exceeding the (4) growth, (5) decrease value void SetControlComissionBlockedInc(const double value) { this.m_control_comission_blocked_inc=::fabs(value); } void SetControlComissionBlockedDec(const double value) { this.m_control_comission_blocked_dec=::fabs(value); } double GetValueChangedComissionBlocked(void) const { return this.m_changed_comission_blocked_value; } bool IsIncreaseComissionBlocked(void) const { return this.m_is_change_comission_blocked_inc; } bool IsDecreaseComissionBlocked(void) const { return this.m_is_change_comission_blocked_dec; } }; //+------------------------------------------------------------------+
在类的主体之外,实现按照列表中的编号返回帐户事件的方法:
//+------------------------------------------------------------------+ //| Return the account event by its number in the list | //+------------------------------------------------------------------+ ENUM_ACCOUNT_EVENT CAccountsCollection::GetEvent(constint shift=WRONG_VALUE) { int total=this.m_list_changes.Total(); if(total==0) return ACCOUNT_EVENT_NO_EVENT; int index=(shift<0 || shift>total-1 ? total-1 : total-shift-1); int event=this.m_list_changes.At(index); return ENUM_ACCOUNT_EVENT(event!=NULL ? event : ACCOUNT_EVENT_NO_EVENT); } //+------------------------------------------------------------------+
帐户属性变更列表中的事件按添加顺序排列 — 第一个位于索引 0,而最后一个位于索引(list_size-1)处。 不过,我们希望让用户按时间序列获取所需事件 — 零号索引应含最后一个事件。 为达此目的,该方法具有索引计算功能:index = (list_size - desired_event_number-1)。 在此情况下,如果我们传递 0,则返回列表中的最后一个事件; 如果是 1,那么则是最早的一个; 如果编号超过列表大小,则返回最后一个事件。
因此,将所需事件的索引传递给方法。
首先,检查列表中的事件数量。 如果没有事件,则返回“无事件”。
接下来,检查期望的事件索引。 如果传递的值小于零或超出数组大小,索引指定列表中的最后一个事件,否则,计算列表中的事件索引,根据规则:如果将 0 传递给方法,我们期望获得最后一个事件(正如在时间序列中),如果是 1 — 最早的一个,等等。 或者,如果需要获取最后一个事件,传递 -1 作为索引输入。
接下来,通过计算的索引从列表中获取事件,并将其返回。
如果未收到任何事件,则返回 NULL。 这意味着我们在处理它之前,应验证方法操作结果的有效性。
实现返回帐户事件描述的方法:
//+------------------------------------------------------------------+ //| Return an account event description | //+------------------------------------------------------------------+ string CAccountsCollection::EventDescription(const ENUM_ACCOUNT_EVENT event) { int total=this.m_list_accounts.Total(); if(total==0) return(DFUN+TextByLanguage("Ошибка. Список изменений пуст","Error. List of changes is empty")); CAccount* account=this.m_list_accounts.At(this.m_index_current); if(account==NULL) return(DFUN+TextByLanguage("Ошибка. Не удалось получить данные аккаунта","Error. Failed to get account data")); constint dg=(account.MarginSOMode()==ACCOUNT_STOPOUT_MODE_MONEY ? (int)account.CurrencyDigits() : 2); conststring curency=" "+account.Currency(); conststring mode_lev=(account.IsPercentsForSOLevels() ? "%" : " "+curency); return ( event==ACCOUNT_EVENT_NO_EVENT ? TextByLanguage("Нет события","No event") : event==ACCOUNT_EVENT_TRADE_ALLOWED_ON ? TextByLanguage("Торговля на счёте разрешена","Trading on account allowed now") : event==ACCOUNT_EVENT_TRADE_ALLOWED_OFF ? TextByLanguage("Торговля на счёте запрещена","Trading on account prohibited now") : event==ACCOUNT_EVENT_TRADE_EXPERT_ON ? TextByLanguage("Автоторговля на счёте разрешена","Autotrading on account allowed now") : event==ACCOUNT_EVENT_TRADE_EXPERT_OFF ? TextByLanguage("Автоторговля на счёте запрещена","Autotrade on account prohibited now") : event==ACCOUNT_EVENT_LEVERAGE_INC ? TextByLanguage("Плечо увеличено на ","Leverage increased by ")+(string)this.GetValueChangedLeverage()+" (1:"+(string)account.Leverage()+")" : event==ACCOUNT_EVENT_LEVERAGE_DEC ? TextByLanguage("Плечо уменьшено на ","Leverage decreased by ")+(string)this.GetValueChangedLeverage()+" (1:"+(string)account.Leverage()+")" : event==ACCOUNT_EVENT_LIMIT_ORDERS_INC ? TextByLanguage("Максимально допустимое количество действующих отложенных ордеров увеличено на","Maximum allowable number of active pending orders increased by ")+(string)this.GetValueChangedLimitOrders()+" ("+(string)account.LimitOrders()+")" : event==ACCOUNT_EVENT_LIMIT_ORDERS_DEC ? TextByLanguage("Максимально допустимое количество действующих отложенных ордеров уменьшено на","Maximum allowable number of active pending orders decreased by ")+(string)this.GetValueChangedLimitOrders()+" ("+(string)account.LimitOrders()+")" : event==ACCOUNT_EVENT_BALANCE_INC ? TextByLanguage("Баланс счёта увеличен на ","Account balance increased by ")+::DoubleToString(this.GetValueChangedBalance(),dg)+curency+" ("+::DoubleToString(account.Balance(),dg)+curency+")" : event==ACCOUNT_EVENT_BALANCE_DEC ? TextByLanguage("Баланс счёта уменьшен на ","Account balance decreased by ")+::DoubleToString(this.GetValueChangedBalance(),dg)+curency+" ("+::DoubleToString(account.Balance(),dg)+curency+")" : event==ACCOUNT_EVENT_EQUITY_INC ? TextByLanguage("Средства увеличены на ","Equity increased by ")+::DoubleToString(this.GetValueChangedEquity(),dg)+curency+" ("+::DoubleToString(account.Equity(),dg)+curency+")" : event==ACCOUNT_EVENT_EQUITY_DEC ? TextByLanguage("Средства уменьшены на ","Equity decreased by ")+::DoubleToString(this.GetValueChangedEquity(),dg)+curency+" ("+::DoubleToString(account.Equity(),dg)+curency+")" : event==ACCOUNT_EVENT_PROFIT_INC ? TextByLanguage("Текущая прибыль счёта увеличена на ","Account current profit increased by ")+::DoubleToString(this.GetValueChangedProfit(),dg)+curency+" ("+::DoubleToString(account.Profit(),dg)+curency+")" : event==ACCOUNT_EVENT_PROFIT_DEC ? TextByLanguage("Текущая прибыль счёта уменьшена на ","Account current profit decreased by ")+::DoubleToString(this.GetValueChangedProfit(),dg)+curency+" ("+::DoubleToString(account.Profit(),dg)+curency+")" : event==ACCOUNT_EVENT_CREDIT_INC ? TextByLanguage("Предоставленный кредит увеличен на ","Credit increased by ")+::DoubleToString(this.GetValueChangedCredit(),dg)+curency+" ("+::DoubleToString(account.Credit(),dg)+curency+")" : event==ACCOUNT_EVENT_CREDIT_DEC ? TextByLanguage("Предоставленный кредит уменьшен на ","Credit decreased by ")+::DoubleToString(this.GetValueChangedCredit(),dg)+curency+" ("+::DoubleToString(account.Credit(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_INC ? TextByLanguage("Залоговые средства увеличены на ","Margin increased by ")+::DoubleToString(this.GetValueChangedMargin(),dg)+curency+" ("+::DoubleToString(account.Margin(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_DEC ? TextByLanguage("Залоговые средства уменьшены на ","Margin decreased by ")+::DoubleToString(this.GetValueChangedMargin(),dg)+curency+" ("+::DoubleToString(account.Margin(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_FREE_INC ? TextByLanguage("Свободные средства увеличены на ","Free margin increased by ")+::DoubleToString(this.GetValueChangedMarginFree(),dg)+curency+" ("+::DoubleToString(account.MarginFree(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_FREE_DEC ? TextByLanguage("Свободные средства уменьшены на ","Free margin decreased by ")+::DoubleToString(this.GetValueChangedMarginFree(),dg)+curency+" ("+::DoubleToString(account.MarginFree(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_LEVEL_INC ? TextByLanguage("Уровень залоговых средств увеличен на ","Margin level increased by ")+::DoubleToString(this.GetValueChangedMarginLevel(),dg)+"%"+" ("+::DoubleToString(account.MarginLevel(),dg)+"%)" : event==ACCOUNT_EVENT_MARGIN_LEVEL_DEC ? TextByLanguage("Уровень залоговых средств уменьшен на ","Margin level decreased by ")+::DoubleToString(this.GetValueChangedMarginLevel(),dg)+"%"+" ("+::DoubleToString(account.MarginLevel(),dg)+"%)" : event==ACCOUNT_EVENT_MARGIN_INITIAL_INC ? TextByLanguage("Гарантийная сумма по отложенным ордерам увеличена на ","Guarantee sum for pending orders increased by ")+::DoubleToString(this.GetValueChangedMarginInitial(),dg)+curency+" ("+::DoubleToString(account.MarginInitial(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_INITIAL_DEC ? TextByLanguage("Гарантийная сумма по отложенным ордерам уменьшена на ","Guarantee sum for pending orders decreased by ")+::DoubleToString(this.GetValueChangedMarginInitial(),dg)+curency+" ("+::DoubleToString(account.MarginInitial(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC ? TextByLanguage("Гарантийная сумма по позициям увеличена на ","Guarantee sum for positions increased by ")+::DoubleToString(this.GetValueChangedMarginMaintenance(),dg)+curency+" ("+::DoubleToString(account.MarginMaintenance(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC ? TextByLanguage("Гарантийная сумма по позициям уменьшена на ","Guarantee sum for positions decreased by ")+::DoubleToString(this.GetValueChangedMarginMaintenance(),dg)+curency+" ("+::DoubleToString(account.MarginMaintenance(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_SO_CALL_INC ? TextByLanguage("Увеличен уровень Margin Call на ","Increased Margin Call level by ")+::DoubleToString(this.GetValueChangedMarginCall(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOCall(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_MARGIN_SO_CALL_DEC ? TextByLanguage("Уменьшен уровень Margin Call на ","Decreased Margin Call level by ")+::DoubleToString(this.GetValueChangedMarginCall(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOCall(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_MARGIN_SO_SO_INC ? TextByLanguage("Увеличен уровень Stop Out на ","Increased Margin Stop Out level by ")+::DoubleToString(this.GetValueChangedMarginStopOut(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOSO(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_MARGIN_SO_SO_DEC ? TextByLanguage("Уменьшен уровень Stop Out на ","Decreased Margin Stop Out level by ")+::DoubleToString(this.GetValueChangedMarginStopOut(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOSO(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_ASSETS_INC ? TextByLanguage("Размер активов увеличен на ","Assets increased by ")+::DoubleToString(this.GetValueChangedAssets(),dg)+" ("+::DoubleToString(account.Assets(),dg)+")" : event==ACCOUNT_EVENT_ASSETS_DEC ? TextByLanguage("Размер активов уменьшен на ","Assets decreased by ")+::DoubleToString(this.GetValueChangedAssets(),dg)+" ("+::DoubleToString(account.Assets(),dg)+")" : event==ACCOUNT_EVENT_LIABILITIES_INC ? TextByLanguage("Размер обязательств увеличен на ","Liabilities increased by ")+::DoubleToString(this.GetValueChangedLiabilities(),dg)+" ("+::DoubleToString(account.Liabilities(),dg)+")" : event==ACCOUNT_EVENT_LIABILITIES_DEC ? TextByLanguage("Размер обязательств уменьшен на ","Liabilities decreased by ")+::DoubleToString(this.GetValueChangedLiabilities(),dg)+" ("+::DoubleToString(account.Liabilities(),dg)+")" : event==ACCOUNT_EVENT_COMISSION_BLOCKED_INC ? TextByLanguage("Размер заблокированных комиссий увеличен на ","Blocked commissions increased by ")+::DoubleToString(this.GetValueChangedComissionBlocked(),dg)+" ("+::DoubleToString(account.ComissionBlocked(),dg)+")" : event==ACCOUNT_EVENT_COMISSION_BLOCKED_DEC ? TextByLanguage("Размер заблокированных комиссий уменьшен на ","Blocked commissions decreased by ")+::DoubleToString(this.GetValueChangedComissionBlocked(),dg)+" ("+::DoubleToString(account.ComissionBlocked(),dg)+")" : ::EnumToString(event) ); } //+------------------------------------------------------------------+
此处,将帐户事件传递给期望获取其描述的方法。 检查帐户对象列表的大小。 如果为空,则返回错误描述。 鉴于我们只能跟踪当前帐户的事件,我们按照当前帐户对象索引从帐户列表中获取当前帐户对象。 如果未收到任何对象,也返回错误说明。
接下来,获取所需帐户属性以便显示正确的事件描述,检查事件并返回其描述。
在类构造函数的初始化清单中,使用默认值初始化品种变量和控制程序图表 ID — 当前品种和当前图表,清除即时报价结构,我们需要定义事件时间,并 初始化可编辑的和受控的帐户参数:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CAccountsCollection::CAccountsCollection(void) : m_folder_name(DIRECTORY+"Accounts"), m_is_account_event(false), m_symbol(::Symbol()), m_chart_id(::ChartID()) { this.m_list_accounts.Clear(); this.m_list_accounts.Sort(SORT_BY_ACCOUNT_LOGIN); this.m_list_accounts.Type(COLLECTION_ACCOUNT_ID); ::ZeroMemory(this.m_struct_prev_account); ::ZeroMemory(this.m_tick); this.InitChangesParams(); this.InitControlsParams(); //--- Create the folder for storing account files ::ResetLastError(); if(!::FolderCreate(this.m_folder_name,FILE_COMMON)) Print(DFUN,TextByLanguage("Не удалось создать папку хранения файлов. Ошибка ","Could not create file storage folder. Error "),::GetLastError()); //--- Create the current account object and add it to the list CAccount* account=new CAccount(); if(account!=NULL) { if(!this.AddToList(account)) { Print(DFUN_ERR_LINE,TextByLanguage("Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию.","Error. Failed to add current account object to collection list.")); delete account; } else account.PrintShort(); } else Print(DFUN,TextByLanguage("Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта.","Error. Failed to create an account object with current account data.")); //--- Download account objects from the files to the collection this.LoadObjects(); //--- Save the current account index this.m_index_current=this.Index(); } //+------------------------------------------------------------------+
最后,将跟踪帐户变化的代码添加到更新帐户数据的方法中:
//+------------------------------------------------------------------+ //| Update the current account data | //+------------------------------------------------------------------+ void CAccountsCollection::Refresh(void) { this.m_is_account_event=false; if(this.m_index_current==WRONG_VALUE) return; CAccount* account=this.m_list_accounts.At(this.m_index_current); if(account==NULL) return; ::ZeroMemory(this.m_struct_curr_account); this.SetAccountsParams(account); //--- First launch if(!this.m_struct_prev_account.login) { this.m_struct_prev_account=this.m_struct_curr_account; return; } //--- f the account hash sum changed if(this.m_struct_curr_account.hash_sum!=this.m_struct_prev_account.hash_sum) { this.m_change_code=this.SetChangeCode(); this.SetTypeEvent(); int total=this.m_list_changes.Total(); if(total>0) { this.m_is_account_event=true; for(int i=0;i<total;i++) { ENUM_ACCOUNT_EVENT event=this.GetEvent(i); if(event==NULL || !::SymbolInfoTick(this.m_symbol,this.m_tick)) continue; string sparam=TimeMSCtoString(this.m_tick.time_msc)+": "+this.EventDescription(event); Print(sparam); ::EventChartCustom(this.m_chart_id,(ushort)event,this.m_tick.time_msc,(double)i,sparam); } } this.m_struct_prev_account.hash_sum=this.m_struct_curr_account.hash_sum; } } //+------------------------------------------------------------------+首先,重置帐户事件标志。 由于我们已经删除了 SavePrevValues() 方法,在其中添加替代代码 — 在第一次启动期间将当前数据结构保存为先前的数据。 更改哈希值时,检查并设置事件代码和发生的事件类型。
在设置事件类型的方法中,帐户属性中同时发生的所有事件都将传递到变化列表。 因此,首先检查变化列表大小。 如果它不为空,设置已发生变化标志,在循环中按照列表数据接收事件,设置其描述文本包括时间(以毫秒为单位)和事件描述,在日志中显示的临时事件描述(此功能将在以后删除,所有函数库系统消息仅在启用日志时才会显示在日志记录中),最后,利用 EventChartCustom() 将事件发送给控制程序。
在 EventChartCustom() 函数参数中,传递:
- 事件 — 至 event_id,
- 事件的毫秒时间 — 至 lparam
- 同时发生的帐户变化列表中的事件索引 — 至 dparam
- 事件的描述文本 — 至 sparam
在该方法的最后,确保将当前哈希值保存到以前的哈希值,以便进行后续验证。
CAccountsCollection 类的改进既已完毕。
我们转到 CEngine 类,此为函数库的起始和终结。 我们需要添加所有必要的功能来处理帐户事件。
在类的私有部分中,添加存储帐户属性变化事件标志和帐户上发生的最后一个事件的变量。 在公有部分,添加返回同时发生的帐户事件列表和最后一个帐户事件的方法:
//+------------------------------------------------------------------+ //| 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 CArrayObj m_list_counters; // List of timer counters 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; // Account last trading event ENUM_ACCOUNT_EVENT m_last_account_event; // Last event in account properties //--- Return the counter index by id int CounterIndex(constint id) const; //--- Return (1) the first launch flag, (2) the flag presence in a trading event bool IsFirstStart(void); //--- Working with (1) order, deal and position, as well as (2) account events void TradeEventsControl(void); void AccountEventsControl(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(constulong ticket); //--- Return the last (1) removed pending order, (2) historical market order, (3) historical order (market or pending) by its ticket COrder* GetLastHistoryPending(void); COrder* GetLastHistoryOrder(void); COrder* GetHistoryOrder(constulong 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(constulong position_id); COrder* GetLastOrderPosition(constulong 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(constulong position_id); //--- Return the list of (1) accounts, (2) account events CArrayObj* GetListAllAccounts(void) { returnthis.m_accounts.GetList(); } CArrayInt* GetListAccountEvents(void) { returnthis.m_accounts.GetListChanges(); } //--- Return the list of order, deal and position events CArrayObj* GetListAllOrdersEvents(void) { returnthis.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 { returnthis.m_last_trade_event; } ENUM_ACCOUNT_EVENT LastAccountEvent(void) const { returnthis.m_last_account_event; } bool IsHedge(void) const { returnthis.m_is_hedge; } bool IsTester(void) const { returnthis.m_is_tester; } //--- Create the timer counter void CreateCounter(constint id,constulong frequency,constulong pause); //--- Timer void OnTimer(void); //--- Constructor/Destructor CEngine(); ~CEngine(); }; //+------------------------------------------------------------------+
在类构造函数的初始化清单中添加最后一个帐户事件的初始化:
//+------------------------------------------------------------------+ //| CEngine constructor | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT),m_last_account_event(ACCOUNT_EVENT_NO_EVENT) {
添加 AccountEventsControl() 方法,该方法以前仅用来调用帐户集合类的 Refresh() 方法:
//+------------------------------------------------------------------+ //| Check account events | //+------------------------------------------------------------------+ void CEngine::AccountEventsControl(void) { //--- Check account property changes and set the flag of the account change events this.m_accounts.Refresh(); this.m_is_account_event=this.m_accounts.IsAccountEvent(); //--- If there are account property changes if(this.m_is_account_event) { //--- Get the last event of the account property change this.m_last_account_event=this.m_accounts.GetEvent(); } } //+------------------------------------------------------------------+
一切都很简单。 首先,更新帐户数据。 如果任意帐户属性有所变化,只需将最后一个事件写入变量。 在基于函数库的控制程序中检索事件的所有其余数据。
测试帐户事件
若要测试帐户事件,我们可以利用上一篇文章中的 EA,因为函数库会自行查找所有帐户属性,发送相应的消息作为图表事件,并在日志中显示已发生的帐户活动描述。
但是,我们来尝试超越函数库的“沙箱”,并在程序中处理一些帐户事件,例如增加净值。
目前,从外部访问程序功能非常有限。 但是,只有在我们收集和处理必要的数据之前才会出现这种情况 — 为了测试所创建的类,以及收集的数据和跟踪事件的正确性,函数库会在日志中显示各种事件。 进而,我们将引入更便利访问任意函数库数据的功能,来极大简化程序中的检索。
若要立即获取有关帐户属性变化的数据,需在 CEngine 类中稍作改进。 我们需要访问当前帐户对象和事件。
为此,在 CEngine 类的公有部分(Engine.mqh 文件)中添加必要的方法:
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(constulong 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);
此处我们添加了按照变化列表中的索引接收帐户事件的方法,接收当前帐户对象的方法和接收帐户事件描述的方法。
按照索引接收帐户事件的方法仅返回帐户集合类中先前描述的 GetEvent() 方法的操作结果。
在清单的最后,实现接收当前帐户对象的方法:
//+------------------------------------------------------------------+ //| Return the current account | //+------------------------------------------------------------------+ CAccount* CEngine::GetAccountCurrent(void) { int index=this.m_accounts.IndexCurrentAccount(); if(index==WRONG_VALUE) return NULL; CArrayObj* list=this.m_accounts.GetList(); return(list!=NULL ? (list.At(index)!=NULL ? list.At(index) : NULL) : NULL); } //+------------------------------------------------------------------+
首先,从帐户集合类里获取当前帐户索引。 如果未收到索引,则返回 NULL。 接下来,获取完整的帐户列表,在帐户列表中按索引返回必要的当前帐户。 若有列表或帐户错误的情况,返回 NULL。
另外,我们还要实现返回帐户事件描述的方法:
//+------------------------------------------------------------------+ //| Return the account event description | //+------------------------------------------------------------------+ string CEngine::GetAccountEventDescription(ENUM_ACCOUNT_EVENT event) { return this.m_accounts.EventDescription(event); } //+------------------------------------------------------------------+
该方法返回帐户集合类方法的操作结果,返回帐户事件描述。
若要测试帐户事件,请使用来自上一篇文章的 EA TestDoEasyPart12_2.mq5,位于 \MQL5\Experts\TestDoEasy\Part12\,并在 \MQL5\Experts\TestDoEasy\Part13 下将其另存为 TestDoEasyPart13.mq5。
立即删除以下输入
inputbool InpFullProperties = false;// Show full accounts properties
同时还有 OnInit() 处理程序中 的快速检查账户集合:
//--- Fast check of the account object collection CArrayObj* list=engine.GetListAllAccounts(); if(list!=NULL) { int total=list.Total(); if(total>0) Print("\n",TextByLanguage("=========== Список сохранённых аккаунтов ===========","=========== List of saved accounts ===========")); for(int i=0;i<total;i++) { CAccount* account=list.At(i); if(account==NULL) continue; Sleep(100); if(InpFullProperties) account.Print(); else account.PrintShort(); } } //---
由于我们更改了帐户对象结构(更改了 uchar 数组的大小以便存储帐户字符串型属性,并添加了另一个整数型属性),因此无法再正确加载所有以前保存的帐户对象文件。 如果它们出现在终端公用文件夹 \Files\DoEasy\Accounts\ 之中,请在启动测试 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; //--- Check and remove remaining EA graphical objects if(IsPresentObects(prefix)) ObjectsDeleteAll(0,prefix); //--- Create the button panel if(!CreateButtons(InpButtShiftX,InpButtShiftY)) returnINIT_FAILED; //--- Set trailing activation button status ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on); //--- 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 //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
为了处理到达程序的来自函数库的所有事件,并避免内建的 OnChartEvent() 混乱,请实现单独的 OnDoEasyEvent() 响应程序来处理其中获取的所有事件。 这会令代码更具可读性,更重要的是,它允许我们处理测试器中的事件,这正是我们现在所需要的,因为我们将处理“超过指定增长值的净值增加”帐户事件,并能更快速、更容易地检查测试器中的所有内容以实现这一目标。
我们在 OnTick() 处理程序中添加处理帐户事件所需的功能:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Initialize the last events static ENUM_TRADE_EVENT last_trade_event=WRONG_VALUE; static ENUM_ACCOUNT_EVENT last_account_event=WRONG_VALUE; //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(); PressButtonsControl(); } //--- If the last trading event changed if(engine.LastTradeEvent()!=last_trade_event) { last_trade_event=engine.LastTradeEvent(); Comment("\nLast trade event: ",EnumToString(last_trade_event)); } //--- If the last account event changed if(engine.LastAccountEvent()!=last_account_event) { last_account_event=engine.LastAccountEvent(); //--- If this is a tester if(MQLInfoInteger(MQL_TESTER)) { //--- Get the list of all account events occurred simultaneously CArrayInt* list=engine.GetListAccountEvents(); if(list!=NULL) { //--- Get the next event in a loop int total=list.Total(); for(int i=0;i<total;i++) { ENUM_ACCOUNT_EVENT event=(ENUM_ACCOUNT_EVENT)list.At(i); if(event==NULL) continue; string sparam=engine.GetAccountEventDescription(event); long lparam=TimeCurrent()*1000; double dparam=(double)i; //--- Send an event to the event handler OnDoEasyEvent(CHARTEVENT_CUSTOM+event,lparam,dparam,sparam); } } } Comment("\nLast account event: ",EnumToString(last_account_event)); } //--- If the trailing flag is set if(trailing_on) { TrailingPositions(); TrailingOrders(); } } //+------------------------------------------------------------------+
在此我们引入了存储最后一个帐户事件类型的新变量。 检查其当前状态与 CAccountsCollection 类返回的最后一个事件类型的关系。 如果状态已变化,则会发生帐户事件。 接下来,仅针对测试器,在循环中根据同时发生事件从帐户列表获取新事件,将其发送到函数库事件处理程序。 清单注释包含用于接收事件并将其发送到处理程序的所有操作。 当测试器运行时,我们无法以毫秒为单位访问事件时间的数据。 因此,只需发送当前时间 * 1000。
现在,我们改进 OnChartEvent() 事件处理程序:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(MQLInfoInteger(MQL_TESTER)) return; if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,"BUTT_")>0) { PressButtonEvents(sparam); } //--- DoEasy library event if(id>=CHARTEVENT_CUSTOM) { OnDoEasyEvent(id,lparam,dparam,sparam); } } //+------------------------------------------------------------------+
在此我们添加调用函数库事件处理程序,以防事件 ID 指向一个函数库事件。
最后,实现函数库事件处理程序:
//+------------------------------------------------------------------+ //| Handling DoEasy library events | //+------------------------------------------------------------------+ void OnDoEasyEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { int idx=id-CHARTEVENT_CUSTOM; string event="::"+string(idx); int digits=Digits(); //--- Handling trading events if(idx<TRADE_EVENTS_NEXT_CODE) { event=EnumToString((ENUM_TRADE_EVENT)ushort(idx)); digits=(int)SymbolInfoInteger(sparam,SYMBOL_DIGITS); } //--- Handling account events else if(idx<ACCOUNT_EVENTS_NEXT_CODE) { event=EnumToString((ENUM_ACCOUNT_EVENT)ushort(idx)); digits=0; //--- if this is an equity increase if((ENUM_ACCOUNT_EVENT)idx==ACCOUNT_EVENT_EQUITY_INC) { Print(DFUN,sparam); //--- Close a position with the highest profit when the equity exceeds the value //--- specified in the CAccountsCollection::InitControlsParams() method for //--- the m_control_equity_inc variable tracking the equity growth by 15 units (by default) //--- AccountCollection file, InitControlsParams() method, string 1199 //--- Get the list of all open positions CArrayObj* list_positions=engine.GetListMarketPosition(); //--- Sort the list by profit considering commission and swap list_positions.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Get the position index with the highest profit int index=CSelect::FindOrderMax(list_positions,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list_positions.At(index); if(position!=NULL) { //--- Get a ticket of a position with the highest profit and close the position by a ticket #ifdef __MQL5__ trade.PositionClose(position.Ticket()); #else PositionClose(position.Ticket(),position.Volume()); #endif } } } } } //+------------------------------------------------------------------+
将事件发送到控制程序所在图表时,在代码中添加 CHARTEVENT_CUSTOM 的值等于 1000。 所以,为了接收真正的代码,我们需要从获得的代码中减去 CHARTEVENT_CUSTOM 的值。 如果事件的代码值位于 TRADE_EVENTS_NEXT_CODE 到 ACCOUNT_EVENTS_NEXT_CODE-1 的范围内,则表示帐户属性变更事件已到达。 由于我们希望在净值增加超过设置中指定的值(默认增长值为 15 或更高)时将盈利最多的持仓平仓,我们需要检查“净值超过指定值”事件,在日志中显示事件描述,并将盈利最多的持仓平仓。 代码中已包含所有必要的注释。
如果我们现在只是在图表上启动 EA,我们将在一段时间后获得有关交易启用/禁用的日记条目:
2019.06.1010:56:33.8772019.06.1006:55:29.279: Trading on the account is prohibited now 2019.06.1011:08:56.5492019.06.1007:08:51.900: Trading on the account is allowed now
在 MetaQuotes-Demo 上,可以每天多次观察到这种启用/禁用,这样我们就可以检查函数库如何在模拟账户上定义此类事件。
现在从测试器中启动 EA,并尽可能多地开仓,以便快速检测净值增加事件,然后将盈利最多的持仓平仓:
正如我们所见,当净值超过指定值时,盈利最多的持仓会自动平仓。 日记当中显示有关所跟踪帐户事件的消息。
下一步是什么?
在下一部分中,我将开始处理品种。 我希望实现品种对象,品种对象集合和品种事件。
下面附有当前版本函数库的所有文件,以及测试 EA 文件供您测试和下载。
请在评论中留下您的问题、意见和建议。
返回目录
系列中的前几篇文章:
第一部分 概念,数据管理。
第二部分 历史订单和成交集合。
第三部分 在场订单和持仓集合,安排搜索。
第四部分 交易事件, 概念。
第五部分 交易事件类和集合。 将事件发送至程序。
第六部分 净持帐户事件。
第七部分 StopLimit 挂单激活事件,为订单和持仓修改事件准备功能。
第八部分 订单和持仓修改事件。
第九部分 与 MQL4 的兼容性 - 准备数据。
第十部分 与 MQL4 的兼容性 - 开仓和激活挂单事件。
第十一部分 与 MQL4 的兼容性 - 平仓事件。
第十二部分 帐户对象类和帐户对象集合。