轻松快捷开发 MetaTrader 程序的函数库 (第十六部分) : 品种集合事件
内容
在第十二部分中创建帐户对象和帐户集合时,以及函数库论述第十三部分中跟踪当前帐户事件时,我们观察到创建一种新型对象的必要性,其会将事件发送到 Engine 对象。
帐户事件跟踪原理与我们在第四篇及以后的文章里开始研究的跟踪交易事件的原理不同。 交易事件已经过定义,并将其发送到交易事件的集合中,以便无碍地访问以前发生的任何事件,而帐户事件只在实时操作 — “此处和现在”:事件经定义,在将其发送到函数库基准对象前,由 EventChartCustom() 发送到程序所在图表。 之后,您可以从函数库基准对象获取对同时发生事件的列表访问权,并在程序中处理它们。 这就是在帐户对象上如何安置事件的。
此处,我们可以理解,几乎每个对象天生就有某些来自一个或另一个对象的重复数量的属性,并且我们在每个新对象的开发过程中一遍又一遍地设置了这些属性的每一个。
这会导致一个难以质疑的决定 — 我们应该创建一个基准对象,所有函数库对象都将继承自该基准对象。 当前,它们是从标准库的 CObject 基准对象 继承而来的。 我们将创建另一个派生自 CObject 的对象,并在其中继承我们的函数库中的所有对象。 因此,可以在基准对象中一次性为每个对象设置所有的共有属性。 所有衍生对象都自动含有这些属性。
最有趣的是,我们现在可以创建一个事件对象,并将其写入基准对象,而所有函数库对象都可以将其事件发送给程序。 这正是我们在函数库概念中所需要的 — 对象应该能够自行告知程序其状态,而函数库或程序应能处理来自对象的相应消息,并决策(由程序),或处理对象事件(函数库) 。 这将增加函数库的交互性,并极大简化最终用户的程序开发,因为函数库将接管所有旨在处理任何对象事件的操作。
对象事件结构是通过 EventChartCustom() 函数重复发送事件 ID、长整数型、双精度型和字符串型参数所需的数据。 由于将要发送给程序的所有事件数据会在事件发生的注册期即刻填充到对象的类中,因此这简化了将事件发送给程序的过程。 我们只需要获取它,然后将其重定向到程序,以便进行进一步处理。
我们来启动开发。 首先,我们将创建事件对象,然后创建基准对象。 之后,我们将实现跟踪品种集合事件,并进行一点调整,同时牢记账户事件类的概念。 交易事件将原样保留,因为它们的结构完全不同,且与概念相冲突。 此外,它们已经完成,并将其数据发送给程序。
所有函数库对象的基准对象类
在 \MQL5\Include\DoEasy\Objects\ 函数库文件夹中,在 BaseObj.mqh 文件中创建新的类 CBaseObj。 CObject 标准库基类将用作该类的基对象。 该类很小巧,所以我将在这里展示其完整清单。 然后我们将通过其成员和方法对其进行分析。
为避免为创建一个对象事件类新文件,请在同一文件的基类之前编写该类://+------------------------------------------------------------------+ //| BaseObj.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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> #include "..\Services\DELib.mqh" //+------------------------------------------------------------------+ //| Base object event class for all library objects | //+------------------------------------------------------------------+ class CEventBaseObj : public CObject { private: long m_time; long m_chart_id; ushort m_event_id; long m_lparam; double m_dparam; string m_sparam; public: void Time(const long time) { this.m_time=time; } long Time(void) const { return this.m_time; } void ChartID(const long chart_id) { this.m_chart_id=chart_id; } long ChartID(void) const { return this.m_chart_id; } void ID(const ushort id) { this.m_event_id=id; } ushort ID(void) const { return this.m_event_id; } void LParam(const long lparam) { this.m_lparam=lparam; } long LParam(void) const { return this.m_lparam; } void DParam(const double dparam) { this.m_dparam=dparam; } double DParam(void) const { return this.m_dparam; } void SParam(const string sparam) { this.m_sparam=sparam; } string SParam(void) const { return this.m_sparam; } public: //--- Constructor CEventBaseObj(const ushort event_id,const long lparam,const double dparam,const string sparam) : m_chart_id(::ChartID()) { this.m_event_id=event_id; this.m_lparam=lparam; this.m_dparam=dparam; this.m_sparam=sparam; } //--- Comparison method to search for identical event objects virtual int Compare(const CObject *node,const int mode=0) const { const CEventBaseObj *compared=node; return ( this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : this.LParam()>compared.LParam() ? 1 : this.LParam()<compared.LParam() ? -1 : this.DParam()>compared.DParam() ? 1 : this.DParam()<compared.DParam() ? -1 : this.SParam()>compared.SParam() ? 1 : this.SParam()<compared.SParam() ? -1 : 0 ); } }; //+------------------------------------------------------------------+ //| Base object class for all library objects | //+------------------------------------------------------------------+ class CBaseObj : public CObject { private: protected: CArrayObj m_list_events; // Object event list MqlTick m_tick; // Tick structure for receiving quote data double m_hash_sum; // Object data hash sum double m_hash_sum_prev; // Object data hash sum during the previous check int m_digits_currency; // Number of decimal places in an account currency int m_global_error; // Global error code long m_chart_id; // Control program chart ID bool m_is_event; // Object event flag int m_event_code; // Object event code string m_name; // Object name string m_folder_name; // Name of the folder storing CBaseObj descendant objects //--- Return time in milliseconds from MqlTick long TickTime(void) const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;} //--- return the flag of the event code presence in the event object bool IsPresentEventFlag(const int change_code) const { return (this.m_event_code & change_code)==change_code; } //--- Return the number of decimal places of the account currency int DigitsCurrency(void) const { return this.m_digits_currency; } //--- Returns the number of decimal places in the 'double' value int GetDigits(const double value) const; //--- Initialize the variables of (1) tracked, (2) controlled object data (implementation in the descendants) virtual void InitChangesParams(void); virtual void InitControlsParams(void); //--- (1) Check the object change, return the change code, (2) set the event type and fill in the list of events (implementation in the descendants) virtual int SetEventCode(void); virtual void SetTypeEvent(void); public: //--- Add the event object to the list bool EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam); //--- Return the occurred event flag to the object data bool IsEvent(void) const { return this.m_is_event; } //--- Return (1) the list of events, (2) the object event code and (3) the global error code CArrayObj *GetListEvents(void) { return &this.m_list_events; } int GetEventCode(void) const { return this.m_event_code; } int GetError(void) const { return this.m_global_error; } //--- Return the event object by its number in the list CEventBaseObj *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true); //--- Return the number of object events int GetEventsTotal(void) const { return this.m_list_events.Total(); } //--- (1) Set and (2) return the chart ID of the control program void SetChartID(const long id) { this.m_chart_id=id; } long GetChartID(void) const { return this.m_chart_id; } //--- (1) Set the sub-folder name, (2) return the folder name for storing descendant object files void SetSubFolderName(const string name) { this.m_folder_name=DIRECTORY+name; } string GetFolderName(void) const { return this.m_folder_name; } //--- Return the object name string GetName(void) const { return this.m_name; } //--- Update the object data (implementation in the descendants) virtual void Refresh(void); //--- Constructor CBaseObj(); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CBaseObj::CBaseObj() : m_global_error(ERR_SUCCESS), m_hash_sum(0),m_hash_sum_prev(0), m_is_event(false),m_event_code(0), m_chart_id(::ChartID()), m_folder_name(DIRECTORY), m_name("") { ::ZeroMemory(this.m_tick); this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif); this.m_list_events.Clear(); this.m_list_events.Sort(); } //+------------------------------------------------------------------+ //| Add the event object to the list | //+------------------------------------------------------------------+ bool CBaseObj::EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam) { CEventBaseObj *event=new CEventBaseObj(event_id,lparam,dparam,sparam); if(event==NULL) return false; this.m_list_events.Sort(); if(this.m_list_events.Search(event)>WRONG_VALUE) { delete event; return false; } return this.m_list_events.Add(event); } //+------------------------------------------------------------------+ //| Return the object event by its index in the list | //+------------------------------------------------------------------+ CEventBaseObj *CBaseObj::GetEvent(const int shift=WRONG_VALUE,const bool check_out=true) { int total=this.m_list_events.Total(); if(total==0 || (!check_out && shift>total-1)) return NULL; int index=(shift<=0 ? total-1 : shift>total-1 ? 0 : total-shift-1); CEventBaseObj *event=this.m_list_events.At(index); return(event!=NULL ? event : NULL); } //+------------------------------------------------------------------+ //| Return the number of decimal places in the 'double' value | //+------------------------------------------------------------------+ int CBaseObj::GetDigits(const double value) const { string val_str=(string)value; int len=::StringLen(val_str); int n=len-::StringFind(val_str,".",0)-1; if(::StringSubstr(val_str,len-1,1)=="0") n--; return n; } //+------------------------------------------------------------------+
我们看一下基准对象事件类。
在基准对象事件类的私密部分中,声明存储所有事件属性的类成员变量:
private: long m_time; long m_chart_id; ushort m_event_id; long m_lparam; double m_dparam; string m_sparam;
事件时间,发送事件的所在图表 ID,事件 ID,事件的 长整数型、双精度型和字符串型数值会传递给控制程序所在的图表。
大多数这些变量的数值都会传递给类构造函数:
//--- Constructor CEventBaseObj(const ushort event_id,const long lparam,const double dparam,const string sparam) : m_chart_id(::ChartID()) { this.m_event_id=event_id; this.m_lparam=lparam; this.m_dparam=dparam; this.m_sparam=sparam; }
在其中会为它们分配数值。
此外,在类初始化清单中,图表 ID 变量接收当前图表 ID。
比较两个对象事件类的方法:
//--- Comparison method to search for identical event objects virtual int Compare(const CObject *node,const int mode=0) const { const CEventBaseObj *compared=node; return ( this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : this.LParam()>compared.LParam() ? 1 : this.LParam()<compared.LParam() ? -1 : this.DParam()>compared.DParam() ? 1 : this.DParam()<compared.DParam() ? -1 : this.SParam()>compared.SParam() ? 1 : this.SParam()<compared.SParam() ? -1 : 0 ); }
逐个元素的比较两个类的所有字段(当前那个和通过指针传递给方法的那个)。 如果所有字段都相等,则该方法返回 0,由于这些对象存储在 CArrayObj 清单中,因此在标准库指针的动态列表中搜索同一对象是必需的,而其 Search() 方法用来在列表中搜索相似对象:
//+------------------------------------------------------------------+ //| Search of position of element in a sorted array | //+------------------------------------------------------------------+ int CArrayObj::Search(const CObject *element) const { int pos; //--- check if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) return(-1); //--- search pos=QuickSearch(element); if(m_data[pos].Compare(element,m_sort_mode)==0) return(pos); //--- not found return(-1); } //+------------------------------------------------------------------+
在对象中需要存在的 Compare() 虚方法。 如果两个对象的所有属性都匹配,则方法返回 0。
在类的公开部分中,声明用于设置和返回所有对象属性的方法:
public: void Time(const long time) { this.m_time=time; } long Time(void) const { return this.m_time; } void ChartID(const long chart_id) { this.m_chart_id=chart_id; } long ChartID(void) const { return this.m_chart_id; } void ID(const ushort id) { this.m_event_id=id; } ushort ID(void) const { return this.m_event_id; } void LParam(const long lparam) { this.m_lparam=lparam; } long LParam(void) const { return this.m_lparam; } void DParam(const double dparam) { this.m_dparam=dparam; } double DParam(void) const { return this.m_dparam; } void SParam(const string sparam) { this.m_sparam=sparam; } string SParam(void) const { return this.m_sparam; }
所有这些内容都很清楚,故无需注释。 这是完整的对象事件类。
我们研究所有函数库对象的基准对象类。
在类的受保护部分中,我们声明了处理先前对象时已经遇到的类成员变量:
protected: CArrayObj m_list_events; // Object event list MqlTick m_tick; // Tick structure for receiving quote data double m_hash_sum; // Object data hash sum double m_hash_sum_prev; // Object data hash sum during the previous check int m_digits_currency; // Number of decimal places in an account currency int m_global_error; // Global error code long m_chart_id; // Control program chart ID bool m_is_event; // Object event flag int m_event_code; // Object event code string m_name; // Object name string m_folder_name; // Name of the folder storing CBaseObj descendant objects
- 对象事件列表 m_list_events 用于存储我们上面所研究事件类的对象。 该对象可能一次有几个事件,因此我们需要定义所有事件,并将它们放在列表中。 这将令我们能够从 CEngine 函数库主对象中提取所有事件的列表,并进行处理。
- m_tick 即时报价的结构用于获取价格和事件时间。
- m_hash_sum哈希值是定义对象属性发生变化所必需的。
通过比较当前和以前的(m_hash_sum_prev)哈希总和来定义对象属性的变化。 - m_digits_currency 是帐户币种的小数位数,对于正确显示某些事件的货币值数据变化是必需的。
- 当任何函数发生错误时返回的错误代码将被写入 m_global_error 全局错误代码。 此代码将传递给调用程序以便进行进一步处理。
- 控制程序所在图表 ID m_chart_id 用于指定对象事件发送到的图表。
- m_is_event 是必需要有的对象事件标志,用于通知程序发生对象事件,以便及时对该事件做出反应。
- m_event_code 对象事件编号存储所有同时发生的事件的标志。 这些标志的存在令我们可以定义同时发生的对象事件的列表。
- m_name 是必需要有的对象名称,用于通知程序,并从其接收事件对象的某些文本属性。 例如,对于帐户,这是帐号+客户名称+服务器名称,而对于品种,则为品种名称。
- 为了将对象保存到文件中,m_folder_name 必需填写存储目标文件的文件夹名:此处,同类型目标文件应存储在同名的子文件夹之中。
子文件夹的基准目录是所有客户机终端的公用文件目录 + 函数库文件夹名称:“DoEasy\\”。 在函数库论述的 第十二部分中,我们已经讨论了在创建帐户集合时存储文件的方法。
我们已在函数库对象中创建了所有这些属性,并在对象相对应的各种函数库论述部分中对它们进行了讨论。 现在,我们将它们置于一个类中 — 所有函数库对象的基准对象是 CBaseObj,从衍生对象类中剔除这些类成员的定义(请参见附件)。
我们来看一下位于类的私密部分的方法:
//--- Return time in milliseconds from MqlTick long TickTime(void) const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;} //--- return the flag of the event code presence in the event object bool IsPresentEventFlag(const int change_code) const { return (this.m_event_code & change_code)==change_code; } //--- Return the number of decimal places of the account currency int DigitsCurrency(void) const { return this.m_digits_currency; } //--- Returns the number of decimal places in the 'double' value int GetDigits(const double value) const; //--- Initialize the variables of (1) tracked, (2) controlled object data (implementation in the descendants) virtual void InitChangesParams(void); virtual void InitControlsParams(void); //--- (1) Check the object change, return the change code, (2) set the event type and fill in the list of events (implementation in the descendants) virtual int SetEventCode(void); virtual void SetTypeEvent(void);
- TickTime() 方法返回事件时间,以毫秒为单位。 对于 MQL4,由于结构中没有毫秒,所以返回以秒 * 1000 为单位的时间
- IsPresentEventFlag() 方法返回 m_event_code 变量中是否存在某些事件代码。
- DigitsCurrency() 方法从 m_digits_currency 变量返回帐户货币值中的小数位数。
- GetDigits() 方法计算并返回传递给它的双精度值中的小数位数。
- InitChangesParams() 虚方法初始化所有可编辑对象属性的参数。
- InitControlsParams() 虚方法初始化跟踪对象属性的参数。
- SetEventCode() 虚方法检查对象属性中的变化,并返回发生变化的编号。
- SetTypeEvent() 虚方法根据事件编号设置发生的事件类型,并将所有事件放入对象事件列表。
所有这些方法均已在前面的文章开发完毕。 所以,在次没有必要对其进行阐述。 我只想澄清一下,所有虚方法在这里都不做任何事情,应该在基准对象衍生类中实现。
在类的公开部分中声明了以下方法:
public: //--- Add the event object to the list bool EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam); //--- Return the occurred event flag to the object data bool IsEvent(void) const { return this.m_is_event; } //--- Return (1) the list of events, (2) the object event code and (3) the global error code CArrayObj *GetListEvents(void) { return &this.m_list_events; } int GetEventCode(void) const { return this.m_event_code; } int GetError(void) const { return this.m_global_error; } //--- Return the event object by its number in the list CEventBaseObj *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true); //--- Return the number of object events int GetEventsTotal(void) const { return this.m_list_events.Total(); } //--- (1) Set and (2) return the chart ID of the control program void SetChartID(const long id) { this.m_chart_id=id; } long GetChartID(void) const { return this.m_chart_id; } //--- (1) Set the sub-folder name, (2) return the folder name for storing descendant object files void SetSubFolderName(const string name) { this.m_folder_name=DIRECTORY+name; } string GetFolderName(void) const { return this.m_folder_name; } //--- Return the object name string GetName(void) const { return this.m_name; } //--- Update the object data (implementation in the descendants) virtual void Refresh(void);
在类构造函数的初始化清单中,为成员变量分配初始值:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CBaseObj::CBaseObj() : m_global_error(ERR_SUCCESS), m_hash_sum(0),m_hash_sum_prev(0), m_is_event(false),m_event_code(0), m_chart_id(::ChartID()), m_folder_name(DIRECTORY), m_name("") { ::ZeroMemory(this.m_tick); this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif); this.m_list_events.Clear(); this.m_list_events.Sort(); } //+------------------------------------------------------------------+
然后将即时报价结构置零,帐户货币的小数位数赋值,清除事件列表,并为对象事件列表设置已排序列表标志。
将事件添加到列表的方法:
//+------------------------------------------------------------------+ //| Add the event object to the list | //+------------------------------------------------------------------+ bool CBaseObj::EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam) { CEventBaseObj *event=new CEventBaseObj(event_id,lparam,dparam,sparam); if(event==NULL) return false; this.m_list_events.Sort(); if(this.m_list_events.Search(event)>WRONG_VALUE) { delete event; return false; } return this.m_list_events.Add(event); } //+------------------------------------------------------------------+
事件 ID,以及事件属性的长整数型、双精度型和字符串型值被传递给该方法。 然后依据这些参数创建一个新事件。 如果列表中已经存在相同的事件,则事件对象和方法将返回 false,否则方法将事件对象添加到列表中,并返回结果。
该方法通过列表中的索引返回事件对象:
//+------------------------------------------------------------------+ //| Return the object event by its index in the list | //+------------------------------------------------------------------+ CEventBaseObj *CBaseObj::GetEvent(const int shift=WRONG_VALUE,const bool check_out=true) { int total=this.m_list_events.Total(); if(total==0 || (!check_out && shift>total-1)) return NULL; int index=(shift<=0 ? total-1 : shift>total-1 ? 0 : total-shift-1); CEventBaseObj *event=this.m_list_events.At(index); return(event!=NULL ? event : NULL); } //+------------------------------------------------------------------+
我们之前已研究过该方法。 在此,我们仅添加了当索引值超出列表时,必须检查并调整索引的标志。 默认情况下,将索引 - 1 传递给该方法,并检查是否超出列表。 在此情况下,该方法从列表中返回最近发生的事件对象。 若要通过其索引获取对象,我们要将所需的索引传递给该方法,并超界检查标志设置为 false。 在这种情况下,将返回一个对象(或列表中的索引)。 如果索引超出列表界外,则返回 NULL。
在双精度值中返回小数位数的方法之前也曾研究过了:
//+------------------------------------------------------------------+ //| Return the number of decimal places in the 'double' value | //+------------------------------------------------------------------+ int CBaseObj::GetDigits(const double value) const { string val_str=(string)value; int len=::StringLen(val_str); int n=len-::StringFind(val_str,".",0)-1; if(::StringSubstr(val_str,len-1,1)=="0") n--; return n; } //+------------------------------------------------------------------+
新的基准对象已准备就绪。
现在,我们只需在每个函数库基准对象中将 CObject 基类替换为 CBaseObj。 这些对象是:
CAccount 类对象:
//+------------------------------------------------------------------+ //| Account class | //+------------------------------------------------------------------+ class CAccount : public CBaseObj {
CSymbol 类对象:
//+------------------------------------------------------------------+ //| Abstract symbol class | //+------------------------------------------------------------------+ class CSymbol : public CBaseObj {
集合类还含有常规对象属性:
交易事件集合:
//+------------------------------------------------------------------+ //| Collection of account trading events | //+------------------------------------------------------------------+ class CEventsCollection : public CBaseObj {
账户集合:
//+------------------------------------------------------------------+ //| Account collection | //+------------------------------------------------------------------+ class CAccountsCollection : public CBaseObj {
品种集合:
//+------------------------------------------------------------------+ //| Symbol collection | //+------------------------------------------------------------------+ class CSymbolsCollection : public CBaseObj {
现在,所有基于 CBaseObj 的对象都有一些相似的属性集合,我们不必为每个新创建的对象重新设置它们。 甚或,我们现在可以为所有对象添加类似的任何属性,并在此基准对象的基础上创建属性。 最有趣的是,每个对象现在都含有用于处理事件的工具。 每个对象事件都拥有相同的参数集,可将事件发送到程序所在图表的 EventChartCustom() 函数。 至此,我们极大简化了新对象的进一步开发,且现有对象得以改进。
现在,我们准备创建品种集合事件。
品种集合事件
与往常一样,所有操作都从常量和枚举的定义开始。 打开 Defines.mqh 文件,并添加跟踪品种事件所需的数据。
由于品种应出现在“市场观察”窗口中才可操控它们,而此窗口中的品种数量有限,
在品种参数中添加指示可同时在“市场观察”窗口里就位的最大品种数量的宏替换:
//--- Symbol parameters #define CLR_DEFAULT (0xFF000000) // Default color #define SYMBOLS_COMMON_TOTAL (1000) // Total number of working symbols
从数据操控部分中移走品种操控模式的枚举
//+------------------------------------------------------------------+ //| Data for working with symbols | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+
移至 Datas.mqh 文件:
//+------------------------------------------------------------------+ //| Datas.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" //+------------------------------------------------------------------+ //| Enumerations | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+ //| Data sets | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Major Forex symbols | //+------------------------------------------------------------------+ string DataSymbolsFXMajors[]= {
该数据不仅对于函数库而言,且对于基于函数库的程序都是必需的,这一事实促成了该决定。 该枚举更多地涉及一般的程序数据,而非函数库。 例如,数据将与许多其他枚举一起用作程序输入,这意味着它将被转换成必要的编译语言(稍后将实现)。 所以,将其放在 Datas.mqh 当中。
从 Defines.mqh 中移出可替换为 添加含有品种事件标志列表的枚举和含有可能的品种事件列表的枚举:
//+------------------------------------------------------------------+ //| Data for working with symbols | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| List of symbol event flags | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_EVENT_FLAGS { SYMBOL_EVENT_FLAG_NO_EVENT = 0, // No event SYMBOL_EVENT_FLAG_TRADE_MODE = 1, // Change order execution permissions SYMBOL_EVENT_FLAG_SESSION_DEALS = 2, // Change the number of deals in the current session SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS = 4, // Change the total number of the current buy orders SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS = 8, // Change the total number of the current sell orders SYMBOL_EVENT_FLAG_VOLUME = 16, // Change in the last deal volume exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY = 32, // Change of the maximum volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY = 64, // Change of the minimum volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SPREAD = 128, // Change of a spread exceeds the specified change value in +/- SYMBOL_EVENT_FLAG_STOPLEVEL = 256, // Change of a Stop order level exceeds the specified value in +/- SYMBOL_EVENT_FLAG_FREEZELEVEL = 512, // Change of the freeze level exceeds the specified value in +/- SYMBOL_EVENT_FLAG_BID_LAST = 1024, // Change of the Bid or Last price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_BID_LAST_HIGH = 2048, // Change of the maximum Bid or Last price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_BID_LAST_LOW = 4096, // Change of the minimum Bid or Last price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_ASK = 8192, // Change of the Ask price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_ASK_HIGH = 16384, // Change of the maximum Ask price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_ASK_LOW = 32768, // Change of the minimum Ask price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY = 65536, // Change of the real volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY = 131072, // Change of the maximum real volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY = 262144, // Change of the minimum real volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_OPTION_STRIKE = 524288, // Change of the strike price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_LIMIT = 1048576, // Change of the maximum available total position volume and pending orders in one direction SYMBOL_EVENT_FLAG_SWAP_LONG = 2097152, // Change swap long SYMBOL_EVENT_FLAG_SWAP_SHORT = 4194304, // Change swap short SYMBOL_EVENT_FLAG_SESSION_VOLUME = 8388608, // Change of the total volume of deals in the current session exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_TURNOVER = 16777216, // Change of the total turnover in the current session exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_INTEREST = 33554432, // Change of the total volume of open positions in the current session exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME = 67108864, // Change of the total volume of buy orders exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME = 134217728, // Change of the total volume of sell orders exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_OPEN = 268435456, // Change of the session open price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_CLOSE = 536870912, // Change of the session close price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_AW = 1073741824 // Change of the average weighted session price exceeds the specified value in +/- }; //+------------------------------------------------------------------+ //| List of possible symbol events | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_EVENT { SYMBOL_EVENT_NO_EVENT = ACCOUNT_EVENTS_NEXT_CODE, // No event SYMBOL_EVENT_MW_ADD, // Adding a symbol to the Market Watch window SYMBOL_EVENT_MW_DEL, // Removing a symbol from the Market Watch window SYMBOL_EVENT_MW_SORT, // Sorting symbols in the Market Watch window SYMBOL_EVENT_TRADE_DISABLE, // Disable order execution SYMBOL_EVENT_TRADE_LONGONLY, // Allow buy only SYMBOL_EVENT_TRADE_SHORTONLY, // Allow sell only SYMBOL_EVENT_TRADE_CLOSEONLY, // Enable close only SYMBOL_EVENT_TRADE_FULL, // No trading limitations SYMBOL_EVENT_SESSION_DEALS_INC, // The increase in the number of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_DEALS_DEC, // The decrease in the number of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORDERS_INC, // The increase in the total number of buy orders currently exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORDERS_DEC, // The decrease in the total number of buy orders currently exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORDERS_INC, // The increase in the total number of sell orders currently exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORDERS_DEC, // The decrease in the total number of sell orders currently exceeds the specified value SYMBOL_EVENT_VOLUME_INC, // Volume increase in the last deal exceeds the specified value SYMBOL_EVENT_VOLUME_DEC, // Volume decrease in the last deal exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_DAY_INC, // The increase in the maximum volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_DAY_DEC, // The decrease in the maximum volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_DAY_INC, // The increase in the minimum volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_DAY_DEC, // The decrease in the minimum volume per day exceeds the specified value SYMBOL_EVENT_SPREAD_INC, // The increase in a spread exceeds the specified change SYMBOL_EVENT_SPREAD_DEC, // The decrease in a spread exceeds the specified change SYMBOL_EVENT_STOPLEVEL_INC, // The increase of a Stop order level exceeds the specified value SYMBOL_EVENT_STOPLEVEL_DEC, // The decrease of a Stop order level exceeds the specified value SYMBOL_EVENT_FREEZELEVEL_INC, // The increase in the freeze level exceeds the specified value SYMBOL_EVENT_FREEZELEVEL_DEC, // The decrease in the freeze level exceeds the specified value SYMBOL_EVENT_BID_LAST_INC, // The increase in the Bid or Last price exceeds the specified value SYMBOL_EVENT_BID_LAST_DEC, // The decrease in the Bid or Last price exceeds the specified value SYMBOL_EVENT_BID_LAST_HIGH_INC, // The increase in the maximum Bid or Last price per day exceeds the specified value SYMBOL_EVENT_BID_LAST_HIGH_DEC, // The decrease in the maximum Bid or Last price per day exceeds the specified value relative to the specified price SYMBOL_EVENT_BID_LAST_LOW_INC, // The increase in the minimum Bid or Last price per day exceeds the specified value relative to the specified price SYMBOL_EVENT_BID_LAST_LOW_DEC, // The decrease in the minimum Bid or Last price per day exceeds the specified value SYMBOL_EVENT_ASK_INC, // The increase in the Ask price exceeds the specified value SYMBOL_EVENT_ASK_DEC, // The decrease in the Ask price exceeds the specified value SYMBOL_EVENT_ASK_HIGH_INC, // The increase in the maximum Ask price per day exceeds the specified value SYMBOL_EVENT_ASK_HIGH_DEC, // The decrease in the maximum Ask price per day exceeds the specified value SYMBOL_EVENT_ASK_LOW_INC, // The increase in the minimum Ask price per day exceeds the specified value SYMBOL_EVENT_ASK_LOW_DEC, // The decrease in the minimum Ask price per day exceeds the specified value SYMBOL_EVENT_VOLUME_REAL_DAY_INC, // The increase in the real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_REAL_DAY_DEC, // The decrease in the real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_INC, // The increase in the maximum real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_DEC, // The decrease in the maximum real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_INC, // The increase in the minimum real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_DEC, // The decrease in the minimum real volume per day exceeds the specified value SYMBOL_EVENT_OPTION_STRIKE_INC, // The increase in the strike price exceeds the specified value SYMBOL_EVENT_OPTION_STRIKE_DEC, // The decrease in the strike price exceeds the specified value SYMBOL_EVENT_VOLUME_LIMIT_INC, // The increase in the maximum available total position volume and pending orders in one direction SYMBOL_EVENT_VOLUME_LIMIT_DEC, // The decrease in the maximum available total position volume and pending orders in one direction SYMBOL_EVENT_SWAP_LONG_INC, // The increase in the swap long SYMBOL_EVENT_SWAP_LONG_DEC, // The decrease in the swap long SYMBOL_EVENT_SWAP_SHORT_INC, // The increase in the swap short SYMBOL_EVENT_SWAP_SHORT_DEC, // The decrease in the swap short SYMBOL_EVENT_SESSION_VOLUME_INC, // The increase in the total volume of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_VOLUME_DEC, // The decrease in the total volume of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_TURNOVER_INC, // The increase in the total turnover in the current session exceeds the specified value SYMBOL_EVENT_SESSION_TURNOVER_DEC, // The decrease in the total turnover in the current session exceeds the specified value SYMBOL_EVENT_SESSION_INTEREST_INC, // The increase in the total volume of open positions in the current session exceeds the specified value SYMBOL_EVENT_SESSION_INTEREST_DEC, // The decrease in the total volume of open positions in the current session exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_INC, // The increase in the total volume of buy orders exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_DEC, // The decrease in the total volume of buy orders exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_INC, // The increase in the total volume of sell orders exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_DEC, // The decrease in the total volume of sell orders exceeds the specified value SYMBOL_EVENT_SESSION_OPEN_INC, // The increase in the session open price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_OPEN_DEC, // The decrease in the session open price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_CLOSE_INC, // The increase in the session close price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_CLOSE_DEC, // The decrease in the session close price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_AW_INC, // The increase in the average weighted session price exceeds the specified value SYMBOL_EVENT_SESSION_AW_DEC, // The decrease in the average weighted session price exceeds the specified value }; #define SYMBOL_EVENTS_NEXT_CODE (SYMBOL_EVENT_SESSION_AW_DEC+1) // The code of the next event after the last symbol event code //+------------------------------------------------------------------+
这里的所有操作都类似于标志枚举,以及可能的帐户和交易事件。 我们已在函数论述的第四部分中研究了事件标志和事件 ID。
若要按品种在“市场观察”窗口中的位置进行排序,添加另一个整数型品种属性:
//+------------------------------------------------------------------+ //| Symbol integer properties | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_PROP_INTEGER { SYMBOL_PROP_STATUS = 0, // Symbol status SYMBOL_PROP_INDEX_MW, // Symbol index in the Market Watch window SYMBOL_PROP_CUSTOM, // Custom symbol flag SYMBOL_PROP_CHART_MODE, // The price type used for generating bars – Bid or Last (from the ENUM_SYMBOL_CHART_MODE enumeration) SYMBOL_PROP_EXIST, // Flag indicating that the symbol under this name exists SYMBOL_PROP_SELECT, // The indication that the symbol is selected in Market Watch SYMBOL_PROP_VISIBLE, // The indication that the symbol is displayed in Market Watch SYMBOL_PROP_SESSION_DEALS, // The number of deals in the current session SYMBOL_PROP_SESSION_BUY_ORDERS, // The total number of Buy orders at the moment SYMBOL_PROP_SESSION_SELL_ORDERS, // The total number of Sell orders at the moment SYMBOL_PROP_VOLUME, // Last deal volume SYMBOL_PROP_VOLUMEHIGH, // Maximum volume within a day SYMBOL_PROP_VOLUMELOW, // Minimum volume within a day SYMBOL_PROP_TIME, // Latest quote time SYMBOL_PROP_DIGITS, // Number of decimal places SYMBOL_PROP_DIGITS_LOTS, // Number of decimal places for a lot SYMBOL_PROP_SPREAD, // Spread in points SYMBOL_PROP_SPREAD_FLOAT, // Floating spread flag SYMBOL_PROP_TICKS_BOOKDEPTH, // Maximum number of orders displayed in the Depth of Market SYMBOL_PROP_TRADE_CALC_MODE, // Contract price calculation method (from the ENUM_SYMBOL_CALC_MODE enumeration) SYMBOL_PROP_TRADE_MODE, // Order execution type (from the ENUM_SYMBOL_TRADE_MODE enumeration) SYMBOL_PROP_START_TIME, // Symbol trading start date (usually used for futures) SYMBOL_PROP_EXPIRATION_TIME, // Symbol trading end date (usually used for futures) SYMBOL_PROP_TRADE_STOPS_LEVEL, // Minimum distance in points from the current close price for setting Stop orders SYMBOL_PROP_TRADE_FREEZE_LEVEL, // Freeze distance for trading operations (in points) SYMBOL_PROP_TRADE_EXEMODE, // Deal execution mode (from the ENUM_SYMBOL_TRADE_EXECUTION enumeration) SYMBOL_PROP_SWAP_MODE, // Swap calculation model (from the ENUM_SYMBOL_SWAP_MODE enumeration) SYMBOL_PROP_SWAP_ROLLOVER3DAYS, // Triple-day swap (from the ENUM_DAY_OF_WEEK enumeration) SYMBOL_PROP_MARGIN_HEDGED_USE_LEG, // Calculating hedging margin using the larger leg (Buy or Sell) SYMBOL_PROP_EXPIRATION_MODE, // Flags of allowed order expiration modes SYMBOL_PROP_FILLING_MODE, // Flags of allowed order filling modes SYMBOL_PROP_ORDER_MODE, // Flags of allowed order types SYMBOL_PROP_ORDER_GTC_MODE, // Expiration of Stop Loss and Take Profit orders if SYMBOL_EXPIRATION_MODE=SYMBOL_EXPIRATION_GTC (from the ENUM_SYMBOL_ORDER_GTC_MODE enumeration) SYMBOL_PROP_OPTION_MODE, // Option type (from the ENUM_SYMBOL_OPTION_MODE enumeration) SYMBOL_PROP_OPTION_RIGHT, // Option right (Call/Put) (from the ENUM_SYMBOL_OPTION_RIGHT enumeration) //--- skipped property SYMBOL_PROP_BACKGROUND_COLOR // The color of the background used for the symbol in Market Watch }; #define SYMBOL_PROP_INTEGER_TOTAL (36) // Total number of integer properties #define SYMBOL_PROP_INTEGER_SKIP (1) // Number of symbol integer properties not used in sorting //+------------------------------------------------------------------+
由于我们已经添加了新属性,我们应将整数型属性的总数增加到 36 ,替换掉 35。
最后,将新属性添加到可能的品种排序条件列表:
//+------------------------------------------------------------------+ //| Possible symbol sorting criteria | //+------------------------------------------------------------------+ #define FIRST_SYM_DBL_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP) #define FIRST_SYM_STR_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP+SYMBOL_PROP_DOUBLE_TOTAL-SYMBOL_PROP_DOUBLE_SKIP) enum ENUM_SORT_SYMBOLS_MODE { //--- Sort by integer properties SORT_BY_SYMBOL_STATUS = 0, // Sort by symbol status SORT_BY_SYMBOL_INDEX_MW, // Sort by index in the Market Watch window SORT_BY_SYMBOL_CUSTOM, // Sort by custom symbol property SORT_BY_SYMBOL_CHART_MODE, // Sort by price type for constructing bars – Bid or Last (from the ENUM_SYMBOL_CHART_MODE enumeration) SORT_BY_SYMBOL_EXIST, // Sort by the flag that a symbol with such a name exists SORT_BY_SYMBOL_SELECT, // Sort by the flag indicating that a symbol is selected in Market Watch SORT_BY_SYMBOL_VISIBLE, // Sort by the flag indicating that a selected symbol is displayed in Market Watch SORT_BY_SYMBOL_SESSION_DEALS, // Sort by the number of deals in the current session SORT_BY_SYMBOL_SESSION_BUY_ORDERS, // Sort by the total number of current buy orders SORT_BY_SYMBOL_SESSION_SELL_ORDERS, // Sort by the total number of current sell orders SORT_BY_SYMBOL_VOLUME, // Sort by last deal volume SORT_BY_SYMBOL_VOLUMEHIGH, // Sort by maximum volume for a day SORT_BY_SYMBOL_VOLUMELOW, // Sort by minimum volume for a day SORT_BY_SYMBOL_TIME, // Sort by the last quote time SORT_BY_SYMBOL_DIGITS, // Sort by a number of decimal places SORT_BY_SYMBOL_DIGITS_LOT, // Sort by a number of decimal places in a lot SORT_BY_SYMBOL_SPREAD, // Sort by spread in points SORT_BY_SYMBOL_SPREAD_FLOAT, // Sort by floating spread SORT_BY_SYMBOL_TICKS_BOOKDEPTH, // Sort by a maximum number of requests displayed in the market depth SORT_BY_SYMBOL_TRADE_CALC_MODE, // Sort by contract price calculation method (from the ENUM_SYMBOL_CALC_MODE enumeration) SORT_BY_SYMBOL_TRADE_MODE, // Sort by order execution type (from the ENUM_SYMBOL_TRADE_MODE enumeration) SORT_BY_SYMBOL_START_TIME, // Sort by an instrument trading start date (usually used for futures) SORT_BY_SYMBOL_EXPIRATION_TIME, // Sort by an instrument trading end date (usually used for futures) SORT_BY_SYMBOL_TRADE_STOPS_LEVEL, // Sort by the minimum indent from the current close price (in points) for setting Stop orders SORT_BY_SYMBOL_TRADE_FREEZE_LEVEL, // Sort by trade operation freeze distance (in points) SORT_BY_SYMBOL_TRADE_EXEMODE, // Sort by trade execution mode (from the ENUM_SYMBOL_TRADE_EXECUTION enumeration) SORT_BY_SYMBOL_SWAP_MODE, // Sort by swap calculation model (from the ENUM_SYMBOL_SWAP_MODE enumeration) SORT_BY_SYMBOL_SWAP_ROLLOVER3DAYS, // Sort by week day for accruing a triple swap (from the ENUM_DAY_OF_WEEK enumeration) SORT_BY_SYMBOL_MARGIN_HEDGED_USE_LEG, // Sort by the calculation mode of a hedged margin using the larger leg (Buy or Sell) SORT_BY_SYMBOL_EXPIRATION_MODE, // Sort by flags of allowed order expiration modes SORT_BY_SYMBOL_FILLING_MODE, // Sort by flags of allowed order filling modes SORT_BY_SYMBOL_ORDER_MODE, // Sort by flags of allowed order types SORT_BY_SYMBOL_ORDER_GTC_MODE, // Sort by StopLoss and TakeProfit orders lifetime SORT_BY_SYMBOL_OPTION_MODE, // Sort by option type (from the ENUM_SYMBOL_OPTION_MODE enumeration) SORT_BY_SYMBOL_OPTION_RIGHT, // Sort by option right (Call/Put) (from the ENUM_SYMBOL_OPTION_RIGHT enumeration) //--- Sort by real properties SORT_BY_SYMBOL_BID = FIRST_SYM_DBL_PROP, // Sort by Bid SORT_BY_SYMBOL_BIDHIGH, // Sort by maximum Bid for a day SORT_BY_SYMBOL_BIDLOW, // Sort by minimum Bid for a day SORT_BY_SYMBOL_ASK, // Sort by Ask SORT_BY_SYMBOL_ASKHIGH, // Sort by maximum Ask for a day SORT_BY_SYMBOL_ASKLOW, // Sort by minimum Ask for a day SORT_BY_SYMBOL_LAST, // Sort by the last deal price SORT_BY_SYMBOL_LASTHIGH, // Sort by maximum Last for a day SORT_BY_SYMBOL_LASTLOW, // Sort by minimum Last for a day SORT_BY_SYMBOL_VOLUME_REAL, // Sort by Volume for a day SORT_BY_SYMBOL_VOLUMEHIGH_REAL, // Sort by maximum Volume for a day SORT_BY_SYMBOL_VOLUMELOW_REAL, // Sort by minimum Volume for a day SORT_BY_SYMBOL_OPTION_STRIKE, // Sort by an option execution price SORT_BY_SYMBOL_POINT, // Sort by a single point value SORT_BY_SYMBOL_TRADE_TICK_VALUE, // Sort by SYMBOL_TRADE_TICK_VALUE_PROFIT value SORT_BY_SYMBOL_TRADE_TICK_VALUE_PROFIT, // Sort by a calculated tick price for a profitable position SORT_BY_SYMBOL_TRADE_TICK_VALUE_LOSS, // Sort by a calculated tick price for a loss-making position SORT_BY_SYMBOL_TRADE_TICK_SIZE, // Sort by a minimum price change SORT_BY_SYMBOL_TRADE_CONTRACT_SIZE, // Sort by a trading contract size SORT_BY_SYMBOL_TRADE_ACCRUED_INTEREST, // Sort by accrued interest SORT_BY_SYMBOL_TRADE_FACE_VALUE, // Sort by face value SORT_BY_SYMBOL_TRADE_LIQUIDITY_RATE, // Sort by liquidity rate SORT_BY_SYMBOL_VOLUME_MIN, // Sort by a minimum volume for performing a deal SORT_BY_SYMBOL_VOLUME_MAX, // Sort by a maximum volume for performing a deal SORT_BY_SYMBOL_VOLUME_STEP, // Sort by a minimum volume change step for deal execution SORT_BY_SYMBOL_VOLUME_LIMIT, // Sort by a maximum allowed aggregate volume of an open position and pending orders in one direction SORT_BY_SYMBOL_SWAP_LONG, // Sort by a long swap value SORT_BY_SYMBOL_SWAP_SHORT, // Sort by a short swap value SORT_BY_SYMBOL_MARGIN_INITIAL, // Sort by an initial margin SORT_BY_SYMBOL_MARGIN_MAINTENANCE, // Sort by a maintenance margin for an instrument SORT_BY_SYMBOL_MARGIN_LONG_INITIAL, // Sort by initial margin requirement applicable to Long orders SORT_BY_SYMBOL_MARGIN_BUY_STOP_INITIAL, // Sort by initial margin requirement applicable to BuyStop orders SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_INITIAL, // Sort by initial margin requirement applicable to BuyLimit orders SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_INITIAL, // Sort by initial margin requirement applicable to BuyStopLimit orders SORT_BY_SYMBOL_MARGIN_LONG_MAINTENANCE, // Sort by maintenance margin requirement applicable to Long orders SORT_BY_SYMBOL_MARGIN_BUY_STOP_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyStop orders SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyLimit orders SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyStopLimit orders SORT_BY_SYMBOL_MARGIN_SHORT_INITIAL, // Sort by initial margin requirement applicable to Short orders SORT_BY_SYMBOL_MARGIN_SELL_STOP_INITIAL, // Sort by initial margin requirement applicable to SellStop orders SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_INITIAL, // Sort by initial margin requirement applicable to SellLimit orders SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_INITIAL, // Sort by initial margin requirement applicable to SellStopLimit orders SORT_BY_SYMBOL_MARGIN_SHORT_MAINTENANCE, // Sort by maintenance margin requirement applicable to Short orders SORT_BY_SYMBOL_MARGIN_SELL_STOP_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellStop orders SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellLimit orders SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellStopLimit orders SORT_BY_SYMBOL_SESSION_VOLUME, // Sort by summary volume of the current session deals SORT_BY_SYMBOL_SESSION_TURNOVER, // Sort by the summary turnover of the current session SORT_BY_SYMBOL_SESSION_INTEREST, // Sort by the summary open interest SORT_BY_SYMBOL_SESSION_BUY_ORDERS_VOLUME, // Sort by the current volume of Buy orders SORT_BY_SYMBOL_SESSION_SELL_ORDERS_VOLUME, // Sort by the current volume of Sell orders SORT_BY_SYMBOL_SESSION_OPEN, // Sort by a session Open price SORT_BY_SYMBOL_SESSION_CLOSE, // Sort by a session Close price SORT_BY_SYMBOL_SESSION_AW, // Sort by an average weighted price of the current session SORT_BY_SYMBOL_SESSION_PRICE_SETTLEMENT, // Sort by a settlement price of the current session SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MIN, // Sort by a minimum price of the current session SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MAX, // Sort by a maximum price of the current session SORT_BY_SYMBOL_MARGIN_HEDGED, // Sort by a contract size or a margin value per one lot of hedged positions //--- Sort by string properties SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP, // Sort by a symbol name SORT_BY_SYMBOL_BASIS, // Sort by an underlying asset of a derivative SORT_BY_SYMBOL_CURRENCY_BASE, // Sort by a base currency of a symbol SORT_BY_SYMBOL_CURRENCY_PROFIT, // Sort by a profit currency SORT_BY_SYMBOL_CURRENCY_MARGIN, // Sort by a margin currency SORT_BY_SYMBOL_BANK, // Sort by a feeder of the current quote SORT_BY_SYMBOL_DESCRIPTION, // Sort by a symbol string description SORT_BY_SYMBOL_FORMULA, // Sort by the formula used for custom symbol pricing SORT_BY_SYMBOL_ISIN, // Sort by the name of a symbol in the ISIN system SORT_BY_SYMBOL_PAGE, // Sort by an address of the web page containing symbol information SORT_BY_SYMBOL_PATH // Sort by a path in the symbol tree }; //+------------------------------------------------------------------+
我们完成了Defines.mqh 文件的修改。
现在我们需要改进品种对象类。 由于我们将跟踪某些品种属性的变化,因此我们需要将它们的当前值与之前值进行比较,即可是绝对值比较,亦或检测某个预定阈值的递增。 为此,我们需要创建品种属性的结构,并拿当前值结构的字段与先前值结构的字段进行比较。 在实现跟踪帐户事件时,我们已讨论对象事件定义的逻辑。 除了基准对象已拥有的存储事件,并将事件发送到程序的方法之外,在此我们将执行相同的操作。
将基准对象文件与 CSymbol 类关联。 在类的私秘部分中,创建跟踪品种属性的结构,并声明该结构的两个变量,以便存储当前和之前的品种状态属性:
//+------------------------------------------------------------------+ //| Symbol.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" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\BaseObj.mqh" //+------------------------------------------------------------------+ //| Abstract symbol class | //+------------------------------------------------------------------+ class CSymbol : public CBaseObj { private: struct MqlDataSymbol { //--- Symbol integer properties ENUM_SYMBOL_TRADE_MODE trade_mode; // SYMBOL_TRADE_MODE Order filling modes long session_deals; // SYMBOL_SESSION_DEALS The number of deals in the current session long session_buy_orders; // SYMBOL_SESSION_BUY_ORDERS The total number of current buy orders long session_sell_orders; // SYMBOL_SESSION_SELL_ORDERS The total number of current sell orders long volume; // SYMBOL_VOLUME Last deal volume long volume_high_day; // SYMBOL_VOLUMEHIGH Maximum volume within a day long volume_low_day; // SYMBOL_VOLUMELOW Minimum volume within a day int spread; // SYMBOL_SPREAD Spread in points int stops_level; // SYMBOL_TRADE_STOPS_LEVEL Minimum distance in points from the current close price for setting Stop orders int freeze_level; // SYMBOL_TRADE_FREEZE_LEVEL Freeze distance for trading operations (in points) //--- Symbol real properties double bid_last; // SYMBOL_BID/SYMBOL_LAST Bid - the best sell offer/Last deal price double bid_last_high; // SYMBOL_BIDHIGH/SYMBOL_LASTHIGH Maximum Bid within the day/Maximum Last per day double bid_last_low; // SYMBOL_BIDLOW/SYMBOL_LASTLOW Minimum Bid within the day/Minimum Last per day double ask; // SYMBOL_ASK Ask - nest buy offer double ask_high; // SYMBOL_ASKHIGH Maximum Ask of the day double ask_low; // SYMBOL_ASKLOW Minimum Ask of the day double volume_real_day; // SYMBOL_VOLUME_REAL Real Volume of the day double volume_high_real_day; // SYMBOL_VOLUMEHIGH_REAL Maximum real Volume of the day double volume_low_real_day; // SYMBOL_VOLUMELOW_REAL Minimum real Volume of the day double option_strike; // SYMBOL_OPTION_STRIKE Strike price double volume_limit; // SYMBOL_VOLUME_LIMIT Maximum permissible total volume for a position and pending orders in one direction double swap_long; // SYMBOL_SWAP_LONG Long swap value double swap_short; // SYMBOL_SWAP_SHORT Short swap value double session_volume; // SYMBOL_SESSION_VOLUME The total volume of deals in the current session double session_turnover; // SYMBOL_SESSION_TURNOVER The total turnover in the current session double session_interest; // SYMBOL_SESSION_INTEREST The total volume of open positions double session_buy_ord_volume; // SYMBOL_SESSION_BUY_ORDERS_VOLUME The total volume of Buy orders at the moment double session_sell_ord_volume; // SYMBOL_SESSION_SELL_ORDERS_VOLUME The total volume of Sell orders at the moment double session_open; // SYMBOL_SESSION_OPEN Session open price double session_close; // SYMBOL_SESSION_CLOSE Session close price double session_aw; // SYMBOL_SESSION_AW The average weighted price of the session }; MqlDataSymbol m_struct_curr_symbol; // Current symbol data MqlDataSymbol m_struct_prev_symbol; // Previous symbol data //---
接下来,声明用于存储指定受控属性变化值、已发生的变化值和指示是否存在跟踪事件标志的类成员变量:
//--- Execution bool m_is_change_trade_mode; // Flag of changing trading mode for a symbol //--- Current session deals long m_control_session_deals_inc; // Controlled value of the growth of the number of deals long m_control_session_deals_dec; // Controlled value of the decrease in the number of deals long m_changed_session_deals_value; // Value of change in the number of deals bool m_is_change_session_deals_inc; // Flag of a change in the number of deals exceeding the growth value bool m_is_change_session_deals_dec; // Flag of a change in the number of deals exceeding the decrease value //--- Buy orders of the current session long m_control_session_buy_ord_inc; // Controlled value of the growth of the number of Buy orders long m_control_session_buy_ord_dec; // Controlled value of the decrease in the number of Buy orders long m_changed_session_buy_ord_value; // Buy orders change value bool m_is_change_session_buy_ord_inc; // Flag of a change in the number of Buy orders exceeding the growth value bool m_is_change_session_buy_ord_dec; // Flag of a change in the number of Buy orders being less than the growth value //--- Sell orders of the current session long m_control_session_sell_ord_inc; // Controlled value of the growth of the number of Sell orders long m_control_session_sell_ord_dec; // Controlled value of the decrease in the number of Sell orders long m_changed_session_sell_ord_value; // Sell orders change value bool m_is_change_session_sell_ord_inc; // Flag of a change in the number of Sell orders exceeding the growth value bool m_is_change_session_sell_ord_dec; // Flag of a change in the number of Sell orders exceeding the decrease value //--- Volume of the last deal long m_control_volume_inc; // Controlled value of the volume growth in the last deal long m_control_volume_dec; // Controlled value of the volume decrease in the last deal long m_changed_volume_value; // Value of the volume change in the last deal bool m_is_change_volume_inc; // Flag of the volume change in the last deal exceeding the growth value bool m_is_change_volume_dec; // Flag of the volume change in the last deal being less than the growth value //--- Maximum volume within a day long m_control_volume_high_day_inc; // Controlled value of the maximum volume growth for a day long m_control_volume_high_day_dec; // Controlled value of the maximum volume decrease for a day long m_changed_volume_high_day_value; // Maximum volume change value within a day bool m_is_change_volume_high_day_inc; // Flag of the maximum day volume exceeding the growth value bool m_is_change_volume_high_day_dec; // Flag of the maximum day volume exceeding the decrease value //--- Minimum volume within a day long m_control_volume_low_day_inc; // Controlled value of the minimum volume growth for a day long m_control_volume_low_day_dec; // Controlled value of the minimum volume decrease for a day long m_changed_volume_low_day_value; // Minimum volume change value within a day bool m_is_change_volume_low_day_inc; // Flag of the minimum day volume exceeding the growth value bool m_is_change_volume_low_day_dec; // Flag of the minimum day volume exceeding the decrease value //--- Spread int m_control_spread_inc; // Controlled spread growth value in points int m_control_spread_dec; // Controlled spread decrease value in points int m_changed_spread_value; // Spread change value in points bool m_is_change_spread_inc; // Flag of spread change in points exceeding the growth value bool m_is_change_spread_dec; // Flag of spread change in points exceeding the decrease value //--- StopLevel int m_control_stops_level_inc; // Controlled StopLevel growth value in points int m_control_stops_level_dec; // Controlled StopLevel decrease value in points int m_changed_stops_level_value; // StopLevel change value in points bool m_is_change_stops_level_inc; // Flag of StopLevel change in points exceeding the growth value bool m_is_change_stops_level_dec; // Flag of StopLevel change in points exceeding the decrease value //--- Freeze distance int m_control_freeze_level_inc; // Controlled FreezeLevel growth value in points int m_control_freeze_level_dec; // Controlled FreezeLevel decrease value in points int m_changed_freeze_level_value; // FreezeLevel change value in points bool m_is_change_freeze_level_inc; // Flag of FreezeLevel change in points exceeding the growth value bool m_is_change_freeze_level_dec; // Flag of FreezeLevel change in points exceeding the decrease value //--- Bid/Last double m_control_bid_last_inc; // Controlled value of Bid or Last price growth double m_control_bid_last_dec; // Controlled value of Bid or Last price decrease double m_changed_bid_last_value; // Bid or Last price change value bool m_is_change_bid_last_inc; // Flag of Bid or Last price change exceeding the growth value bool m_is_change_bid_last_dec; // Flag of Bid or Last price change exceeding the decrease value //--- Maximum Bid/Last of the day double m_control_bid_last_high_inc; // Controlled growth value of the maximum Bid or Last price of the day double m_control_bid_last_high_dec; // Controlled decrease value of the maximum Bid or Last price of the day double m_changed_bid_last_high_value; // Maximum Bid or Last change value for the day bool m_is_change_bid_last_high_inc; // Flag of the maximum Bid or Last price change for the day exceeding the growth value bool m_is_change_bid_last_high_dec; // Flag of the maximum Bid or Last price change for the day exceeding the decrease value //--- Minimum Bid/Last of the day double m_control_bid_last_low_inc; // Controlled growth value of the minimum Bid or Last price of the day double m_control_bid_last_low_dec; // Controlled decrease value of the minimum Bid or Last price of the day double m_changed_bid_last_low_value; // Minimum Bid or Last change value for the day bool m_is_change_bid_last_low_inc; // Flag of the minimum Bid or Last price change for the day exceeding the growth value bool m_is_change_bid_last_low_dec; // Flag of the minimum Bid or Last price change for the day exceeding the decrease value //--- Ask double m_control_ask_inc; // Controlled value of the Ask price growth double m_control_ask_dec; // Controlled value of the Ask price decrease double m_changed_ask_value; // Ask price change value bool m_is_change_ask_inc; // Flag of the Ask price change exceeding the growth value bool m_is_change_ask_dec; // Flag of the Ask price change exceeding the decrease value //--- Maximum Ask price for the day double m_control_ask_high_inc; // Controlled growth value of the maximum Ask price of the day double m_control_ask_high_dec; // Controlled decrease value of the maximum Ask price of the day double m_changed_ask_high_value; // Maximum Ask price change value for the day bool m_is_change_ask_high_inc; // Flag of the maximum Ask price change for the day exceeding the growth value bool m_is_change_ask_high_dec; // Flag of the maximum Ask price change for the day exceeding the decrease value //--- Minimum Ask price for the day double m_control_ask_low_inc; // Controlled growth value of the minimum Ask price of the day double m_control_ask_low_dec; // Controlled decrease value of the minimum Ask price of the day double m_changed_ask_low_value; // Minimum Ask price change value for the day bool m_is_change_ask_low_inc; // Flag of the minimum Ask price change for the day exceeding the growth value bool m_is_change_ask_low_dec; // Flag of the minimum Ask price change for the day exceeding the decrease value //--- Real Volume for the day double m_control_volume_real_inc; // Controlled value of the real volume growth of the day double m_control_volume_real_dec; // Controlled value of the real volume decrease of the day double m_changed_volume_real_value; // Real volume change value of the day bool m_is_change_volume_real_inc; // Flag of the real volume change for the day exceeding the growth value bool m_is_change_volume_real_dec; // Flag of the real volume change for the day exceeding the decrease value //--- Maximum real volume for the day double m_control_volume_high_real_day_inc; // Controlled value of the maximum real volume growth of the day double m_control_volume_high_real_day_dec; // Controlled value of the maximum real volume decrease of the day double m_changed_volume_high_real_day_value; // Maximum real volume change value of the day bool m_is_change_volume_high_real_day_inc; // Flag of the maximum real volume change for the day exceeding the growth value bool m_is_change_volume_high_real_day_dec; // Flag of the maximum real volume change for the day exceeding the decrease value //--- Minimum real volume for the day double m_control_volume_low_real_day_inc; // Controlled value of the minimum real volume growth of the day double m_control_volume_low_real_day_dec; // Controlled value of the minimum real volume decrease of the day double m_changed_volume_low_real_day_value; // Minimum real volume change value of the day bool m_is_change_volume_low_real_day_inc; // Flag of the minimum real volume change for the day exceeding the growth value bool m_is_change_volume_low_real_day_dec; // Flag of the minimum real volume change for the day exceeding the decrease value //--- Strike price double m_control_option_strike_inc; // Controlled value of the strike price growth double m_control_option_strike_dec; // Controlled value of the strike price decrease double m_changed_option_strike_value; // Strike price change value bool m_is_change_option_strike_inc; // Flag of the strike price change exceeding the growth value bool m_is_change_option_strike_dec; // Flag of the strike price change exceeding the decrease value //--- Total volume of positions and orders double m_changed_volume_limit_value; // Minimum total volume change value bool m_is_change_volume_limit_inc; // Flag of the minimum total volume increase bool m_is_change_volume_limit_dec; // Flag of the minimum total volume decrease //--- Swap long double m_changed_swap_long_value; // Swap long change value bool m_is_change_swap_long_inc; // Flag of the swap long increase bool m_is_change_swap_long_dec; // Flag of the swap long decrease //--- Swap short double m_changed_swap_short_value; // Swap short change value bool m_is_change_swap_short_inc; // Flag of the swap short increase bool m_is_change_swap_short_dec; // Flag of the swap short decrease //--- The total volume of deals in the current session double m_control_session_volume_inc; // Controlled value of the total trade volume growth in the current session double m_control_session_volume_dec; // Controlled value of the total trade volume decrease in the current session double m_changed_session_volume_value; // The total deal volume change value in the current session bool m_is_change_session_volume_inc; // Flag of total trade volume change in the current session exceeding the growth value bool m_is_change_session_volume_dec; // Flag of total trade volume change in the current session exceeding the decrease value //--- The total turnover in the current session double m_control_session_turnover_inc; // Controlled value of the total turnover growth in the current session double m_control_session_turnover_dec; // Controlled value of the total turnover decrease in the current session double m_changed_session_turnover_value; // Total turnover change value in the current session bool m_is_change_session_turnover_inc; // Flag of total turnover change in the current session exceeding the growth value bool m_is_change_session_turnover_dec; // Flag of total turnover change in the current session exceeding the decrease value //--- The total volume of open positions double m_control_session_interest_inc; // Controlled value of the total open position volume growth in the current session double m_control_session_interest_dec; // Controlled value of the total open position volume decrease in the current session double m_changed_session_interest_value; // Change value of the open positions total volume in the current session bool m_is_change_session_interest_inc; // Flag of total open positions' volume change in the current session exceeding the growth value bool m_is_change_session_interest_dec; // Flag of total open positions' volume change in the current session exceeding the decrease value //--- The total volume of Buy orders at the moment double m_control_session_buy_ord_volume_inc; // Controlled value of the current total buy order volume growth double m_control_session_buy_ord_volume_dec; // Controlled value of the current total buy order volume decrease double m_changed_session_buy_ord_volume_value; // Change value of the current total buy order volume bool m_is_change_session_buy_ord_volume_inc; // Flag of changing the current total buy orders volume exceeding the growth value bool m_is_change_session_buy_ord_volume_dec; // Flag of changing the current total buy orders volume exceeding the decrease value //--- The total volume of Sell orders at the moment double m_control_session_sell_ord_volume_inc; // Controlled value of the current total sell order volume growth double m_control_session_sell_ord_volume_dec; // Controlled value of the current total sell order volume decrease double m_changed_session_sell_ord_volume_value; // Change value of the current total sell order volume bool m_is_change_session_sell_ord_volume_inc; // Flag of changing the current total sell orders volume exceeding the growth value bool m_is_change_session_sell_ord_volume_dec; // Flag of changing the current total sell orders volume exceeding the decrease value //--- Session open price double m_control_session_open_inc; // Controlled value of the session open price growth double m_control_session_open_dec; // Controlled value of the session open price decrease double m_changed_session_open_value; // Session open price change value bool m_is_change_session_open_inc; // Flag of the session open price change exceeding the growth value bool m_is_change_session_open_dec; // Flag of the session open price change exceeding the decrease value //--- Session close price double m_control_session_close_inc; // Controlled value of the session close price growth double m_control_session_close_dec; // Controlled value of the session close price decrease double m_changed_session_close_value; // Session close price change value bool m_is_change_session_close_inc; // Flag of the session close price change exceeding the growth value bool m_is_change_session_close_dec; // Flag of the session close price change exceeding the decrease value //--- The average weighted session price double m_control_session_aw_inc; // Controlled value of the average weighted session price growth double m_control_session_aw_dec; // Controlled value of the average weighted session price decrease double m_changed_session_aw_value; // The average weighted session price change value bool m_is_change_session_aw_inc; // Flag of the average weighted session price change value exceeding the growth value bool m_is_change_session_aw_dec; // Flag of the average weighted session price change value exceeding the decrease value
在私密部分中,声明用于初始化跟踪变量和品种属性的虚拟方法(已在 CBaseObj 基类中声明),以及 依据返回的事件代码检查属性变化的方法,按其代码设置事件类型,并将其写入事件列表的方法:
//--- Initialize the variables of (1) tracked, (2) controlled symbol data virtual void InitChangesParams(void); virtual void InitControlsParams(void); //--- Check symbol changes, return a change code virtual int SetEventCode(void); //--- Set an event type and fill in the event list virtual void SetTypeEvent(void);
我们在类的实体之外编写其实现。
初始化跟踪品种属性的方法:
//+------------------------------------------------------------------+ //| Initialize the variables of tracked symbol data | //+------------------------------------------------------------------+ void CSymbol::InitChangesParams(void) { //--- List and code of changes this.m_list_events.Clear(); // Clear the change list this.m_list_events.Sort(); // Sort the change list //--- Execution this.m_is_change_trade_mode=false; // Flag of changing trading mode for a symbol //--- Current session deals this.m_changed_session_deals_value=0; // Value of change in the number of deals this.m_is_change_session_deals_inc=false; // Flag of a change in the number of deals exceeding the growth value this.m_is_change_session_deals_dec=false; // Flag of a change in the number of deals exceeding the decrease value //--- Buy orders of the current session this.m_changed_session_buy_ord_value=0; // Buy orders change value this.m_is_change_session_buy_ord_inc=false; // Flag of a change in the number of Buy orders exceeding the growth value this.m_is_change_session_buy_ord_dec=false; // Flag of a change in the number of Buy orders exceeding the decrease value //--- Sell orders of the current session this.m_changed_session_sell_ord_value=0; // Sell orders change value this.m_is_change_session_sell_ord_inc=false; // Flag of a change in the number of Sell orders exceeding the growth value this.m_is_change_session_sell_ord_dec=false; // Flag of a change in the number of Sell orders exceeding the decrease value //--- Volume of the last deal this.m_changed_volume_value=0; // Value of the volume change in the last deal this.m_is_change_volume_inc=false; // Flag of the volume change in the last deal exceeding the growth value this.m_is_change_volume_dec=false; // Flag of the volume change in the last deal exceeding the decrease value //--- Maximum volume within a day this.m_changed_volume_high_day_value=0; // Maximum volume change value within a day this.m_is_change_volume_high_day_inc=false; // Flag of the maximum day volume exceeding the growth value this.m_is_change_volume_high_day_dec=false; // Flag of the maximum day volume exceeding the decrease value //--- Minimum volume within a day this.m_changed_volume_low_day_value=0; // Minimum volume change value within a day this.m_is_change_volume_low_day_inc=false; // Flag of the minimum day volume exceeding the growth value this.m_is_change_volume_low_day_dec=false; // Flag of the minimum day volume exceeding the decrease value //--- Spread this.m_changed_spread_value=0; // Spread change value in points this.m_is_change_spread_inc=false; // Flag of spread change in points exceeding the growth value this.m_is_change_spread_dec=false; // Flag of spread change in points exceeding the decrease value //--- StopLevel this.m_changed_stops_level_value=0; // StopLevel change value in points this.m_is_change_stops_level_inc=false; // Flag of StopLevel change in points exceeding the growth value this.m_is_change_stops_level_dec=false; // Flag of StopLevel change in points exceeding the decrease value //--- Freeze distance this.m_changed_freeze_level_value=0; // FreezeLevel change value in points this.m_is_change_freeze_level_inc=false; // Flag of FreezeLevel change in points exceeding the growth value this.m_is_change_freeze_level_dec=false; // Flag of FreezeLevel change in points exceeding the decrease value //--- Bid/Last this.m_changed_bid_last_value=0; // Bid or Last price change value this.m_is_change_bid_last_inc=false; // Flag of Bid or Last price change exceeding the growth value this.m_is_change_bid_last_dec=false; // Flag of Bid or Last price change exceeding the decrease value //--- Maximum Bid/Last of the day this.m_changed_bid_last_high_value=0; // Maximum Bid or Last change value for the day this.m_is_change_bid_last_high_inc=false; // Flag of the maximum Bid or Last price change for the day exceeding the growth value this.m_is_change_bid_last_high_dec=false; // Flag of the maximum Bid or Last price change for the day exceeding the decrease value //--- Minimum Bid/Last of the day this.m_changed_bid_last_low_value=0; // Minimum Bid or Last change value for the day this.m_is_change_bid_last_low_inc=false; // Flag of the minimum Bid or Last price change for the day exceeding the growth value this.m_is_change_bid_last_low_dec=false; // Flag of the minimum Bid or Last price change for the day exceeding the decrease value //--- Ask this.m_changed_ask_value=0; // Ask price change value this.m_is_change_ask_inc=false; // Flag of the Ask price change exceeding the growth value this.m_is_change_ask_dec=false; // Flag of the Ask price change exceeding the decrease value //--- Maximum Ask price for the day this.m_changed_ask_high_value=0; // Maximum Ask price change value for the day this.m_is_change_ask_high_inc=false; // Flag of the maximum day Ask exceeding the growth value this.m_is_change_ask_high_dec=false; // Flag of the maximum day Ask exceeding the decrease value //--- Minimum Ask price for the day this.m_changed_ask_low_value=0; // Minimum Ask price change value for the day this.m_is_change_ask_low_inc=false; // Flag of the minimum Ask volume exceeding the growth value this.m_is_change_ask_low_dec=false; // Flag of the minimum Ask volume exceeding the decrease value //--- Real Volume for the day this.m_changed_volume_real_value=0; // Real volume change value of the day this.m_is_change_volume_real_inc=false; // Flag of the real volume change for the day exceeding the growth value this.m_is_change_volume_real_dec=false; // Flag of the real volume change for the day exceeding the decrease value //--- Maximum real volume for the day this.m_changed_volume_high_real_day_value=0; // Maximum real volume change value of the day this.m_is_change_volume_high_real_day_inc=false; // Flag of the maximum real volume change for the day exceeding the growth value this.m_is_change_volume_high_real_day_dec=false; // Flag of the maximum real volume change for the day exceeding the decrease value //--- Minimum real volume for the day this.m_changed_volume_low_real_day_value=0; // Minimum real volume change value of the day this.m_is_change_volume_low_real_day_inc=false; // Flag of the minimum real volume change for the day exceeding the growth value this.m_is_change_volume_low_real_day_dec=false; // Flag of the minimum real volume change for the day exceeding the decrease value //--- Strike price this.m_changed_option_strike_value=0; // Strike price change value this.m_is_change_option_strike_inc=false; // Flag of the strike price change exceeding the growth value this.m_is_change_option_strike_dec=false; // Flag of the strike price change exceeding the decrease value //--- Total volume of positions and orders this.m_changed_volume_limit_value=0; // Minimum total volume change value this.m_is_change_volume_limit_inc=false; // Flag of the minimum total volume increase this.m_is_change_volume_limit_dec=false; // Flag of the minimum total volume decrease //--- Swap long this.m_changed_swap_long_value=0; // Swap long change value this.m_is_change_swap_long_inc=false; // Flag of the swap long increase this.m_is_change_swap_long_dec=false; // Flag of the swap long decrease //--- Swap short this.m_changed_swap_short_value=0; // Swap short change value this.m_is_change_swap_short_inc=false; // Flag of the swap short increase this.m_is_change_swap_short_dec=false; // Flag of the swap short decrease //--- The total volume of deals in the current session this.m_changed_session_volume_value=0; // The total deal volume change value in the current session this.m_is_change_session_volume_inc=false; // Flag of total trade volume change in the current session exceeding the growth value this.m_is_change_session_volume_dec=false; // Flag of total trade volume change in the current session exceeding the decrease value //--- The total turnover in the current session this.m_changed_session_turnover_value=0; // Total turnover change value in the current session this.m_is_change_session_turnover_inc=false; // Flag of total turnover change in the current session exceeding the growth value this.m_is_change_session_turnover_dec=false; // Flag of total turnover change in the current session exceeding the decrease value //--- The total volume of open positions this.m_changed_session_interest_value=0; // Change value of the open positions total volume in the current session this.m_is_change_session_interest_inc=false; // Flag of total open positions' volume change in the current session exceeding the growth value this.m_is_change_session_interest_dec=false; // Flag of total open positions' volume change in the current session exceeding the decrease value //--- The total volume of Buy orders at the moment this.m_changed_session_buy_ord_volume_value=0; // Change value of the current total buy order volume this.m_is_change_session_buy_ord_volume_inc=false; // Flag of changing the current total buy orders volume exceeding the growth value this.m_is_change_session_buy_ord_volume_dec=false; // Flag of changing the current total buy orders volume exceeding the decrease value //--- The total volume of Sell orders at the moment this.m_changed_session_sell_ord_volume_value=0; // Change value of the current total sell order volume this.m_is_change_session_sell_ord_volume_inc=false; // Flag of changing the current total sell orders volume exceeding the growth value this.m_is_change_session_sell_ord_volume_dec=false; // Flag of changing the current total sell orders volume exceeding the decrease value //--- Session open price this.m_changed_session_open_value=0; // Session open price change value this.m_is_change_session_open_inc=false; // Flag of the session open price change exceeding the growth value this.m_is_change_session_open_dec=false; // Flag of the session open price change exceeding the decrease value //--- Session close price this.m_changed_session_close_value=0; // Session close price change value this.m_is_change_session_close_inc=false; // Flag of the session close price change exceeding the growth value this.m_is_change_session_close_dec=false; // Flag of the session close price change exceeding the decrease value //--- The average weighted session price this.m_changed_session_aw_value=0; // The average weighted session price change value this.m_is_change_session_aw_inc=false; // Flag of the average weighted session price change value exceeding the growth value this.m_is_change_session_aw_dec=false; // Flag of the average weighted session price change value exceeding the decrease value } //+------------------------------------------------------------------+
在该方法中,仅将初始值分配给跟踪品种属性的变量。 先前在类的私密部分中已声明过这些初始变量。
初始化品种属性的受控数值的方法:
//+------------------------------------------------------------------+ //| Initialize the variables of controlled symbol data | //+------------------------------------------------------------------+ void CSymbol::InitControlsParams(void) { //--- Current session deals this.m_control_session_deals_inc=10; // Controlled value of the growth of the number of deals this.m_control_session_deals_dec=10; // Controlled value of the decrease in the number of deals //--- Buy orders of the current session this.m_control_session_buy_ord_inc=10; // Controlled value of the growth of the number of Buy orders this.m_control_session_buy_ord_dec=10; // Controlled value of the decrease in the number of Buy orders //--- Sell orders of the current session this.m_control_session_sell_ord_inc=10; // Controlled value of the growth of the number of Sell orders this.m_control_session_sell_ord_dec=10; // Controlled value of the decrease in the number of Sell orders //--- Volume of the last deal this.m_control_volume_inc=10; // Controlled value of the volume growth in the last deal this.m_control_volume_dec=10; // Controlled value of the volume decrease in the last deal //--- Maximum volume within a day this.m_control_volume_high_day_inc=50; // Controlled value of the maximum volume growth for a day this.m_control_volume_high_day_dec=50; // Controlled value of the maximum volume decrease for a day //--- Minimum volume within a day this.m_control_volume_low_day_inc=50; // Controlled value of the minimum volume growth for a day this.m_control_volume_low_day_dec=50; // Controlled value of the minimum volume decrease for a day //--- Spread this.m_control_spread_inc=2; // Controlled spread growth value in points this.m_control_spread_dec=2; // Controlled spread decrease value in points //--- StopLevel this.m_control_stops_level_inc=2; // Controlled StopLevel growth value in points this.m_control_stops_level_dec=2; // Controlled StopLevel decrease value in points //--- Freeze distance this.m_control_freeze_level_inc=2; // Controlled FreezeLevel growth value in points this.m_control_freeze_level_dec=2; // Controlled FreezeLevel decrease value in points //--- Bid/Last this.m_control_bid_last_inc=DBL_MAX; // Controlled value of Bid or Last price growth this.m_control_bid_last_dec=DBL_MAX; // Controlled value of Bid or Last price decrease //--- Maximum Bid/Last of the day this.m_control_bid_last_high_inc=DBL_MAX; // Controlled growth value of the maximum Bid or Last price of the day this.m_control_bid_last_high_dec=DBL_MAX; // Controlled decrease value of the maximum Bid or Last price of the day //--- Minimum Bid/Last of the day this.m_control_bid_last_low_inc=DBL_MAX; // Controlled growth value of the minimum Bid or Last price of the day this.m_control_bid_last_low_dec=DBL_MAX; // Controlled decrease value of the minimum Bid or Last price of the day //--- Ask this.m_control_ask_inc=DBL_MAX; // Controlled value of the Ask price growth this.m_control_ask_dec=DBL_MAX; // Controlled value of the Ask price decrease //--- Maximum Ask price for the day this.m_control_ask_high_inc=DBL_MAX; // Controlled growth value of the maximum Ask price of the day this.m_control_ask_high_dec=DBL_MAX; // Controlled decrease value of the maximum Ask price of the day //--- Minimum Ask price for the day this.m_control_ask_low_inc=DBL_MAX; // Controlled growth value of the minimum Ask price of the day this.m_control_ask_low_dec=DBL_MAX; // Controlled decrease value of the minimum Ask price of the day //--- Real Volume for the day this.m_control_volume_real_inc=50; // Controlled value of the real volume growth of the day this.m_control_volume_real_dec=50; // Controlled value of the real volume decrease of the day //--- Maximum real volume for the day this.m_control_volume_high_real_day_inc=20; // Controlled value of the maximum real volume growth of the day this.m_control_volume_high_real_day_dec=20; // Controlled value of the maximum real volume decrease of the day //--- Minimum real volume for the day this.m_control_volume_low_real_day_inc=10; // Controlled value of the minimum real volume growth of the day this.m_control_volume_low_real_day_dec=10; // Controlled value of the minimum real volume decrease of the day //--- Strike price this.m_control_option_strike_inc=0; // Controlled value of the strike price growth this.m_control_option_strike_dec=0; // Controlled value of the strike price decrease //--- The total volume of deals in the current session this.m_control_session_volume_inc=10; // Controlled value of the total trade volume growth in the current session this.m_control_session_volume_dec=10; // Controlled value of the total trade volume decrease in the current session //--- The total turnover in the current session this.m_control_session_turnover_inc=1000; // Controlled value of the total turnover growth in the current session this.m_control_session_turnover_dec=500; // Controlled value of the total turnover decrease in the current session //--- The total volume of open positions this.m_control_session_interest_inc=50; // Controlled value of the total open position volume growth in the current session this.m_control_session_interest_dec=20; // Controlled value of the total open position volume decrease in the current session //--- The total volume of Buy orders at the moment this.m_control_session_buy_ord_volume_inc=50; // Controlled value of the current total buy order volume growth this.m_control_session_buy_ord_volume_dec=20; // Controlled value of the current total buy order volume decrease //--- The total volume of Sell orders at the moment this.m_control_session_sell_ord_volume_inc=50; // Controlled value of the current total sell order volume growth this.m_control_session_sell_ord_volume_dec=20; // Controlled value of the current total sell order volume decrease //--- Session open price this.m_control_session_open_inc=0; // Controlled value of the session open price growth this.m_control_session_open_dec=0; // Controlled value of the session open price decrease //--- Session close price this.m_control_session_close_inc=0; // Controlled value of the session close price growth this.m_control_session_close_dec=0; // Controlled value of the session close price decrease //--- The average weighted session price this.m_control_session_aw_inc=0; // Controlled value of the average weighted session price growth this.m_control_session_aw_dec=0; // Controlled value of the average weighted session price decrease } //+------------------------------------------------------------------+
方法中只需将初始值分配给受控品种属性的变量。 先前在类的私密部分中已声明过这些初始变量。 如果属性超过变量中设置的值,则会生成相应的帐户事件。 若要禁用属性控件,应将 DBL_MAX 值分配给其变量。 若要跟踪任何变化,则为变量分配 0。
该方法检查品种属性发生的变化,并返回所发生变化的代码:
//+------------------------------------------------------------------+ //| Check symbol changes, return a change code | //+------------------------------------------------------------------+ int CSymbol::SetEventCode(void) { this.m_event_code=SYMBOL_EVENT_FLAG_NO_EVENT; if(this.m_struct_curr_symbol.trade_mode!=this.m_struct_prev_symbol.trade_mode) this.m_event_code+=SYMBOL_EVENT_FLAG_TRADE_MODE; if(this.m_struct_curr_symbol.session_deals!=this.m_struct_prev_symbol.session_deals) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_DEALS; if(this.m_struct_curr_symbol.session_buy_orders!=this.m_struct_prev_symbol.session_buy_orders) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS; if(this.m_struct_curr_symbol.session_sell_orders!=this.m_struct_prev_symbol.session_sell_orders) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS; if(this.m_struct_curr_symbol.volume!=this.m_struct_prev_symbol.volume) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME; if(this.m_struct_curr_symbol.volume_high_day!=this.m_struct_prev_symbol.volume_high_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY; if(this.m_struct_curr_symbol.volume_low_day!=this.m_struct_prev_symbol.volume_low_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY; if(this.m_struct_curr_symbol.spread!=this.m_struct_prev_symbol.spread) this.m_event_code+=SYMBOL_EVENT_FLAG_SPREAD; if(this.m_struct_curr_symbol.stops_level!=this.m_struct_prev_symbol.stops_level) this.m_event_code+=SYMBOL_EVENT_FLAG_STOPLEVEL; if(this.m_struct_curr_symbol.freeze_level!=this.m_struct_prev_symbol.freeze_level) this.m_event_code+=SYMBOL_EVENT_FLAG_FREEZELEVEL; if(this.m_struct_curr_symbol.bid_last!=this.m_struct_prev_symbol.bid_last) this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST; if(this.m_struct_curr_symbol.bid_last_high!=this.m_struct_prev_symbol.bid_last_high) this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST_HIGH; if(this.m_struct_curr_symbol.bid_last_low!=this.m_struct_prev_symbol.bid_last_low) this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST_LOW; if(this.m_struct_curr_symbol.ask!=this.m_struct_prev_symbol.ask) this.m_event_code+=SYMBOL_EVENT_FLAG_ASK; if(this.m_struct_curr_symbol.ask_high!=this.m_struct_prev_symbol.ask_high) this.m_event_code+=SYMBOL_EVENT_FLAG_ASK_HIGH; if(this.m_struct_curr_symbol.ask_low!=this.m_struct_prev_symbol.ask_low) this.m_event_code+=SYMBOL_EVENT_FLAG_ASK_LOW; if(this.m_struct_curr_symbol.volume_real_day!=this.m_struct_prev_symbol.volume_real_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY; if(this.m_struct_curr_symbol.volume_high_real_day!=this.m_struct_prev_symbol.volume_high_real_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY; if(this.m_struct_curr_symbol.volume_low_real_day!=this.m_struct_prev_symbol.volume_low_real_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY; if(this.m_struct_curr_symbol.option_strike!=this.m_struct_prev_symbol.option_strike) this.m_event_code+=SYMBOL_EVENT_FLAG_OPTION_STRIKE; if(this.m_struct_curr_symbol.volume_limit!=this.m_struct_prev_symbol.volume_limit) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LIMIT; if(this.m_struct_curr_symbol.swap_long!=this.m_struct_prev_symbol.swap_long) this.m_event_code+=SYMBOL_EVENT_FLAG_SWAP_LONG; if(this.m_struct_curr_symbol.swap_short!=this.m_struct_prev_symbol.swap_short) this.m_event_code+=SYMBOL_EVENT_FLAG_SWAP_SHORT; if(this.m_struct_curr_symbol.session_volume!=this.m_struct_prev_symbol.session_volume) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_VOLUME; if(this.m_struct_curr_symbol.session_turnover!=this.m_struct_prev_symbol.session_turnover) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_TURNOVER; if(this.m_struct_curr_symbol.session_interest!=this.m_struct_prev_symbol.session_interest) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_INTEREST; if(this.m_struct_curr_symbol.session_buy_ord_volume!=this.m_struct_prev_symbol.session_buy_ord_volume) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME; if(this.m_struct_curr_symbol.session_sell_ord_volume!=this.m_struct_prev_symbol.session_sell_ord_volume) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME; if(this.m_struct_curr_symbol.session_open!=this.m_struct_prev_symbol.session_open) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_OPEN; if(this.m_struct_curr_symbol.session_close!=this.m_struct_prev_symbol.session_close) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_CLOSE; if(this.m_struct_curr_symbol.session_aw!=this.m_struct_prev_symbol.session_aw) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_AW; //--- return this.m_event_code; } //+------------------------------------------------------------------+
首先,在方法中重置事件代码。 接下来,在当前数据结构和先前数据结构中比较受控品种参数的值。 如果数据不相似,则在事件代码中添加相应的标志。
方法会设置事件类型,并将所发生的事件写入事件列表:
//+------------------------------------------------------------------+ //| Set a symbol object event type | //+------------------------------------------------------------------+ void CSymbol::SetTypeEvent(void) { this.InitChangesParams(); ENUM_SYMBOL_EVENT event_id=SYMBOL_EVENT_NO_EVENT; //--- Change of trading modes on a symbol if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_TRADE_MODE)) { event_id= ( this.TradeMode()==SYMBOL_TRADE_MODE_DISABLED ? SYMBOL_EVENT_TRADE_DISABLE : this.TradeMode()==SYMBOL_TRADE_MODE_LONGONLY ? SYMBOL_EVENT_TRADE_LONGONLY : this.TradeMode()==SYMBOL_TRADE_MODE_SHORTONLY ? SYMBOL_EVENT_TRADE_SHORTONLY : this.TradeMode()==SYMBOL_TRADE_MODE_CLOSEONLY ? SYMBOL_EVENT_TRADE_CLOSEONLY : SYMBOL_EVENT_TRADE_FULL ); this.m_is_change_trade_mode=true; if(this.EventAdd(event_id,this.TickTime(),this.TradeMode(),this.Name())) this.m_struct_prev_symbol.trade_mode=this.m_struct_curr_symbol.trade_mode; } //--- Change of the number of deals in the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_DEALS)) { this.m_changed_session_deals_value=this.m_struct_curr_symbol.session_deals-this.m_struct_prev_symbol.session_deals; if(this.m_changed_session_deals_value>this.m_control_session_deals_inc) { this.m_is_change_session_deals_inc=true; event_id=SYMBOL_EVENT_SESSION_DEALS_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_deals_value,this.Name())) this.m_struct_prev_symbol.session_deals=this.m_struct_curr_symbol.session_deals; } else if(this.m_changed_session_deals_value<-this.m_control_session_deals_dec) { this.m_is_change_session_deals_dec=true; event_id=SYMBOL_EVENT_SESSION_DEALS_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_deals_value,this.Name())) this.m_struct_prev_symbol.session_deals=this.m_struct_curr_symbol.session_deals; } } //--- Change of the total number of the current buy orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS)) { this.m_changed_session_buy_ord_value=this.m_struct_curr_symbol.session_buy_orders-this.m_struct_prev_symbol.session_buy_orders; if(this.m_changed_session_buy_ord_value>this.m_control_session_buy_ord_inc) { this.m_is_change_session_buy_ord_inc=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORDERS_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_value,this.Name())) this.m_struct_prev_symbol.session_buy_orders=this.m_struct_curr_symbol.session_buy_orders; } else if(this.m_changed_session_buy_ord_value<-this.m_control_session_buy_ord_dec) { this.m_is_change_session_buy_ord_dec=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORDERS_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_value,this.Name())) this.m_struct_prev_symbol.session_buy_orders=this.m_struct_curr_symbol.session_buy_orders; } } //--- Change of the total number of the current sell orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS)) { this.m_changed_session_sell_ord_value=this.m_struct_curr_symbol.session_sell_orders-this.m_struct_prev_symbol.session_sell_orders; if(this.m_changed_session_sell_ord_value>this.m_control_session_sell_ord_inc) { this.m_is_change_session_sell_ord_inc=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORDERS_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_value,this.Name())) this.m_struct_prev_symbol.session_sell_orders=this.m_struct_curr_symbol.session_sell_orders; } else if(this.m_changed_session_sell_ord_value<-this.m_control_session_sell_ord_dec) { this.m_is_change_session_sell_ord_dec=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORDERS_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_value,this.Name())) this.m_struct_prev_symbol.session_sell_orders=this.m_struct_curr_symbol.session_sell_orders; } } //--- Volume change in the last deal if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME)) { this.m_changed_volume_value=this.m_struct_curr_symbol.volume-this.m_struct_prev_symbol.volume; if(this.m_changed_volume_value>this.m_control_volume_inc) { this.m_is_change_volume_inc=true; event_id=SYMBOL_EVENT_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_value,this.Name())) this.m_struct_prev_symbol.volume=this.m_struct_curr_symbol.volume; } else if(this.m_changed_volume_value<-this.m_control_volume_dec) { this.m_is_change_volume_dec=true; event_id=SYMBOL_EVENT_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_value,this.Name())) this.m_struct_prev_symbol.volume=this.m_struct_curr_symbol.volume; } } //--- Maximum volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY)) { this.m_changed_volume_high_day_value=this.m_struct_curr_symbol.volume_high_day-this.m_struct_prev_symbol.volume_high_day; if(this.m_changed_volume_high_day_value>this.m_control_volume_high_day_inc) { this.m_is_change_volume_high_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_day=this.m_struct_curr_symbol.volume_high_day; } else if(this.m_changed_volume_high_day_value<-this.m_control_volume_high_day_dec) { this.m_is_change_volume_high_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_day=this.m_struct_curr_symbol.volume_high_day; } } //--- Minimum volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY)) { this.m_changed_volume_low_day_value=this.m_struct_curr_symbol.volume_low_day-this.m_struct_prev_symbol.volume_low_day; if(this.m_changed_volume_low_day_value>this.m_control_volume_low_day_inc) { this.m_is_change_volume_low_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_LOW_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_day=this.m_struct_curr_symbol.volume_low_day; } else if(this.m_changed_volume_low_day_value<-this.m_control_volume_low_day_dec) { this.m_is_change_volume_low_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_LOW_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_day=this.m_struct_curr_symbol.volume_low_day; } } //--- Spread value change in points if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SPREAD)) { this.m_changed_spread_value=this.m_struct_curr_symbol.spread-this.m_struct_prev_symbol.spread; if(this.m_changed_spread_value>this.m_control_spread_inc) { this.m_is_change_spread_inc=true; event_id=SYMBOL_EVENT_SPREAD_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_spread_value,this.Name())) this.m_struct_prev_symbol.spread=this.m_struct_curr_symbol.spread; } else if(this.m_changed_spread_value<-this.m_control_spread_dec) { this.m_is_change_spread_dec=true; event_id=SYMBOL_EVENT_SPREAD_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_spread_value,this.Name())) this.m_struct_prev_symbol.spread=this.m_struct_curr_symbol.spread; } } //--- StopLevel change in points if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_STOPLEVEL)) { this.m_changed_stops_level_value=this.m_struct_curr_symbol.stops_level-this.m_struct_prev_symbol.stops_level; if(this.m_changed_stops_level_value>this.m_control_stops_level_inc) { this.m_is_change_stops_level_inc=true; event_id=SYMBOL_EVENT_STOPLEVEL_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_stops_level_value,this.Name())) this.m_struct_prev_symbol.stops_level=this.m_struct_curr_symbol.stops_level; } else if(this.m_changed_stops_level_value<-this.m_control_stops_level_dec) { this.m_is_change_stops_level_dec=true; event_id=SYMBOL_EVENT_STOPLEVEL_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_stops_level_value,this.Name())) this.m_struct_prev_symbol.stops_level=this.m_struct_curr_symbol.stops_level; } } //--- FreezeLevel change in points if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_FREEZELEVEL)) { this.m_changed_freeze_level_value=this.m_struct_curr_symbol.freeze_level-this.m_struct_prev_symbol.freeze_level; if(this.m_changed_freeze_level_value>this.m_control_freeze_level_inc) { this.m_is_change_freeze_level_inc=true; event_id=SYMBOL_EVENT_FREEZELEVEL_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_freeze_level_value,this.Name())) this.m_struct_prev_symbol.freeze_level=this.m_struct_curr_symbol.freeze_level; } else if(this.m_changed_freeze_level_value<-this.m_control_freeze_level_dec) { this.m_is_change_freeze_level_dec=true; event_id=SYMBOL_EVENT_FREEZELEVEL_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_freeze_level_value,this.Name())) this.m_struct_prev_symbol.freeze_level=this.m_struct_curr_symbol.freeze_level; } } //--- Bid/Last price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST)) { this.m_changed_bid_last_value=this.m_struct_curr_symbol.bid_last-this.m_struct_prev_symbol.bid_last; if(this.m_changed_bid_last_value>this.m_control_bid_last_inc) { this.m_is_change_bid_last_inc=true; event_id=SYMBOL_EVENT_BID_LAST_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_value,this.Name())) this.m_struct_prev_symbol.bid_last=this.m_struct_curr_symbol.bid_last; } else if(this.m_changed_bid_last_value<-this.m_control_bid_last_dec) { this.m_is_change_bid_last_dec=true; event_id=SYMBOL_EVENT_BID_LAST_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_value,this.Name())) this.m_struct_prev_symbol.bid_last=this.m_struct_curr_symbol.bid_last; } } //--- Maximum Bid/Last change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST_HIGH)) { this.m_changed_bid_last_high_value=this.m_struct_curr_symbol.bid_last_high-this.m_struct_prev_symbol.bid_last_high; if(this.m_changed_bid_last_high_value>this.m_control_bid_last_high_inc) { this.m_is_change_bid_last_high_inc=true; event_id=SYMBOL_EVENT_BID_LAST_HIGH_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_high_value,this.Name())) this.m_struct_prev_symbol.bid_last_high=this.m_struct_curr_symbol.bid_last_high; } else if(this.m_changed_bid_last_high_value<-this.m_control_bid_last_high_dec) { this.m_is_change_bid_last_high_dec=true; event_id=SYMBOL_EVENT_BID_LAST_HIGH_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_high_value,this.Name())) this.m_struct_prev_symbol.bid_last_high=this.m_struct_curr_symbol.bid_last_high; } } //--- Minimum Bid/Last change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST_LOW)) { this.m_changed_bid_last_low_value=this.m_struct_curr_symbol.bid_last_low-this.m_struct_prev_symbol.bid_last_low; if(this.m_changed_bid_last_low_value>this.m_control_bid_last_low_inc) { this.m_is_change_bid_last_low_inc=true; event_id=SYMBOL_EVENT_BID_LAST_LOW_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_low_value,this.Name())) this.m_struct_prev_symbol.bid_last_low=this.m_struct_curr_symbol.bid_last_low; } else if(this.m_changed_bid_last_low_value<-this.m_control_bid_last_low_dec) { this.m_is_change_bid_last_low_dec=true; event_id=SYMBOL_EVENT_BID_LAST_LOW_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_low_value,this.Name())) this.m_struct_prev_symbol.bid_last_low=this.m_struct_curr_symbol.bid_last_low; } } //--- Ask price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK)) { this.m_changed_ask_value=this.m_struct_curr_symbol.ask-this.m_struct_prev_symbol.ask; if(this.m_changed_ask_value>this.m_control_ask_inc) { this.m_is_change_ask_inc=true; event_id=SYMBOL_EVENT_ASK_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_value,this.Name())) this.m_struct_prev_symbol.ask=this.m_struct_curr_symbol.ask; } else if(this.m_changed_ask_value<-this.m_control_ask_dec) { this.m_is_change_ask_dec=true; event_id=SYMBOL_EVENT_ASK_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_value,this.Name())) this.m_struct_prev_symbol.ask=this.m_struct_curr_symbol.ask; } } //--- Maximum As change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK_HIGH)) { this.m_changed_ask_high_value=this.m_struct_curr_symbol.ask_high-this.m_struct_prev_symbol.ask_high; if(this.m_changed_ask_high_value>this.m_control_ask_high_inc) { this.m_is_change_ask_high_inc=true; event_id=SYMBOL_EVENT_ASK_HIGH_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_high_value,this.Name())) this.m_struct_prev_symbol.ask_high=this.m_struct_curr_symbol.ask_high; } else if(this.m_changed_ask_high_value<-this.m_control_ask_high_dec) { this.m_is_change_ask_high_dec=true; event_id=SYMBOL_EVENT_ASK_HIGH_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_high_value,this.Name())) this.m_struct_prev_symbol.ask_high=this.m_struct_curr_symbol.ask_high; } } //--- Minimum Ask change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK_LOW)) { this.m_changed_ask_low_value=this.m_struct_curr_symbol.ask_low-this.m_struct_prev_symbol.ask_low; if(this.m_changed_ask_low_value>this.m_control_ask_low_inc) { this.m_is_change_ask_low_inc=true; event_id=SYMBOL_EVENT_ASK_LOW_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_low_value,this.Name())) this.m_struct_prev_symbol.ask_low=this.m_struct_curr_symbol.ask_low; } else if(this.m_changed_ask_low_value<-this.m_control_ask_low_dec) { this.m_is_change_ask_low_dec=true; event_id=SYMBOL_EVENT_ASK_LOW_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_low_value,this.Name())) this.m_struct_prev_symbol.ask_low=this.m_struct_curr_symbol.ask_low; } } //--- Real volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY)) { this.m_changed_volume_real_value=this.m_struct_curr_symbol.volume_real_day-this.m_struct_prev_symbol.volume_real_day; if(this.m_changed_volume_real_value>this.m_control_volume_real_inc) { this.m_is_change_volume_real_inc=true; event_id=SYMBOL_EVENT_VOLUME_REAL_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_real_value,this.Name())) this.m_struct_prev_symbol.volume_real_day=this.m_struct_curr_symbol.volume_real_day; } else if(this.m_changed_volume_real_value<-this.m_control_volume_real_dec) { this.m_is_change_volume_real_dec=true; event_id=SYMBOL_EVENT_VOLUME_REAL_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_real_value,this.Name())) this.m_struct_prev_symbol.volume_real_day=this.m_struct_curr_symbol.volume_real_day; } } //--- Maximum real volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY)) { this.m_changed_volume_high_real_day_value=this.m_struct_curr_symbol.volume_high_real_day-this.m_struct_prev_symbol.volume_high_real_day; if(this.m_changed_volume_high_real_day_value>this.m_control_volume_high_real_day_inc) { this.m_is_change_volume_high_real_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_real_day=this.m_struct_curr_symbol.volume_high_real_day; } else if(this.m_changed_volume_high_real_day_value<-this.m_control_volume_high_real_day_dec) { this.m_is_change_volume_high_real_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_real_day=this.m_struct_curr_symbol.volume_high_real_day; } } //--- Minimum real volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY)) { this.m_changed_volume_low_real_day_value=this.m_struct_curr_symbol.volume_low_real_day-this.m_struct_prev_symbol.volume_low_real_day; if(this.m_changed_volume_low_real_day_value>this.m_control_volume_low_real_day_inc) { this.m_is_change_volume_low_real_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_real_day=this.m_struct_curr_symbol.volume_low_real_day; } else if(this.m_changed_volume_low_real_day_value<-this.m_control_volume_low_real_day_dec) { this.m_is_change_volume_low_real_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_real_day=this.m_struct_curr_symbol.volume_low_real_day; } } //--- Strike price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_OPTION_STRIKE)) { this.m_changed_option_strike_value=this.m_struct_curr_symbol.option_strike-this.m_struct_prev_symbol.option_strike; if(this.m_changed_option_strike_value>this.m_control_option_strike_inc) { this.m_is_change_option_strike_inc=true; event_id=SYMBOL_EVENT_OPTION_STRIKE_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_option_strike_value,this.Name())) this.m_struct_prev_symbol.option_strike=this.m_struct_curr_symbol.option_strike; } else if(this.m_changed_option_strike_value<-this.m_control_option_strike_dec) { this.m_is_change_option_strike_dec=true; event_id=SYMBOL_EVENT_OPTION_STRIKE_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_option_strike_value,this.Name())) this.m_struct_prev_symbol.option_strike=this.m_struct_curr_symbol.option_strike; } } //--- Change of the maximum available total position volume and pending orders in one direction if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LIMIT)) { this.m_changed_volume_limit_value=this.m_struct_curr_symbol.volume_limit-this.m_struct_prev_symbol.volume_limit; if(this.m_changed_volume_limit_value>0) { this.m_is_change_volume_limit_inc=true; event_id=SYMBOL_EVENT_VOLUME_LIMIT_INC; } else { this.m_is_change_volume_limit_dec=true; event_id=SYMBOL_EVENT_VOLUME_LIMIT_DEC; } if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_limit_value,this.Name())) this.m_struct_prev_symbol.volume_limit=this.m_struct_curr_symbol.volume_limit; } //--- Swap long change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SWAP_LONG)) { this.m_changed_swap_long_value=this.m_struct_curr_symbol.swap_long-this.m_struct_prev_symbol.swap_long; if(this.m_changed_swap_long_value>0) { this.m_is_change_swap_long_inc=true; event_id=SYMBOL_EVENT_SWAP_LONG_INC; } else { this.m_is_change_swap_long_dec=true; event_id=SYMBOL_EVENT_SWAP_LONG_DEC; } if(this.EventAdd(event_id,this.TickTime(),this.m_changed_swap_long_value,this.Name())) this.m_struct_prev_symbol.swap_long=this.m_struct_curr_symbol.swap_long; } //--- Swap short change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SWAP_SHORT)) { this.m_changed_swap_short_value=this.m_struct_curr_symbol.swap_short-this.m_struct_prev_symbol.swap_short; if(this.m_changed_swap_short_value>0) { this.m_is_change_swap_short_inc=true; event_id=SYMBOL_EVENT_SWAP_SHORT_INC; } else { this.m_is_change_swap_short_dec=true; event_id=SYMBOL_EVENT_SWAP_SHORT_DEC; } if(this.EventAdd(event_id,this.TickTime(),this.m_changed_swap_short_value,this.Name())) this.m_struct_prev_symbol.swap_short=this.m_struct_curr_symbol.swap_short; } //--- Change of the total volume of deals during the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_VOLUME)) { this.m_changed_session_volume_value=this.m_struct_curr_symbol.session_volume-this.m_struct_prev_symbol.session_volume; if(this.m_changed_session_volume_value>this.m_control_session_volume_inc) { this.m_is_change_session_volume_inc=true; event_id=SYMBOL_EVENT_SESSION_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_volume_value,this.Name())) this.m_struct_prev_symbol.session_volume=this.m_struct_curr_symbol.session_volume; } else if(this.m_changed_session_volume_value<-this.m_control_session_volume_dec) { this.m_is_change_session_volume_dec=true; event_id=SYMBOL_EVENT_SESSION_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_volume_value,this.Name())) this.m_struct_prev_symbol.session_volume=this.m_struct_curr_symbol.session_volume; } } //--- Change of the total turnover during the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_TURNOVER)) { this.m_changed_session_turnover_value=this.m_struct_curr_symbol.session_turnover-this.m_struct_prev_symbol.session_turnover; if(this.m_changed_session_turnover_value>this.m_control_session_turnover_inc) { this.m_is_change_session_turnover_inc=true; event_id=SYMBOL_EVENT_SESSION_TURNOVER_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_turnover_value,this.Name())) this.m_struct_prev_symbol.session_turnover=this.m_struct_curr_symbol.session_turnover; } else if(this.m_changed_session_turnover_value<-this.m_control_session_turnover_dec) { this.m_is_change_session_turnover_dec=true; event_id=SYMBOL_EVENT_SESSION_TURNOVER_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_turnover_value,this.Name())) this.m_struct_prev_symbol.session_turnover=this.m_struct_curr_symbol.session_turnover; } } //--- Change of the total volume of open positions during the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_INTEREST)) { this.m_changed_session_interest_value=this.m_struct_curr_symbol.session_interest-this.m_struct_prev_symbol.session_interest; if(this.m_changed_session_interest_value>this.m_control_session_interest_inc) { this.m_is_change_session_interest_inc=true; event_id=SYMBOL_EVENT_SESSION_INTEREST_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_interest_value,this.Name())) this.m_struct_prev_symbol.session_interest=this.m_struct_curr_symbol.session_interest; } else if(this.m_changed_session_interest_value<-this.m_control_session_interest_dec) { this.m_is_change_session_interest_dec=true; event_id=SYMBOL_EVENT_SESSION_INTEREST_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_interest_value,this.Name())) this.m_struct_prev_symbol.session_interest=this.m_struct_curr_symbol.session_interest; } } //--- Change of the current total volume of buy orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME)) { this.m_changed_session_buy_ord_volume_value=this.m_struct_curr_symbol.session_buy_ord_volume-this.m_struct_prev_symbol.session_buy_ord_volume; if(this.m_changed_session_buy_ord_volume_value>this.m_control_session_buy_ord_volume_inc) { this.m_is_change_session_buy_ord_volume_inc=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_buy_ord_volume=this.m_struct_curr_symbol.session_buy_ord_volume; } else if(this.m_changed_session_buy_ord_volume_value<-this.m_control_session_buy_ord_volume_dec) { this.m_is_change_session_buy_ord_volume_dec=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_buy_ord_volume=this.m_struct_curr_symbol.session_buy_ord_volume; } } //--- Change of the current total volume of sell orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME)) { this.m_changed_session_sell_ord_volume_value=this.m_struct_curr_symbol.session_sell_ord_volume-this.m_struct_prev_symbol.session_sell_ord_volume; if(this.m_changed_session_sell_ord_volume_value>this.m_control_session_sell_ord_volume_inc) { this.m_is_change_session_sell_ord_volume_inc=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_sell_ord_volume=this.m_struct_curr_symbol.session_sell_ord_volume; } else if(this.m_changed_session_sell_ord_volume_value<-this.m_control_session_sell_ord_volume_dec) { this.m_is_change_session_sell_ord_volume_dec=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_sell_ord_volume=this.m_struct_curr_symbol.session_sell_ord_volume; } } //--- Session open price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_OPEN)) { this.m_changed_session_open_value=this.m_struct_curr_symbol.session_open-this.m_struct_prev_symbol.session_open; if(this.m_changed_session_open_value>this.m_control_session_open_inc) { this.m_is_change_session_open_inc=true; event_id=SYMBOL_EVENT_SESSION_OPEN_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_open_value,this.Name())) this.m_struct_prev_symbol.session_open=this.m_struct_curr_symbol.session_open; } else if(this.m_changed_session_open_value<-this.m_control_session_open_dec) { this.m_is_change_session_open_dec=true; event_id=SYMBOL_EVENT_SESSION_OPEN_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_open_value,this.Name())) this.m_struct_prev_symbol.session_open=this.m_struct_curr_symbol.session_open; } } //--- Session close price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_CLOSE)) { this.m_changed_session_close_value=this.m_struct_curr_symbol.session_close-this.m_struct_prev_symbol.session_close; if(this.m_changed_session_close_value>this.m_control_session_close_inc) { this.m_is_change_session_close_inc=true; event_id=SYMBOL_EVENT_SESSION_CLOSE_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_close_value,this.Name())) this.m_struct_prev_symbol.session_close=this.m_struct_curr_symbol.session_close; } else if(this.m_changed_session_close_value<-this.m_control_session_close_dec) { this.m_is_change_session_close_dec=true; event_id=SYMBOL_EVENT_SESSION_CLOSE_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_close_value,this.Name())) this.m_struct_prev_symbol.session_close=this.m_struct_curr_symbol.session_close; } } //--- Average weighted session price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_AW)) { this.m_changed_session_aw_value=this.m_struct_curr_symbol.session_aw-this.m_struct_prev_symbol.session_aw; if(this.m_changed_session_aw_value>this.m_control_session_aw_inc) { this.m_is_change_session_aw_inc=true; event_id=SYMBOL_EVENT_SESSION_AW_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_aw_value,this.Name())) this.m_struct_prev_symbol.session_aw=this.m_struct_curr_symbol.session_aw; } else if(this.m_changed_session_aw_value<-this.m_control_session_aw_dec) { this.m_is_change_session_aw_dec=true; event_id=SYMBOL_EVENT_SESSION_AW_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_aw_value,this.Name())) this.m_struct_prev_symbol.session_aw=this.m_struct_curr_symbol.session_aw; } } } //+------------------------------------------------------------------+
由于跟踪品种属性过程中检查变化的逻辑位于相同的模块,因此该方法非常“庞大”。 在第十三部分里,我们在跟踪帐户变化时已研究过类似的方法。 此处的逻辑类似,只是保存事件的全部功能现在位于 CBaseObj 基准对象中。
我们以时段的平均加权价格变化为例进行研究。
方法伊始,利用 InitChangesParams() 方法重置要跟踪属性的值,并将事件状态设置为“无事件” 。
- 利用同样位于基准对象中的 IsPresentEventFlag() 方法,检查m_event_code 变量中设置的事件代码,判断是否存在 SYMBOL_SESSION_AW 品种值变化的标志。
如果事件代码中检测到存在数值变化的标志,
- 计算属性值,并检查该值是否超过受控值。
- 如果计算出的数值超过受控值,
- 设置加权平均价格事件的标志,
- 写入“平均加权价格增长” 事件 ID,
- 调用 CBaseObj 基类的 EventAdd() 方法,将事件添加到列表。
如果事件已成功添加到列表中,
- 将当前属性值另存为前值,以便后续检查。
将数据发送到 EventAdd() 方法,将事件添加到列表:
- 事件 ID (event_id 检查事件时填写)
- 当前时间(以毫秒为单位)(CBaseObj 基类的 TickTime() 方法)
- 计算出的数值,按照变化的品种属性(m_changed_session_aw_value)
- 对象名称(这里是品种名称)
我们还要略微修改受保护的类构造函数:为了填充对象品种的新属性“市场观察窗口中的品种索引”,我们需要在扫描市场观察品种时传递此索引。 索引将直接传递给类构造函数:
protected: //--- Protected parametric constructor CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index);
在类的同一受保护部分中,添加另一个按隔夜利率收取模式返回小数位的方法:
//--- Get and return integer properties of a selected symbol from its parameters bool SymbolExists(const string name) const; long SymbolExists(void) const; long SymbolCustom(void) const; long SymbolChartMode(void) const; long SymbolMarginHedgedUseLEG(void) const; long SymbolOrderFillingMode(void) const; long SymbolOrderMode(void) const; long SymbolExpirationMode(void) const; long SymbolOrderGTCMode(void) const; long SymbolOptionMode(void) const; long SymbolOptionRight(void) const; long SymbolBackgroundColor(void) const; long SymbolCalcMode(void) const; long SymbolSwapMode(void) const; long SymbolDigitsLot(void); int SymbolDigitsBySwap(void); //--- Get and return real properties of a selected symbol from its parameters
隔夜利率可按照资金、点数和百分比收取。 对于每种隔夜利率收取类型,我们需要返回相应的小数位。 这正是该方法的作用。 我们在类的主体之外编写它:
//+------------------------------------------------------------------+ //| Return the number of decimal places | //| depending on the swap calculation method | //+------------------------------------------------------------------+ int CSymbol::SymbolDigitsBySwap(void) { return ( this.SwapMode()==SYMBOL_SWAP_MODE_POINTS || this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_CURRENT || this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_BID ? this.Digits() : this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_SYMBOL || this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_MARGIN || this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT ? this.DigitsCurrency(): this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_CURRENT || this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_OPEN ? 1 : 0 ); } //+------------------------------------------------------------------+
我们将 Refresh() 方法设为虚方法,因为它也需在所有 CBaseObj 对象的基类中定义。 另外,将 RefreshRates() 报价数据刷新方法类型从 void 替换为 bool 。 由于 RefreshRates() 方法是在 Refresh() 方法的开头处调用的。 如果未得到任何数据,则该方法返回 false。 相应地,会立即自 Refresh() 方法执行退出。
添加定义返回品种事件描述的方法:
//--- Update all symbol data virtual void Refresh(void); //--- Update quote data by a symbol bool RefreshRates(void); //--- Return description of symbol events string EventDescription(const ENUM_SYMBOL_EVENT event);
在类的公开部分中简化访问方法,在方法中返回品种整数型属性,
添加返回“市场观察”窗口中交易品种索引的方法:
//+------------------------------------------------------------------+ //| Methods of a simplified access to the order object properties | //+------------------------------------------------------------------+ //--- Integer properties long Status(void) const { return this.GetProperty(SYMBOL_PROP_STATUS); } int IndexInMarketWatch(void) const { return (int)this.GetProperty(SYMBOL_PROP_INDEX_MW); } bool IsCustom(void) const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM); } color ColorBackground(void) const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR); } ENUM_SYMBOL_CHART_MODE ChartMode(void) const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE); } bool IsExist(void) const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST); } bool IsExist(const string name) const { return this.SymbolExists(name); } bool IsSelect(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT); } bool IsVisible(void) const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE); } long SessionDeals(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS); } long SessionBuyOrders(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS); } long SessionSellOrders(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS); } long Volume(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME); } long VolumeHigh(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH); } long VolumeLow(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW); } datetime Time(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME); } int Digits(void) const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS); } int DigitsLot(void) const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS); } int Spread(void) const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD); } bool IsSpreadFloat(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT); } int TicksBookdepth(void) const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH); } ENUM_SYMBOL_CALC_MODE TradeCalcMode(void) const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE); } ENUM_SYMBOL_TRADE_MODE TradeMode(void) const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE); } datetime StartTime(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME); } datetime ExpirationTime(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME); } int TradeStopLevel(void) const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL); } int TradeFreezeLevel(void) const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL); } ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void) const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE); } ENUM_SYMBOL_SWAP_MODE SwapMode(void) const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE); } ENUM_DAY_OF_WEEK SwapRollover3Days(void) const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS); } bool IsMarginHedgedUseLeg(void) const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG); } int ExpirationModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE); } int FillingModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE); } int OrderModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE); } ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void) const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE); } ENUM_SYMBOL_OPTION_MODE OptionMode(void) const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE); } ENUM_SYMBOL_OPTION_RIGHT OptionRight(void) const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT); } //--- Real properties
而在返回实数型属性的方法中,
添加返回出价或最后价格的方法,返回一天当中最高出价或最后价格的方法以及返回最小出价或当天最后价格的方法:
//--- Real properties double Bid(void) const { return this.GetProperty(SYMBOL_PROP_BID); } double BidHigh(void) const { return this.GetProperty(SYMBOL_PROP_BIDHIGH); } double BidLow(void) const { return this.GetProperty(SYMBOL_PROP_BIDLOW); } double Ask(void) const { return this.GetProperty(SYMBOL_PROP_ASK); } double AskHigh(void) const { return this.GetProperty(SYMBOL_PROP_ASKHIGH); } double AskLow(void) const { return this.GetProperty(SYMBOL_PROP_ASKLOW); } double Last(void) const { return this.GetProperty(SYMBOL_PROP_LAST); } double LastHigh(void) const { return this.GetProperty(SYMBOL_PROP_LASTHIGH); } double LastLow(void) const { return this.GetProperty(SYMBOL_PROP_LASTLOW); } double VolumeReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL); } double VolumeHighReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL); } double VolumeLowReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL); } double OptionStrike(void) const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE); } double Point(void) const { return this.GetProperty(SYMBOL_PROP_POINT); } double TradeTickValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE); } double TradeTickValueProfit(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT); } double TradeTickValueLoss(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS); } double TradeTickSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE); } double TradeContractSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE); } double TradeAccuredInterest(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST); } double TradeFaceValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE); } double TradeLiquidityRate(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE); } double LotsMin(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN); } double LotsMax(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX); } double LotsStep(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP); } double VolumeLimit(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT); } double SwapLong(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG); } double SwapShort(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT); } double MarginInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL); } double MarginMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE); } double MarginLongInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL); } double MarginBuyStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL); } double MarginBuyLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL); } double MarginBuyStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL); } double MarginLongMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE); } double MarginBuyStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE); } double MarginBuyLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE); } double MarginBuyStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE); } double MarginShortInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL); } double MarginSellStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL); } double MarginSellLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL); } double MarginSellStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL); } double MarginShortMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE); } double MarginSellStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE); } double MarginSellLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE); } double MarginSellStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE); } double SessionVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME); } double SessionTurnover(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER); } double SessionInterest(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST); } double SessionBuyOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME); } double SessionSellOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME); } double SessionOpen(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN); } double SessionClose(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE); } double SessionAW(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_AW); } double SessionPriceSettlement(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT); } double SessionPriceLimitMin(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN); } double SessionPriceLimitMax(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX); } double MarginHedged(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED); } double NormalizedPrice(const double price) const; double BidLast(void) const; double BidLastHigh(void) const; double BidLastLow(void) const; //--- String properties
我们在类的主体之外编写其实现:
//+------------------------------------------------------------------+ //| Return Bid or Last price | //| depending on the chart construction method | //+------------------------------------------------------------------+ double CSymbol::BidLast(void) const { return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BID) : this.GetProperty(SYMBOL_PROP_LAST)); } //+------------------------------------------------------------------+ //| Return maximum Bid or Last price for a day | //| depending on the chart construction method | //+------------------------------------------------------------------+ double CSymbol::BidLastHigh(void) const { return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BIDHIGH) : this.GetProperty(SYMBOL_PROP_LASTHIGH)); } //+------------------------------------------------------------------+ //| Return minimum Bid or Last price for a day | //| depending on the chart construction method | //+------------------------------------------------------------------+ double CSymbol::BidLastLow(void) const { return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BIDLOW) : this.GetProperty(SYMBOL_PROP_LASTLOW)); } //+------------------------------------------------------------------+
这一切都很简单:根据用于构造价格图表的价格,返回相应的品种属性(出价或最后价格)。
另外,在公开部分编写设置受控属性和返回属性变化值和品种事件标志的方法:
//+------------------------------------------------------------------+ //| Get and set the parameters of tracked changes | //+------------------------------------------------------------------+ //--- Execution //--- Flag of changing the trading mode for a symbol bool IsChangedTradeMode(void) const { return this.m_is_change_trade_mode; } //--- Current session deals //--- setting the controlled value of (1) growth, (2) decrease in the number of deals during the current session //--- getting (3) the number of deals change value during the current session, //--- getting the flag of the number of deals change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionDealsInc(const long value) { this.m_control_session_deals_inc=::fabs(value); } void SetControlSessionDealsDec(const long value) { this.m_control_session_deals_dec=::fabs(value); } long GetValueChangedSessionDeals(void) const { return this.m_changed_session_deals_value; } bool IsIncreaseSessionDeals(void) const { return this.m_is_change_session_deals_inc; } bool IsDecreaseSessionDeals(void) const { return this.m_is_change_session_deals_dec; } //--- Buy orders of the current session //--- setting the controlled value of (1) growth, (2) decrease in the current number of Buy orders //--- getting (3) the current number of Buy orders change value, //--- getting the flag of the current Buy orders' number change exceeding the (4) growth, (5) decrease value void SetControlSessionBuyOrdInc(const long value) { this.m_control_session_buy_ord_inc=::fabs(value); } void SetControlSessionBuyOrdDec(const long value) { this.m_control_session_buy_ord_dec=::fabs(value); } long GetValueChangedSessionBuyOrders(void) const { return this.m_changed_session_buy_ord_value; } bool IsIncreaseSessionBuyOrders(void) const { return this.m_is_change_session_buy_ord_inc; } bool IsDecreaseSessionBuyOrders(void) const { return this.m_is_change_session_buy_ord_dec; } //--- Sell orders of the current session //--- setting the controlled value of (1) growth, (2) decrease in the current number of Sell orders //--- getting (3) the current number of Sell orders change value, //--- getting the flag of the current Sell orders' number change exceeding the (4) growth, (5) decrease value void SetControlSessionSellOrdInc(const long value) { this.m_control_session_sell_ord_inc=::fabs(value); } void SetControlSessionSellOrdDec(const long value) { this.m_control_session_sell_ord_dec=::fabs(value); } long GetValueChangedSessionSellOrders(void) const { return this.m_changed_session_sell_ord_value; } bool IsIncreaseSessionSellOrders(void) const { return this.m_is_change_session_sell_ord_inc; } bool IsDecreaseSessionSellOrders(void) const { return this.m_is_change_session_sell_ord_dec; } //--- Volume of the last deal //--- setting the last deal volume controlled (1) growth, (2) decrease value //--- getting (3) volume change values in the last deal, //--- getting the flag of the volume change in the last deal exceeding the (4) growth, (5) decrease value void SetControlVolumeInc(const long value) { this.m_control_volume_inc=::fabs(value); } void SetControlVolumeDec(const long value) { this.m_control_volume_dec=::fabs(value); } long GetValueChangedVolume(void) const { return this.m_changed_volume_value; } bool IsIncreaseVolume(void) const { return this.m_is_change_volume_inc; } bool IsDecreaseVolume(void) const { return this.m_is_change_volume_dec; } //--- Maximum volume within a day //--- setting the maximum day volume controlled (1) growth, (2) decrease value //--- getting (3) the maximum volume change value within a day, //--- getting the flag of the maximum day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeHighInc(const long value) { this.m_control_volume_high_day_inc=::fabs(value); } void SetControlVolumeHighDec(const long value) { this.m_control_volume_high_day_dec=::fabs(value); } long GetValueChangedVolumeHigh(void) const { return this.m_changed_volume_high_day_value; } bool IsIncreaseVolumeHigh(void) const { return this.m_is_change_volume_high_day_inc; } bool IsDecreaseVolumeHigh(void) const { return this.m_is_change_volume_high_day_dec; } //--- Minimum volume within a day //--- setting the minimum day volume controlled (1) growth, (2) decrease value //--- getting (3) the minimum volume change value within a day, //--- getting the flag of the minimum day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeLowInc(const long value) { this.m_control_volume_low_day_inc=::fabs(value); } void SetControlVolumeLowDec(const long value) { this.m_control_volume_low_day_dec=::fabs(value); } long GetValueChangedVolumeLow(void) const { return this.m_changed_volume_low_day_value; } bool IsIncreaseVolumeLow(void) const { return this.m_is_change_volume_low_day_inc; } bool IsDecreaseVolumeLow(void) const { return this.m_is_change_volume_low_day_dec; } //--- Spread //--- setting the controlled spread decrease (1) growth, (2) decrease value in points //--- getting (3) spread change value in points, //--- getting the flag of the spread change in points exceeding the (4) growth, (5) decrease value void SetControlSpreadInc(const int value) { this.m_control_spread_inc=::fabs(value); } void SetControlSpreadDec(const int value) { this.m_control_spread_dec=::fabs(value); } int GetValueChangedSpread(void) const { return this.m_changed_spread_value; } bool IsIncreaseSpread(void) const { return this.m_is_change_spread_inc; } bool IsDecreaseSpread(void) const { return this.m_is_change_spread_dec; } //--- StopLevel //--- setting the controlled StopLevel decrease (1) growth, (2) decrease value in points //--- getting (3) StopLevel change value in points, //--- getting the flag of StopLevel change in points exceeding the (4) growth, (5) decrease value void SetControlStopLevelInc(const int value) { this.m_control_stops_level_inc=::fabs(value); } void SetControlStopLevelDec(const int value) { this.m_control_stops_level_dec=::fabs(value); } int GetValueChangedStopLevel(void) const { return this.m_changed_stops_level_value; } bool IsIncreaseStopLevel(void) const { return this.m_is_change_stops_level_inc; } bool IsDecreaseStopLevel(void) const { return this.m_is_change_stops_level_dec; } //--- Freeze distance //--- setting the controlled FreezeLevel decrease (1) growth, (2) decrease value in points //--- getting (3) FreezeLevel change value in points, //--- getting the flag of FreezeLevel change in points exceeding the (4) growth, (5) decrease value void SetControlFreezeLevelInc(const int value) { this.m_control_freeze_level_inc=::fabs(value); } void SetControlFreezeLevelDec(const int value) { this.m_control_freeze_level_dec=::fabs(value); } int GetValueChangedFreezeLevel(void) const { return this.m_changed_freeze_level_value; } bool IsIncreaseFreezeLevel(void) const { return this.m_is_change_freeze_level_inc; } bool IsDecreaseFreezeLevel(void) const { return this.m_is_change_freeze_level_dec; } //--- Bid/Last //--- setting the Bid or Last price controlled (1) growth, (2) decrease value //--- getting (3) Bid or Last price change value, //--- getting the flag of the Bid or Last price change exceeding the (4) growth, (5) decrease value void SetControlBidLastInc(const double value) { this.m_control_bid_last_inc=::fabs(value); } void SetControlBidLastDec(const double value) { this.m_control_bid_last_dec=::fabs(value); } double GetValueChangedBidLast(void) const { return this.m_changed_bid_last_value; } bool IsIncreaseBidLast(void) const { return this.m_is_change_bid_last_inc; } bool IsDecreaseBidLast(void) const { return this.m_is_change_bid_last_dec; } //--- Maximum Bid/Last of the day //--- setting the maximum Bid or Last price controlled (1) growth, (2) decrease value //--- getting the (3) maximum Bid or Last price change value, //--- getting the flag of the maximum Bid or Last price change exceeding the (4) growth, (5) decrease value void SetControlBidLastHighInc(const double value) { this.m_control_bid_last_high_inc=::fabs(value); } void SetControlBidLastHighDec(const double value) { this.m_control_bid_last_high_dec=::fabs(value); } double GetValueChangedBidLastHigh(void) const { return this.m_changed_bid_last_high_value; } bool IsIncreaseBidLastHigh(void) const { return this.m_is_change_bid_last_high_inc; } bool IsDecreaseBidLastHigh(void) const { return this.m_is_change_bid_last_high_dec; } //--- Minimum Bid/Last of the day //--- setting the minimum Bid or Last price controlled (1) growth, (2) decrease value //--- getting the (3) minimum Bid or Last price change value, //--- getting the flag of the minimum Bid or Last price change exceeding the (4) growth, (5) decrease value void SetControlBidLastLowInc(const double value) { this.m_control_bid_last_low_inc=::fabs(value); } void SetControlBidLastLowDec(const double value) { this.m_control_bid_last_low_dec=::fabs(value); } double GetValueChangedBidLastLow(void) const { return this.m_changed_bid_last_low_value; } bool IsIncreaseBidLastLow(void) const { return this.m_is_change_bid_last_low_inc; } bool IsDecreaseBidLastLow(void) const { return this.m_is_change_bid_last_low_dec; } //--- Ask //--- setting the Ask price controlled (1) growth, (2) decrease value //--- getting (3) Ask price change value, //--- getting the flag of the Ask price change exceeding the (4) growth, (5) decrease value void SetControlAskInc(const double value) { this.m_control_ask_inc=::fabs(value); } void SetControlAskDec(const double value) { this.m_control_ask_dec=::fabs(value); } double GetValueChangedAsk(void) const { return this.m_changed_ask_value; } bool IsIncreaseAsk(void) const { return this.m_is_change_ask_inc; } bool IsDecreaseAsk(void) const { return this.m_is_change_ask_dec; } //--- Maximum Ask price for the day //--- setting the maximum day Ask controlled (1) growth, (2) decrease value //--- getting (3) the maximum Ask change value within a day, //--- getting the flag of the maximum day Ask change exceeding the (4) growth, (5) decrease value void SetControlAskHighInc(const double value) { this.m_control_ask_high_inc=::fabs(value); } void SetControlAskHighDec(const double value) { this.m_control_ask_high_dec=::fabs(value); } double GetValueChangedAskHigh(void) const { return this.m_changed_ask_high_value; } bool IsIncreaseAskHigh(void) const { return this.m_is_change_ask_high_inc; } bool IsDecreaseAskHigh(void) const { return this.m_is_change_ask_high_dec; } //--- Minimum Ask price for the day //--- setting the minimum day Ask controlled (1) growth, (2) decrease value //--- getting (3) the minimum Ask change value within a day, //--- getting the flag of the minimum day Ask change exceeding the (4) growth, (5) decrease value void SetControlAskLowInc(const double value) { this.m_control_ask_low_inc=::fabs(value); } void SetControlAskLowDec(const double value) { this.m_control_ask_low_dec=::fabs(value); } double GetValueChangedAskLow(void) const { return this.m_changed_ask_low_value; } bool IsIncreaseAskLow(void) const { return this.m_is_change_ask_low_inc; } bool IsDecreaseAskLow(void) const { return this.m_is_change_ask_low_dec; } //--- Real Volume for the day //--- setting the real day volume controlled (1) growth, (2) decrease value //--- getting (3) the change value of the real day volume, //--- getting the flag of the real day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeRealInc(const double value) { this.m_control_volume_real_inc=::fabs(value); } void SetControlVolumeRealDec(const double value) { this.m_control_volume_real_dec=::fabs(value); } double GetValueChangedVolumeReal(void) const { return this.m_changed_volume_real_value; } bool IsIncreaseVolumeReal(void) const { return this.m_is_change_volume_real_inc; } bool IsDecreaseVolumeReal(void) const { return this.m_is_change_volume_real_dec; } //--- Maximum real volume for the day //--- setting the maximum real day volume controlled (1) growth, (2) decrease value //--- getting (3) the change value of the maximum real day volume, //--- getting the flag of the maximum real day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeHighRealInc(const double value) { this.m_control_volume_high_real_day_inc=::fabs(value); } void SetControlVolumeHighRealDec(const double value) { this.m_control_volume_high_real_day_dec=::fabs(value); } double GetValueChangedVolumeHighReal(void) const { return this.m_changed_volume_high_real_day_value; } bool IsIncreaseVolumeHighReal(void) const { return this.m_is_change_volume_high_real_day_inc; } bool IsDecreaseVolumeHighReal(void) const { return this.m_is_change_volume_high_real_day_dec; } //--- Minimum real volume for the day //--- setting the minimum real day volume controlled (1) growth, (2) decrease value //--- getting (3) the change value of the minimum real day volume, //--- getting the flag of the minimum real day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeLowRealInc(const double value) { this.m_control_volume_low_real_day_inc=::fabs(value); } void SetControlVolumeLowRealDec(const double value) { this.m_control_volume_low_real_day_dec=::fabs(value); } double GetValueChangedVolumeLowReal(void) const { return this.m_changed_volume_low_real_day_value; } bool IsIncreaseVolumeLowReal(void) const { return this.m_is_change_volume_low_real_day_inc; } bool IsDecreaseVolumeLowReal(void) const { return this.m_is_change_volume_low_real_day_dec; } //--- Strike price //--- setting the strike price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the strike price, //--- getting the flag of the strike price change exceeding the (4) growth, (5) decrease value void SetControlOptionStrikeInc(const double value) { this.m_control_option_strike_inc=::fabs(value); } void SetControlOptionStrikeDec(const double value) { this.m_control_option_strike_dec=::fabs(value); } double GetValueChangedOptionStrike(void) const { return this.m_changed_option_strike_value; } bool IsIncreaseOptionStrike(void) const { return this.m_is_change_option_strike_inc; } bool IsDecreaseOptionStrike(void) const { return this.m_is_change_option_strike_dec; } //--- Maximum allowed total volume of unidirectional positions and orders //--- (1) getting the change value of the maximum allowed total volume of unidirectional positions and orders, //--- getting the flag of (2) increasing, (3) decreasing the maximum allowed total volume of unidirectional positions and orders double GetValueChangedVolumeLimit(void) const { return this.m_changed_volume_limit_value; } bool IsIncreaseVolumeLimit(void) const { return this.m_is_change_volume_limit_inc; } bool IsDecreaseVolumeLimit(void) const { return this.m_is_change_volume_limit_dec; } //--- Swap long //--- (1) getting the swap long change value, //--- getting the flag of (2) increasing, (3) decreasing the swap long double GetValueChangedSwapLong(void) const { return this.m_changed_swap_long_value; } bool IsIncreaseSwapLong(void) const { return this.m_is_change_swap_long_inc; } bool IsDecreaseSwapLong(void) const { return this.m_is_change_swap_long_dec; } //--- Swap short //--- (1) getting the swap short change value, //--- getting the flag of (2) increasing, (3) decreasing the swap short double GetValueChangedSwapShort(void) const { return this.m_changed_swap_short_value; } bool IsIncreaseSwapShort(void) const { return this.m_is_change_swap_short_inc; } bool IsDecreaseSwapShort(void) const { return this.m_is_change_swap_short_dec; } //--- The total volume of deals in the current session //--- setting the controlled value of (1) growth, (2) decrease in the total volume of deals during the current session //--- getting (3) the total deal volume change value in the current session, //--- getting the flag of the total deal volume change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionVolumeInc(const double value) { this.m_control_session_volume_inc=::fabs(value); } void SetControlSessionVolumeDec(const double value) { this.m_control_session_volume_dec=::fabs(value); } double GetValueChangedSessionVolume(void) const { return this.m_changed_session_volume_value; } bool IsIncreaseSessionVolume(void) const { return this.m_is_change_session_volume_inc; } bool IsDecreaseSessionVolume(void) const { return this.m_is_change_session_volume_dec; } //--- The total turnover in the current session //--- setting the controlled value of the turnover (1) growth, (2) decrease during the current session //--- getting (3) the total turnover change value in the current session, //--- getting the flag of the total turnover change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionTurnoverInc(const double value) { this.m_control_session_turnover_inc=::fabs(value); } void SetControlSessionTurnoverDec(const double value) { this.m_control_session_turnover_dec=::fabs(value); } double GetValueChangedSessionTurnover(void) const { return this.m_changed_session_turnover_value; } bool IsIncreaseSessionTurnover(void) const { return this.m_is_change_session_turnover_inc; } bool IsDecreaseSessionTurnover(void) const { return this.m_is_change_session_turnover_dec; } //--- The total volume of open positions //--- setting the controlled value of (1) growth, (2) decrease in the total volume of open positions during the current session //--- getting (3) the change value of the open positions total volume in the current session, //--- getting the flag of the open positions total volume change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionInterestInc(const double value) { this.m_control_session_interest_inc=::fabs(value); } void SetControlSessionInterestDec(const double value) { this.m_control_session_interest_dec=::fabs(value); } double GetValueChangedSessionInterest(void) const { return this.m_changed_session_interest_value; } bool IsIncreaseSessionInterest(void) const { return this.m_is_change_session_interest_inc; } bool IsDecreaseSessionInterest(void) const { return this.m_is_change_session_interest_dec; } //--- The total volume of Buy orders at the moment //--- setting the controlled value of (1) growth, (2) decrease in the current total buy order volume //--- getting (3) the change value of the current total buy order volume, //--- getting the flag of the current total buy orders' volume change exceeding the (4) growth, (5) decrease value void SetControlSessionBuyOrdVolumeInc(const double value) { this.m_control_session_buy_ord_volume_inc=::fabs(value); } void SetControlSessionBuyOrdVolumeDec(const double value) { this.m_control_session_buy_ord_volume_dec=::fabs(value); } double GetValueChangedSessionBuyOrdVolume(void) const { return this.m_changed_session_buy_ord_volume_value; } bool IsIncreaseSessionBuyOrdVolume(void) const { return this.m_is_change_session_buy_ord_volume_inc; } bool IsDecreaseSessionBuyOrdVolume(void) const { return this.m_is_change_session_buy_ord_volume_dec; } //--- The total volume of Sell orders at the moment //--- setting the controlled value of (1) growth, (2) decrease in the current total sell order volume //--- getting (3) the change value of the current total sell order volume, //--- getting the flag of the current total sell orders' volume change exceeding the (4) growth, (5) decrease value void SetControlSessionSellOrdVolumeInc(const double value) { this.m_control_session_sell_ord_volume_inc=::fabs(value); } void SetControlSessionSellOrdVolumeDec(const double value) { this.m_control_session_sell_ord_volume_dec=::fabs(value); } double GetValueChangedSessionSellOrdVolume(void) const { return this.m_changed_session_sell_ord_volume_value; } bool IsIncreaseSessionSellOrdVolume(void) const { return this.m_is_change_session_sell_ord_volume_inc; } bool IsDecreaseSessionSellOrdVolume(void) const { return this.m_is_change_session_sell_ord_volume_dec; } //--- Session open price //--- setting the session open price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the session open price, //--- getting the flag of the session open price change exceeding the (4) growth, (5) decrease value void SetControlSessionPriceOpenInc(const double value) { this.m_control_session_open_inc=::fabs(value); } void SetControlSessionPriceOpenDec(const double value) { this.m_control_session_open_dec=::fabs(value); } double GetValueChangedSessionPriceOpen(void) const { return this.m_changed_session_open_value; } bool IsIncreaseSessionPriceOpen(void) const { return this.m_is_change_session_open_inc; } bool IsDecreaseSessionPriceOpen(void) const { return this.m_is_change_session_open_dec; } //--- Session close price //--- setting the session close price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the session close price, //--- getting the flag of the session close price change exceeding the (4) growth, (5) decrease value void SetControlSessionPriceCloseInc(const double value) { this.m_control_session_close_inc=::fabs(value); } void SetControlSessionPriceCloseDec(const double value) { this.m_control_session_close_dec=::fabs(value); } double GetValueChangedSessionPriceClose(void) const { return this.m_changed_session_close_value; } bool IsIncreaseSessionPriceClose(void) const { return this.m_is_change_session_close_inc; } bool IsDecreaseSessionPriceClose(void) const { return this.m_is_change_session_close_dec; } //--- The average weighted session price //--- setting the average weighted session price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the average weighted session price, //--- getting the flag of the average weighted session price change exceeding the (4) growth, (5) decrease value void SetControlSessionPriceAWInc(const double value) { this.m_control_session_aw_inc=::fabs(value); } void SetControlSessionPriceAWDec(const double value) { this.m_control_session_aw_dec=::fabs(value); } double GetValueChangedSessionPriceAW(void) const { return this.m_changed_session_aw_value; } bool IsIncreaseSessionPriceAW(void) const { return this.m_is_change_session_aw_inc; } bool IsDecreaseSessionPriceAW(void) const { return this.m_is_change_session_aw_dec; } //---
在此,为每个受控属性提供了用来设置受控属性变化值的方法。 当超过该值时,将形成一个事件。 可以使用返回事件标志的方法来接收事件标志,同时也可以使用相应的方法来获取变化值。 在函数库论述的第13部分中,我们已经讨论了类似的实现帐户事件跟踪的方法。
在类构造函数中进行了一些修改:
//+------------------------------------------------------------------+ //| Closed parametric constructor | //+------------------------------------------------------------------+ CSymbol::CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index) { this.m_name=name; if(!this.Exist()) { ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\"",": ",TextByLanguage("Ошибка. Такого символа нет на сервере","Error. There is no such symbol on the server")); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; } bool select=::SymbolInfoInteger(this.m_name,SYMBOL_SELECT); ::ResetLastError(); if(!select) { if(!this.SetToMarketWatch()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\": ",TextByLanguage("Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in the market watch. Error: "),this.m_global_error); } } ::ResetLastError(); if(!::SymbolInfoTick(this.m_name,this.m_tick)) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error); } //--- Initialize data this.Reset(); this.InitMarginRates(); ::ZeroMemory(this.m_struct_prev_symbol); this.m_struct_prev_symbol.trade_mode=WRONG_VALUE; this.InitChangesParams(); this.InitControlsParams(); #ifdef __MQL5__ ::ResetLastError(); if(!this.MarginRates()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "),this.m_global_error); return; } #endif //--- Save integer properties this.m_long_prop[SYMBOL_PROP_STATUS] = symbol_status; this.m_long_prop[SYMBOL_PROP_INDEX_MW] = index; this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_DIGITS] = ::SymbolInfoInteger(this.m_name,SYMBOL_DIGITS); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_SPREAD_FLOAT] = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD_FLOAT); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_TRADE_MODE] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_MODE); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_EXEMODE] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_EXEMODE); this.m_long_prop[SYMBOL_PROP_SWAP_ROLLOVER3DAYS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SWAP_ROLLOVER3DAYS); this.m_long_prop[SYMBOL_PROP_TIME] = this.TickTime(); this.m_long_prop[SYMBOL_PROP_EXIST] = this.SymbolExists(); this.m_long_prop[SYMBOL_PROP_CUSTOM] = this.SymbolCustom(); this.m_long_prop[SYMBOL_PROP_MARGIN_HEDGED_USE_LEG] = this.SymbolMarginHedgedUseLEG(); this.m_long_prop[SYMBOL_PROP_ORDER_MODE] = this.SymbolOrderMode(); this.m_long_prop[SYMBOL_PROP_FILLING_MODE] = this.SymbolOrderFillingMode(); this.m_long_prop[SYMBOL_PROP_EXPIRATION_MODE] = this.SymbolExpirationMode(); this.m_long_prop[SYMBOL_PROP_ORDER_GTC_MODE] = this.SymbolOrderGTCMode(); this.m_long_prop[SYMBOL_PROP_OPTION_MODE] = this.SymbolOptionMode(); this.m_long_prop[SYMBOL_PROP_OPTION_RIGHT] = this.SymbolOptionRight(); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); this.m_long_prop[SYMBOL_PROP_CHART_MODE] = this.SymbolChartMode(); this.m_long_prop[SYMBOL_PROP_TRADE_CALC_MODE] = this.SymbolCalcMode(); this.m_long_prop[SYMBOL_PROP_SWAP_MODE] = this.SymbolSwapMode(); //--- Save real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_POINT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_POINT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; //--- Save string properties this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)] = this.m_name; this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_BASE); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_PROFIT); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_MARGIN); this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)] = ::SymbolInfoString(this.m_name,SYMBOL_DESCRIPTION); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)] = ::SymbolInfoString(this.m_name,SYMBOL_PATH); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)] = this.SymbolBasis(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)] = this.SymbolBank(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)] = this.SymbolISIN(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)] = this.SymbolFormula(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)] = this.SymbolPage(); //--- Save additional integer properties this.m_long_prop[SYMBOL_PROP_DIGITS_LOTS] = this.SymbolDigitsLot(); //--- if(!select) this.RemoveFromMarketWatch(); } //+------------------------------------------------------------------+
现在,构造函数接收市场观察品种索引,将品种名称分配给对象名称,并重置先前品种数据的结构 。 先前的数据结构字段 trade_mode 含有 WRONG_VALUE(在交易模式字段中此值的存在令我们能够 定义首次启动)。 初始化品种属性的 已变化和受控变量。 传递给构造函数的索引被写入品种属性的“市场观察窗口索引”。
从现在开始,我们在 CBaseObj 基类中有了 m_name 变量来存储对象名称(在我们的示例中是品种名称),即 CSymbol 类应该不再含有 m_symbol_name 变量。 所有曾出现的情况都应当由 m_name 替换(在类构造函数中为已分配品种名称)。
在 Symbol 类的清单中高亮选择所有 this.m symbol_name 的文本,然后按 Ctrl+H 。 搜索和替换窗口出现,高亮选择的事件已插入搜索字段。 在替换字段中输入 this.m_name ,并将清单中所有检测到的曾出现 this.m_symbol_name 都替换为 this.m_name。
我们还应删除目前还位于 CBaseObj 基准对象中的其余类成员变量。 它们出现在 CSymbol 中会于编译期间触发变量重复警告。 在如下所附的文件中,所有此类变量已被删除。 只需下载文件并查看其内容即可。
将品种属性的新“市场观察窗口索引”描述添加到返回整数型属性描述的方法中:
//+------------------------------------------------------------------+ //| Return the description of the symbol integer property | //+------------------------------------------------------------------+ string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property) { return ( property==SYMBOL_PROP_STATUS ? TextByLanguage("Статус","Status")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_INDEX_MW ? TextByLanguage("Индекс в окне \"Обзор рынка\"","Index in the \"Market Watch window\"")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetStatusDescription() ) : property==SYMBOL_PROP_CUSTOM ? TextByLanguage("Пользовательский символ","Custom symbol")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_CHART_MODE ? TextByLanguage("Тип цены для построения баров","Price type used for generating symbols bars")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetChartModeDescription() ) : property==SYMBOL_PROP_EXIST ? TextByLanguage("Символ с таким именем существует","Symbol with this name exists")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_SELECT ? TextByLanguage("Символ выбран в Market Watch","Symbol selected in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_VISIBLE ? TextByLanguage("Символ отображается в Market Watch","Symbol visible in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_SESSION_DEALS ? TextByLanguage("Количество сделок в текущей сессии","Number of deals in the current session")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_SESSION_BUY_ORDERS ? TextByLanguage("Общее число ордеров на покупку в текущий момент","Number of Buy orders at the moment")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_SESSION_SELL_ORDERS ? TextByLanguage("Общее число ордеров на продажу в текущий момент","Number of Sell orders at the moment")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_VOLUME ? TextByLanguage("Объем в последней сделке","Volume of the last deal")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_VOLUMEHIGH ? TextByLanguage("Максимальный объём за день","Maximal day volume")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_VOLUMELOW ? TextByLanguage("Минимальный объём за день","Minimal day volume")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_TIME ? TextByLanguage("Время последней котировки","Time of the last quote")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property)==0 ? TextByLanguage("(Ещё не было тиков)","(No ticks yet)") : TimeMSCtoString(this.GetProperty(property))) ) : property==SYMBOL_PROP_DIGITS ? TextByLanguage("Количество знаков после запятой","Digits after decimal point")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_DIGITS_LOTS ? TextByLanguage("Количество знаков после запятой в значении лота","Digits after decimal point in the value of the lot")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_SPREAD ? TextByLanguage("Размер спреда в пунктах","Spread value in points")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_SPREAD_FLOAT ? TextByLanguage("Плавающий спред","Spread is floating")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_TICKS_BOOKDEPTH ? TextByLanguage("Максимальное количество показываемых заявок в стакане","Maximal number of requests shown in Depth of Market")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_TRADE_CALC_MODE ? TextByLanguage("Способ вычисления стоимости контракта","Contract price calculation mode")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetCalcModeDescription() ) : property==SYMBOL_PROP_TRADE_MODE ? TextByLanguage("Тип исполнения ордеров","Order execution type")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetTradeModeDescription() ) : property==SYMBOL_PROP_START_TIME ? TextByLanguage("Дата начала торгов по инструменту","Date of symbol trade beginning")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : (this.GetProperty(property)==0 ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000)) ) : property==SYMBOL_PROP_EXPIRATION_TIME ? TextByLanguage("Дата окончания торгов по инструменту","Date of symbol trade end")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : (this.GetProperty(property)==0 ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000)) ) : property==SYMBOL_PROP_TRADE_STOPS_LEVEL ? TextByLanguage("Минимальный отступ от цены закрытия для установки Stop ордеров","Minimal indention from close price to place Stop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_TRADE_FREEZE_LEVEL ? TextByLanguage("Дистанция заморозки торговых операций","Distance to freeze trade operations in points")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_TRADE_EXEMODE ? TextByLanguage("Режим заключения сделок","Deal execution mode")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetTradeExecDescription() ) : property==SYMBOL_PROP_SWAP_MODE ? TextByLanguage("Модель расчета свопа","Swap calculation model")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetSwapModeDescription() ) : property==SYMBOL_PROP_SWAP_ROLLOVER3DAYS ? TextByLanguage("День недели для начисления тройного свопа","Day of week to charge 3 days swap rollover")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+DayOfWeekDescription(this.SwapRollover3Days()) ) : property==SYMBOL_PROP_MARGIN_HEDGED_USE_LEG ? TextByLanguage("Расчет хеджированной маржи по наибольшей стороне","Calculating hedging margin using the larger leg")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_EXPIRATION_MODE ? TextByLanguage("Флаги разрешенных режимов истечения ордера","Flags of allowed order expiration modes")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetExpirationModeFlagsDescription() ) : property==SYMBOL_PROP_FILLING_MODE ? TextByLanguage("Флаги разрешенных режимов заливки ордера","Flags of allowed order filling modes")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetFillingModeFlagsDescription() ) : property==SYMBOL_PROP_ORDER_MODE ? TextByLanguage("Флаги разрешённых типов ордеров","Flags of allowed order types")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOrderModeFlagsDescription() ) : property==SYMBOL_PROP_ORDER_GTC_MODE ? TextByLanguage("Срок действия StopLoss и TakeProfit ордеров","Expiration of Stop Loss and Take Profit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOrderGTCModeDescription() ) : property==SYMBOL_PROP_OPTION_MODE ? TextByLanguage("Тип опциона","Option type")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOptionTypeDescription() ) : property==SYMBOL_PROP_OPTION_RIGHT ? TextByLanguage("Право опциона","Option right")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOptionRightDescription() ) : property==SYMBOL_PROP_BACKGROUND_COLOR ? TextByLanguage("Цвет фона символа в Market Watch","Background color of symbol in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : #ifdef __MQL5__ (this.GetProperty(property)==CLR_DEFAULT || this.GetProperty(property)==CLR_NONE ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true)) #else TextByLanguage(": Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : "" ); } //+------------------------------------------------------------------+
从 CSymbol 类方法实现清单中删除 Exist() 方法的第二种形式,和返回数字值中小数位数的方法:
//+------------------------------------------------------------------+
bool CSymbol::Exist(const string name) const
{
int total=::SymbolsTotal(false);
for(int i=0;i<total;i++)
if(::SymbolName(i,false)==name)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Return the number of decimal places in the 'double' value |
//+------------------------------------------------------------------+
int CSymbol::GetDigits(const double value) const
{
string val_str=(string)value;
int len=::StringLen(val_str);
int n=len-::StringFind(val_str,".",0)-1;
if(::StringSubstr(val_str,len-1,1)=="0")
n--;
return n;
}
//+------------------------------------------------------------------+
这些方法在此已是多余的 — 在此类中不需要带输入的 Exist()。 所以,我将其移至服务函数的 DELib.mqh 文件中,这是正确的位置,而 GetDigits()现在位于 CBaseObj 基类中。
CSymbol 类的 Refresh() 方法从计时器启动,并刷新所有品种数据。 我们将以相同的方法搜索品种属性的变化。 我们还有另一种方法 — RefreshRates(),它也从计时器启动,但刷新率较高。 此方法仅刷新品种报价数据。 如果我们在这两个方法中都实现了搜索品种属性变化,这将导致事件消息重复。
可能的解决方案如下:RefreshRates() 方法刷新报价数据,并返回其成功接收的标志。 该方法将像以前一样从其计时器中调用。 但在 Refresh() 方法里也新增对它的调用。 因此,这两种方法都能像以前一样被调用 — 每个方法都在计时器中进行,而仅在 Refresh() 方法中执行搜索品种属性变化。
我们针对 RefreshRates() 和 Refresh() 方法添加必要的修改:
//+------------------------------------------------------------------+ //| Update quote data by a symbol | //+------------------------------------------------------------------+ bool CSymbol::RefreshRates(void) { //--- Get quote data ::ResetLastError(); if(!::SymbolInfoTick(this.m_name,this.m_tick)) { this.m_global_error=::GetLastError(); return false; } //--- Update integer properties this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = this.TickTime(); //--- Update real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTLOW); return true; } //+------------------------------------------------------------------+
首先,获取品种报价数据。 如果获取失败,则写入错误代码,退出方法,并返回 false 。 如果已获取数据,则填写必要的品种属性,然后返回 true 。
//+------------------------------------------------------------------+ //| Update all symbol data | //+------------------------------------------------------------------+ void CSymbol::Refresh(void) { //--- Update quote data if(!this.RefreshRates()) return; #ifdef __MQL5__ ::ResetLastError(); if(!this.MarginRates()) { this.m_global_error=::GetLastError(); return; } #endif //--- Prepare event data this.m_is_event=false; ::ZeroMemory(this.m_struct_curr_symbol); this.m_hash_sum=0; //--- Update integer properties this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); //--- Update real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; //--- Fill in the current symbol data structure this.m_struct_curr_symbol.ask = this.Ask(); this.m_struct_curr_symbol.ask_high = this.AskHigh(); this.m_struct_curr_symbol.ask_low = this.AskLow(); this.m_struct_curr_symbol.bid_last = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.Bid() : this.Last()); this.m_struct_curr_symbol.bid_last_high = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.BidHigh() : this.LastHigh()); this.m_struct_curr_symbol.bid_last_low = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.BidLow() : this.LastLow()); this.m_struct_curr_symbol.volume = this.Volume(); this.m_struct_curr_symbol.session_deals = this.SessionDeals(); this.m_struct_curr_symbol.session_buy_orders = this.SessionBuyOrders(); this.m_struct_curr_symbol.session_sell_orders = this.SessionSellOrders(); this.m_struct_curr_symbol.volume_high_day = this.VolumeHigh(); this.m_struct_curr_symbol.volume_low_day = this.VolumeLow(); this.m_struct_curr_symbol.spread = this.Spread(); this.m_struct_curr_symbol.stops_level = this.TradeStopLevel(); this.m_struct_curr_symbol.freeze_level = this.TradeFreezeLevel(); this.m_struct_curr_symbol.volume_limit = this.VolumeLimit(); this.m_struct_curr_symbol.swap_long = this.SwapLong(); this.m_struct_curr_symbol.swap_short = this.SwapShort(); this.m_struct_curr_symbol.session_volume = this.SessionVolume(); this.m_struct_curr_symbol.session_turnover = this.SessionTurnover(); this.m_struct_curr_symbol.session_interest = this.SessionInterest(); this.m_struct_curr_symbol.session_buy_ord_volume = this.SessionBuyOrdersVolume(); this.m_struct_curr_symbol.session_sell_ord_volume = this.SessionSellOrdersVolume(); this.m_struct_curr_symbol.session_open = this.SessionOpen(); this.m_struct_curr_symbol.session_close = this.SessionClose(); this.m_struct_curr_symbol.session_aw = this.SessionAW(); this.m_struct_curr_symbol.volume_real_day = this.VolumeReal(); this.m_struct_curr_symbol.volume_high_real_day = this.VolumeHighReal(); this.m_struct_curr_symbol.volume_low_real_day = this.VolumeLowReal(); this.m_struct_curr_symbol.option_strike = this.OptionStrike(); this.m_struct_curr_symbol.trade_mode = this.TradeMode(); //--- Hash sum calculation this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume; this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_deals; this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_buy_orders; this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_sell_orders; this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume_high_day; this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume_low_day; this.m_hash_sum+=(double)this.m_struct_curr_symbol.spread; this.m_hash_sum+=(double)this.m_struct_curr_symbol.stops_level; this.m_hash_sum+=(double)this.m_struct_curr_symbol.freeze_level; this.m_hash_sum+=this.m_struct_curr_symbol.ask; this.m_hash_sum+=this.m_struct_curr_symbol.ask_high; this.m_hash_sum+=this.m_struct_curr_symbol.ask_low; this.m_hash_sum+=this.m_struct_curr_symbol.bid_last; this.m_hash_sum+=this.m_struct_curr_symbol.bid_last_high; this.m_hash_sum+=this.m_struct_curr_symbol.bid_last_low; this.m_hash_sum+=this.m_struct_curr_symbol.volume_limit; this.m_hash_sum+=this.m_struct_curr_symbol.swap_long; this.m_hash_sum+=this.m_struct_curr_symbol.swap_short; this.m_hash_sum+=this.m_struct_curr_symbol.session_volume; this.m_hash_sum+=this.m_struct_curr_symbol.session_turnover; this.m_hash_sum+=this.m_struct_curr_symbol.session_interest; this.m_hash_sum+=this.m_struct_curr_symbol.session_buy_ord_volume; this.m_hash_sum+=this.m_struct_curr_symbol.session_sell_ord_volume; this.m_hash_sum+=this.m_struct_curr_symbol.session_open; this.m_hash_sum+=this.m_struct_curr_symbol.session_close; this.m_hash_sum+=this.m_struct_curr_symbol.session_aw; this.m_hash_sum+=this.m_struct_curr_symbol.volume_real_day; this.m_hash_sum+=this.m_struct_curr_symbol.volume_high_real_day; this.m_hash_sum+=this.m_struct_curr_symbol.volume_low_real_day; this.m_hash_sum+=this.m_struct_curr_symbol.option_strike; this.m_hash_sum+=this.m_struct_curr_symbol.trade_mode; //--- First launch if(this.m_struct_prev_symbol.trade_mode==WRONG_VALUE) { this.m_struct_prev_symbol=this.m_struct_curr_symbol; this.m_hash_sum_prev=this.m_hash_sum; return; } //--- If symbol's hash sum changed if(this.m_hash_sum!=this.m_hash_sum_prev) { this.m_event_code=this.SetEventCode(); this.SetTypeEvent(); CEventBaseObj *event=this.GetEvent(WRONG_VALUE,false); if(event!=NULL) { ENUM_SYMBOL_EVENT event_id=(ENUM_SYMBOL_EVENT)event.ID(); if(event_id!=SYMBOL_EVENT_NO_EVENT) { this.m_is_event=true; } } this.m_hash_sum_prev=this.m_hash_sum; } } //+------------------------------------------------------------------+
在此,我们首先调用 RefreshRates() 方法。 如果无法获取报价数据,则获取其余的数据毫无意义。 退出方法。
接下来,重置事件标志,当前品种属性状态的结构和当前哈希和。 然后, 用当前数据填充所有品种属性,并将这些数据写入当前品种属性状态的结构。 填充结构后,计算哈希和。
如果这是首次启动( SYMBOL_TRADE_MODE 品种属性设置为 WRONG_VALUE ),则将当前状态结构的值保存为先前的状态结构,将当前哈希值写入当前值,然后退出该方法。
如果这不是首次启动,则需要检查先前和当前的哈希和是否不一致。
如果哈希和已变化,则品种属性已变化。 调用放置事件代码的方法,从已发生事件列表里获取事件代码和事件项的方法,并从新添加的事件里获取最后事件。 检查事件类型。 如果它不是“无事件”,则激活事件标志。 最后,将当前的哈希和保存为前一个,以供以后检查。
CSymbol 类当中搜索事件并处理新基准对象的改进就此完毕。
品种对象类已然准备就绪。 现在,每个品种都能够跟踪其事件,并将其放入它的事件列表。 鉴于我们要用到品种集合,因此我们需要循环遍历所有集合品种,从它们当中得到一个事件列表。 所有这些事件都应放置到集合事件列表中(现在,集合具有相同的列表,因为它位于 CBaseObj 基准对象中)。 因此,仅余的步骤就是调查获得的事件列表,定义品种集合里的每一个都发生了一次或多次事件的事实。
打开品种集合类的 SymbolsCollection.mqh 文件,并进行必要的修改:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayString.mqh> #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Symbol collection | //+------------------------------------------------------------------+ class CSymbolsCollection : public CBaseObj { private: CListObj m_list_all_symbols; // The list of all symbol objects CArrayString m_list_names; // Symbol name control list ENUM_SYMBOLS_MODE m_mode_list; // Mode of working with symbol lists ENUM_SYMBOL_EVENT m_last_event; // The last event string m_array_symbols[]; // The array of used symbols passed from the program int m_delta_symbol; // Difference in the number of symbols compared to the previous check int m_total_symbols; // Number of symbols in the Market Watch window int m_total_symbol_prev; // Number of symbols in the Market Watch window during the previous check //--- Return the flag of a symbol object presence by its name in the (1) list of all symbols, (2) Market Watch window, (3) control list bool IsPresentSymbolInList(const string symbol_name); bool IsPresentSymbolInMW(const string symbol_name); bool IsPresentSymbolInControlList(const string symbol_name); //--- Create the symbol object and place it to the list bool CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index); //--- Return the (1) type of a used symbol list (Market watch/Server), //--- (2) the number of visible symbols, (3) symbol index in the Market Watch window ENUM_SYMBOLS_MODE TypeSymbolsList(const string &symbol_used_array[]); int SymbolsTotalVisible(void) const; int SymbolIndexInMW(const string name) const; //--- Define a symbol affiliation with a group by name and return it ENUM_SYMBOL_STATUS SymbolStatus(const string symbol_name) const; //--- Return a symbol affiliation with a category by custom criteria ENUM_SYMBOL_STATUS StatusByCustomPredefined(const string symbol_name) const; //--- Return a symbol affiliation with categories by margin calculation ENUM_SYMBOL_STATUS StatusByCalcMode(const string symbol_name) const; //--- Return a symbol affiliation with pre-defined (1) majors, (2) minors, (3) exotics, (4) RUB, //--- (5) indicatives, (6) metals, (7) commodities, (8) indices, (9) cryptocurrency, (10) options bool IsPredefinedFXMajor(const string name) const; bool IsPredefinedFXMinor(const string name) const; bool IsPredefinedFXExotic(const string name) const; bool IsPredefinedFXRUB(const string name) const; bool IsPredefinedIndicative(const string name) const; bool IsPredefinedMetall(const string name) const; bool IsPredefinedCommodity(const string name) const; bool IsPredefinedIndex(const string name) const; bool IsPredefinedCrypto(const string name) const; bool IsPredefinedOption(const string name) const; public: //--- Return the full collection list 'as is' CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Return the (1) symbol object, (2) the symbol object index from the list by a name CSymbol *GetSymbolByName(const string name); int GetSymbolIndexByName(const string name); //--- Return the number of new symbols in the Market Watch window int NewSymbols(void) const { return this.m_delta_symbol; } //--- Return (1) the mode of working with symbol lists, (2) the event flag and (3) the event of one of the collection symbols ENUM_SYMBOLS_MODE ModeSymbolsList(void) const { return this.m_mode_list; } bool IsEvent(void) const { return this.m_is_event; } int GetLastEventsCode(void) const { return this.m_event_code; } ENUM_SYMBOL_EVENT GetLastEvent(void) const { return this.m_last_event; } //--- Return the number of symbols in the collection int GetSymbolsCollectionTotal(void) const { return this.m_list_all_symbols.Total(); } //--- Constructor CSymbolsCollection(); //--- (1) Set the list of used symbols, (2) creating the symbol list (Market Watch or the complete list) bool SetUsedSymbols(const string &symbol_used_array[]); bool CreateSymbolsList(const bool flag); //--- Save names of used Market Watch symbols void CopySymbolsNames(void); //--- Update (1) all, (2) quote data of the collection symbols virtual void Refresh(void); void RefreshRates(void); //--- Working with the events of the (1) collection symbol list, (2) market watch window void SymbolsEventsControl(void); void MarketWatchEventsControl(const bool send_events=true); //--- Return the description of the (1) Market Watch window event, (2) mode of working with symbols string EventDescription(const ENUM_SYMBOL_EVENT event); string ModeSymbolsListDescription(void); }; //+------------------------------------------------------------------+
标准库中包含的 CArrayString 类文件将用于创建“市场观察”窗口的快照。 该列表用于存储来自市场观察的交易品种组的副本,并将窗口中交易品种组的当前状态与快照中的状态进行比较。 若有任何变化,我们应对其做出反应,以便创建“市场观察”窗口事件。
发生在任何集合品种上的最后一个事件都会添加到 m_last_event 变量中。 因此,该变量存储所用品种之一的最新发生事件。
m_array_symbols 数组将所用品种数组从控制程序传递到品种集合类。
“市场观察”窗口中的当前和先前交易品种数量将分别存储在 m_total_symbols 和 m_total_symbols_prev 类成员变量之中。 比较变量的数值即可令我们定义在市场观察中添加和删除品种的事件。
类的私密方法 IsPresentSymbolInMW() 和 IsPresentSymbolInControlList() 按其名称查找市场观察窗口,以及市场观察窗口的快照列表,并返回该品种的存在标志。 SymbolsTotalVisible() 和 SymbolIndexInMW() 方法返回“市场观察”窗口中可见品种的数量,以及品种在窗口列表中相应的位置索引。
将以下方法添加到类的公开部分:
IsEvent() — 返回品种集合当中的品种存在于“市场观察”窗口的事件标志,
GetLastEventsCode() — 返回交易品种集合或“市场观察”窗口中最后一个事件的代码,
GetLastEvent() — 返回交易品种集合或“市场观察”窗口中的最后一个事件,
GetSymbolsCollectionTotal() — 返回集合中的品种总数,
CreateSymbolsList() — 依据“市场观察”窗口或服务器上(不超过1000个)的完整交易品种创建集合列表,
CopySymbolsNames() — 依据全部集合品种列表创建市场观察窗口品种的快照,
Refresh() — 现在,该方法已声明为虚方法,因为它已在基类对象中声明为虚方法(而品种集合现在是基于 CBaseObj 基准对象类而创建的),
SymbolsEventsControl() — 操控品种集合列表并定义品种集合事件的方法,
MarketWatchEventsControl() — 操控“市场观察”窗口列表,并定义市场观察窗口中事件的方法,
EventDescription() — 返回品种集合事件的描述,
ModeSymbolsListDescription() — 返回品种处理模式的描述。
我们看一下这些方法的实现。
在类构造函数的初始化清单中,为操控“市场观察”窗口而初始化变量。 在类的实体中,将集合品种的排序从“按名称排序”更改为“ 在“市场观察”窗口中按索引排序” ,然后清除“市场观察”窗口快照列表。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CSymbolsCollection::CSymbolsCollection(void) : m_total_symbol_prev(0), m_delta_symbol(0), m_mode_list(SYMBOLS_MODE_CURRENT) { this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Type(COLLECTION_SYMBOLS_ID); this.m_list_names.Clear(); } //+------------------------------------------------------------------+
由于某些品种可能在“市场观察”窗口中不可见,但实际上仍然存在( SYMBOL_VISIBLE 品种属性),因此某些品种(通常,这些是交叉盘,用于按入金货币计算保证金需求和利润 )会自动被选择,且不会显示在市场观察当中。 所以,为了仅找出可见品种的数量,我们需要在循环里遍历窗口计算具有此属性的品种。
SymbolsTotalVisible() 方法返回“市场观察”窗口中可见品种的数量:
//+------------------------------------------------------------------+ //| Return the number of visible symbols in the Market Watch window | //+------------------------------------------------------------------+ int CSymbolsCollection::SymbolsTotalVisible(void) const { int total=::SymbolsTotal(true),n=0; for(int i=0;i<total;i++) { if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE)) continue; n++; } return n; } //+------------------------------------------------------------------+
返回“市场观察”窗口列表中的交易品种索引的方法:
//+------------------------------------------------------------------+ //| Return symbol index in the Market Watch window | //+------------------------------------------------------------------+ int CSymbolsCollection::SymbolIndexInMW(const string name) const { int total=::SymbolsTotal(true); for(int i=0;i<total;i++) { if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE)) continue; if(SymbolName(i,true)==name) return i; } return WRONG_VALUE; } //+------------------------------------------------------------------+
当操控“市场观察”窗口中的品种列表时,我们需要找出窗口列表中每个品种的索引,以便能够将集合品种列表中的品种位置与市场观察窗口中的品种位置同步。 例如,创建自定义品种列表窗口,并与终端窗口完全同步的时候也许很有用。 索引是品种属性之一,可令我们按其对列表进行排序。 该索引将传递给抽象品种类构造函数。
该方法返回可见品种在“市场观察”窗口中存在的标志:
//+------------------------------------------------------------------+ //| Return the visible symbol object presence flag | //| by its name in the Market Watch window | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPresentSymbolInMW(const string symbol_name) { int total=SymbolsTotal(true); for(int i=0;i<total;i++) { string name=::SymbolName(i,true); if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; if(name==symbol_name) return true; } return false; } //+------------------------------------------------------------------+
该方法接收品种名称,然后,市场观察窗口中选择所有品种的完整列表作为循环,我们 跳过不可见的品种,将下一个品种的名称与传递给该方法的品种进行比较。 如果匹配,返回 true 。 如果在列表里未发现该品种,返回 false 。
该方法返回交易品种出现在市场观察窗口快照列表中的标志:
//+------------------------------------------------------------------+ //| Return the flag of a symbol object presence in the control list | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPresentSymbolInControlList(const string symbol_name) { int total=this.m_list_names.Total(); for(int i=0;i<total;i++) { string name=this.m_list_names.At(i); if(name==NULL) continue; if(name==symbol_name) return true; } return false; } //+------------------------------------------------------------------+
必须将品种名称传递给方法。 循环遍历市场观察窗口快照列表,接收必要的品种,如果其名称与传递给该方法的名称匹配,则返回 true ,否则 — false 。
依据所操控“市场观察”窗口,或服务器上的完整品种列表创建列表的方法:
//+------------------------------------------------------------------+ //| Creating the symbol list (Market Watch or the complete list) | //+------------------------------------------------------------------+ bool CSymbolsCollection::CreateSymbolsList(const bool flag) { bool res=true; int total=::SymbolsTotal(flag); for(int i=0;i<total && i<SYMBOLS_COMMON_TOTAL;i++) { string name=::SymbolName(i,flag); if(flag && !::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name,i); res &=add; if(!add) continue; } return res; } //+------------------------------------------------------------------+
该方法接收标志设置搜索模式: true — 操控市场观察窗口中选定的交易品种, false — 操控服务器上存在的完整品种列表。 根据标志获取品种总数 — 即可是市场观察窗口,亦或是服务器上,且按列表循环,但不超过 Defines.mqh 文件里的 SYMBOLS_COMMON_TOTAL 常量设置的值(1000 品种),从列表中获取下一个品种的名称,如果操控的是市场观察窗口,则检查其可见性属性,如果不可见,则跳过该品种。
然后通过名称获取品种对象状态,并利用上一篇文章中研究过的 CreateNewSymbol() 方法将品种添加到所有集合品种列表中。 (请注意,由于加入了新的交易品种属性,该方法已略作修改 — 在“市场观察”窗口交易品种列表中的索引。 现在,索引也传递给了品种对象。
将每个品种添加到所有集合品种列表中的结果,返回到方法并保存在变量中,且在方法处理完整个品种循环后,返回该变量的总值。
我们来研究改进创建品种对象,及其在列表中位置的方法:
//+------------------------------------------------------------------+ //| Create a symbol object and place it to the list | //+------------------------------------------------------------------+ bool CSymbolsCollection::CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index) { if(this.IsPresentSymbolInList(name)) { return true; } if(#ifdef __MQL5__ !::SymbolInfoInteger(name,SYMBOL_EXIST) #else !Exist(name) #endif ) { string t1=TextByLanguage("Ошибка входных данных: нет символа ","Input error: no "); string t2=TextByLanguage(" на сервере"," symbol on the server"); ::Print(DFUN,t1,name,t2); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; return false; } CSymbol *symbol=NULL; switch(symbol_status) { case SYMBOL_STATUS_FX : symbol=new CSymbolFX(name,index); break; // Forex symbol case SYMBOL_STATUS_FX_MAJOR : symbol=new CSymbolFXMajor(name,index); break; // Major Forex symbol case SYMBOL_STATUS_FX_MINOR : symbol=new CSymbolFXMinor(name,index); break; // Minor Forex symbol case SYMBOL_STATUS_FX_EXOTIC : symbol=new CSymbolFXExotic(name,index); break; // Exotic Forex symbol case SYMBOL_STATUS_FX_RUB : symbol=new CSymbolFXRub(name,index); break; // Forex symbol/RUR case SYMBOL_STATUS_METAL : symbol=new CSymbolMetall(name,index); break; // Metal case SYMBOL_STATUS_INDEX : symbol=new CSymbolIndex(name,index); break; // Index case SYMBOL_STATUS_INDICATIVE : symbol=new CSymbolIndicative(name,index); break; // Indicative case SYMBOL_STATUS_CRYPTO : symbol=new CSymbolCrypto(name,index); break; // Cryptocurrency symbol case SYMBOL_STATUS_COMMODITY : symbol=new CSymbolCommodity(name,index); break; // Commodity case SYMBOL_STATUS_EXCHANGE : symbol=new CSymbolExchange(name,index); break; // Exchange symbol case SYMBOL_STATUS_FUTURES : symbol=new CSymbolFutures(name,index); break; // Futures case SYMBOL_STATUS_CFD : symbol=new CSymbolCFD(name,index); break; // CFD case SYMBOL_STATUS_STOCKS : symbol=new CSymbolStocks(name,index); break; // Stock case SYMBOL_STATUS_BONDS : symbol=new CSymbolBonds(name,index); break; // Bond case SYMBOL_STATUS_OPTION : symbol=new CSymbolOption(name,index); break; // Option case SYMBOL_STATUS_COLLATERAL : symbol=new CSymbolCollateral(name,index); break; // Non-tradable asset case SYMBOL_STATUS_CUSTOM : symbol=new CSymbolCustom(name,index); break; // Custom symbol default : symbol=new CSymbolCommon(name,index); break; // The rest } if(symbol==NULL) { ::Print(DFUN,TextByLanguage("Не удалось создать объект-символ ","Failed to create symbol object "),name); return false; } if(!this.m_list_all_symbols.Add(symbol)) { string t1=TextByLanguage("Не удалось добавить символ ","Failed to add "); string t2=TextByLanguage(" в список"," symbol to the list"); ::Print(DFUN,t1,name,t2); delete symbol; return false; } return true; } //+------------------------------------------------------------------+
如清单中所见,这里我们还附加了将品种名称与其索引发送给每个品种对象类构造函数的代码。 这意味着我们需要重新调整从 CSymbol 抽象品种类派生出的每个子类。
我们以 CSymbolFX 类为例来研究如何改进:
//+------------------------------------------------------------------+ //| SymbolFX.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Symbol.mqh" //+------------------------------------------------------------------+ //| Forex symbol | //+------------------------------------------------------------------+ class CSymbolFX : public CSymbol { public: //--- Constructor CSymbolFX(const string name,const int index) : CSymbol(SYMBOL_STATUS_FX,name,index) {} //--- Supported integer properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Supported real properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Supported string properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Display a short symbol description in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+
在此,除了品种名称之外,类构造函数还接收其索引,并在初始化清单里将索引传递到 CSymbol 父类构造函数中。
这就是在抽象品种派生的所有类中需要修改的全部内容。 附带于下的文件中,已针对品种对象类进行了所有修改。
改进方法会在集合中设置所用品种列表:
//+------------------------------------------------------------------+ //| Set the list of used symbols | //+------------------------------------------------------------------+ bool CSymbolsCollection::SetUsedSymbols(const string &symbol_used_array[]) { ::ArrayCopy(this.m_array_symbols,symbol_used_array); this.m_mode_list=this.TypeSymbolsList(this.m_array_symbols); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW); //--- Use only the current symbol if(this.m_mode_list==SYMBOLS_MODE_CURRENT) { string name=::Symbol(); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); return this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name)); } else { bool res=true; //--- Use the pre-defined symbol list if(this.m_mode_list==SYMBOLS_MODE_DEFINES) { int total=::ArraySize(this.m_array_symbols); for(int i=0;i<total;i++) { string name=this.m_array_symbols[i]; ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name)); res &=add; if(!add) continue; } return res; } //--- Use the full list of the server symbols else if(this.m_mode_list==SYMBOLS_MODE_ALL) { return this.CreateSymbolsList(false); } //--- Use the symbol list from the Market Watch window else if(this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH) { this.MarketWatchEventsControl(false); return true; } } return false; } //+------------------------------------------------------------------+
在此,将控制程序传递来的所用品种数组复制到自定义数组。 保存操控品种的模式,将所有品种列表的排序设置为按索引排序。 现在, 创建新品种对象的方法除了品种名称之外现在还接收其索引。
当使用服务器上所有品种的完整列表时,调用构造集合品种列表的方法,参数 flag = false,该标志表示依据服务器上的完整品种列表构造。
在“市场观察”窗口中使用列表时,调用操控市场观察窗口的方法,参数 flag= false,这表示需要创建并填写列表,而非完全禁止使用事件。
处理所有集合品种事件的方法:
//+------------------------------------------------------------------+ //| Working with the events of the collection symbol list | //+------------------------------------------------------------------+ void CSymbolsCollection::SymbolsEventsControl(void) { this.m_is_event=false; this.m_list_events.Clear(); this.m_list_events.Sort(); //--- The full update of all collection symbols int total=this.m_list_all_symbols.Total(); for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.Refresh(); if(!symbol.IsEvent()) continue; this.m_is_event=true; CArrayObj *list=symbol.GetListEvents(); if(list==NULL) continue; this.m_event_code=symbol.GetEventCode(); int n=list.Total(); for(int j=0; j<n; j++) { CEventBaseObj *event=list.At(j); if(event==NULL) continue; ENUM_SYMBOL_EVENT event_id=(ENUM_SYMBOL_EVENT)event.ID(); if(event_id==SYMBOL_EVENT_NO_EVENT) continue; this.m_last_event=event_id; if(this.EventAdd((ushort)event.ID(),event.LParam(),event.DParam(),event.SParam())) { ::EventChartCustom(this.m_chart_id,(ushort)event_id,event.LParam(),event.DParam(),event.SParam()); } } } } //+------------------------------------------------------------------+
该方法在计时器中运作。 首先初始化数据:
品种集合事件标志被重置,
品种集合中的事件列表将被清除,
为列表设置排序标志。
接着,在循环中遍历集合品种列表中的所有品种,接收下一个品种,刷新其所有数据,并检查是否为品种设置了事件标志。 如果没有事件,则检查集合中的下一个品种。
如果品种带有事件标志,则为整个集合设置事件标志(至少所有品种之一存在事件,即表示整个集合都存在该事件)。 获取所有当前品种事件的列表,设置最后一个集合事件的代码等于列表中当前品种的事件代码。 如果存在事件,变量中设置的值存储着最后一个集合事件的代码,此代码会更新到下一个品种,当 在循环中遍历所有当前品种事件的列表, 我们得到一个新事件,并将事件 ID 保存为最后一个集合事件。 同样方式,下一个品种的事件将更新最后一个品种集合事件。
接下来,利用为其设置的品种事件参数来创建集合事件(事件 ID ,长整数型,双精度型和 字符串),然后将品种事件保存到品种集合事件列表中。
如果品种事件成功保存到集合事件列表中,则利用 EventChartCustom() 函数按照相同的事件参数将该事件发送到程序所在图表,以便进一步在调用程序中处理事件。
因此,接收集合列表中每个品种的事件列表,我们将遍历每个品种的事件列表,将其所有事件发送到集合事件列表。 循环结束后,集合事件列表将包含所有集合品种的所有事件。 为每个事件创建一个自定义事件,并将其发送到控制程序所在图表。
为了区分市场观察窗口中的事件,我们需要计算所有市场观察品种的哈希和。 其变化则表明发生了事件。 首先应想到的是简单统计窗口中的品种数量。 不过,添加或删除品种会增加或减小列表的大小,而使用鼠标对品种进行排序不会改变品种的数量。 这意味着“市场观察”窗口中的交易品种数量不适合计算哈希和。
我们来做如下操作:每个存储在列表中的品种名称可以由一个数字(品种代码)代表,该数字由品种(字符)代码的 uchar 值之和组成,该品种名称还包括该品种在市场观察窗口所处的顺序索引。 所有这些品种代码的总和构成哈希和。
- 在列表中新添品种会更改哈希和(已添加品种的新代码会被加入其中)。
- 从列表中删除品种也会更改哈希和(从哈希和中减去已删除品种的代码)。
- 对品种列表进行排序会更改哈希和(已排序品种的代码会改变,因为它们的索引会变化)
实现操控“市场观察”窗口事件的方法:
//+------------------------------------------------------------------+ //| Working with market watch window events | //+------------------------------------------------------------------+ void CSymbolsCollection::MarketWatchEventsControl(const bool send_events=true) { ::ResetLastError(); //--- If no current prices are received, exit if(!::SymbolInfoTick(::Symbol(),this.m_tick)) { this.m_global_error=::GetLastError(); return; } uchar array[]; int sum=0; this.m_hash_sum=0; //--- Calculate the hash sum of all visible symbols in the Market Watch window this.m_total_symbols=this.SymbolsTotalVisible(); //--- In the loop by all Market Watch window symbols int total_symbols=::SymbolsTotal(true); for(int i=0;i<total_symbols;i++) { //--- get a symbol name by index string name=::SymbolName(i,true); //--- skip if invisible if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; //--- write symbol name (characters) codes to the uchar array ::StringToCharArray(name,array); //--- in a loop by the resulting array, sum up the values of all array cells creating the symbol code for(int j=::ArraySize(array)-1;j>WRONG_VALUE;j--) sum+=array[j]; //--- add the symbol code and the loop index specifying the symbol index in the market watch list to the hash sum m_hash_sum+=i+sum; } //--- If sending events is disabled, create the collection list and exit saving the current hash some as the previous one if(!send_events) { //--- Clear the list this.m_list_all_symbols.Clear(); //--- Clear the collection list this.CreateSymbolsList(true); //--- Clear the market watch window snapshot this.CopySymbolsNames(); //--- save the current hash some as the previous one this.m_hash_sum_prev=this.m_hash_sum; //--- save the current number of visible symbols as the previous one this.m_total_symbol_prev=this.m_total_symbols; return; } //--- If the hash sum of symbols in the Market Watch window has changed if(this.m_hash_sum!=this.m_hash_sum_prev) { //--- Define the Market Watch window event this.m_delta_symbol=this.m_total_symbols-this.m_total_symbol_prev; ENUM_SYMBOL_EVENT event_id= ( this.m_total_symbols>this.m_total_symbol_prev ? SYMBOL_EVENT_MW_ADD : this.m_total_symbols<this.m_total_symbol_prev ? SYMBOL_EVENT_MW_DEL : SYMBOL_EVENT_MW_SORT ); //--- Adding a symbol to the Market Watch window if(event_id==SYMBOL_EVENT_MW_ADD) { string name=""; //--- In the loop by all Market Watch window symbols int total=::SymbolsTotal(true), index=WRONG_VALUE; for(int i=0;i<total;i++) { //--- get the symbol name and check its "visibility". Skip it if invisible name=::SymbolName(i,true); if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; //--- If there is no symbol in the collection symbol list yet if(!this.IsPresentSymbolInList(name)) { //--- clear the collection list this.m_list_all_symbols.Clear(); //--- recreate the collection list this.CreateSymbolsList(true); //--- create the symbol collection snapshot this.CopySymbolsNames(); //--- get a new symbol index in the Market Watch window index=this.GetSymbolIndexByName(name); //--- If the "Adding a new symbol" event is successfully added to the event list if(this.EventAdd(event_id,this.TickTime(),index,name)) { //--- send the event to the chart: //--- long value = event time in milliseconds, double value = symbol index, string value = added symbol name ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,name); } } } //--- Save the new number of visible symbols in the market watch window this.m_total_symbols=this.SymbolsTotalVisible(); } //--- Remove a symbol from the Market Watch window else if(event_id==SYMBOL_EVENT_MW_DEL) { //--- clear the collection list this.m_list_all_symbols.Clear(); //--- recreate the collection list this.CreateSymbolsList(true); //--- In a loop by the market watch window snapshot int total=this.m_list_names.Total(); for(int i=0; i<total;i++) { //--- get a symbol name string name=this.m_list_names.At(i); if(name==NULL) continue; //--- if no symbol with such a name exists in the collection symbol list if(!this.IsPresentSymbolInList(name)) { //--- If the "Removing a symbol" event is successfully added to the event list if(this.EventAdd(event_id,this.TickTime(),WRONG_VALUE,name)) { //--- send the event to the chart: //--- long value = event tine in milliseconds, double value = -1 for an absent symbol, string value = a removed symbol name ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),WRONG_VALUE,name); } } } //--- Recreate the market watch snapshot this.CopySymbolsNames(); //--- Save the new number of visible symbols in the market watch window this.m_total_symbols=this.SymbolsTotalVisible(); } //--- Sorting symbols in the Market Watch window else if(event_id==SYMBOL_EVENT_MW_SORT) { //--- clear the collection list this.m_list_all_symbols.Clear(); //--- set sorting of the collection list as sorting by index this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW); //--- recreate the collection list this.CreateSymbolsList(true); //--- get the current symbol index in the Market Watch window int index=this.GetSymbolIndexByName(Symbol()); //--- send the event to the chart: //--- long value = event time in milliseconds, double value = current symbol index, string value = current symbol name ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,::Symbol()); } //--- save the current number of visible symbols as the previous one this.m_total_symbol_prev=this.m_total_symbols; //--- save the current hash some as the previous one this.m_hash_sum_prev=this.m_hash_sum; } } //+------------------------------------------------------------------+
为了避免描述方法代码中的所有分支,我已将代码逐模块放置在清单中。 每个模块都有详尽的注释。 我希望所有一切都清晰明了。 如果您有任何疑问,请在文章评论中询问。
当操控“市场观察”窗口,跟踪其中发生的事件时,仅使用哈希和是不够的。 如果我们想知道事件发生之前发生的情况,则需要拥有一份市场观察品种列表(市场观察快照)的副本。 举例来说,此副本令我们可以找出被删除的品种。 没有市场观察快照,我们将不知道被删除的交易品种的名称。
创建“市场观察”窗口快照的方法:
//+------------------------------------------------------------------+ //| Save names of used Market Watch symbols | //+------------------------------------------------------------------+ void CSymbolsCollection::CopySymbolsNames(void) { this.m_list_names.Clear(); int total=this.m_list_all_symbols.Total(); for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; this.m_list_names.Add(symbol.Name()); } } //+------------------------------------------------------------------+
在此,我们清除品种名称列表。 循环遍历集合品种列表,接收一个新品种,然后将其添加到品种名称列表中。
循环完成后,我们将在品种集合列表中找到所有品种的名称列表。
方法按名称返回品种对象:
//+------------------------------------------------------------------+ //| Return an object symbol from the list by a name | //+------------------------------------------------------------------+ CSymbol *CSymbolsCollection::GetSymbolByName(const string name) { CArrayObj *list=this.GetList(SYMBOL_PROP_NAME,name,EQUAL); if(list==NULL || list.Total()==0) return NULL; CSymbol *symbol=list.At(0); return(symbol!=NULL ? symbol : NULL); } //+------------------------------------------------------------------+
将品种名称传递给方法。 接下来,利用按“品种名称”属性 接收 GetList() 对象列表的方法,创建一个新列表,单个的对象品种应位于与传递给方法的名称相匹配的位置。
从列表中获取品种对象,如果搜索成功,则将其返回;如果在品种集合列表里没有搜到含有该名称的品种,则返回 NULL 。
该方法返回品种集合列表中的品种索引:
//+------------------------------------------------------------------+ //| Return the symbol object index from the list by a name | //+------------------------------------------------------------------+ int CSymbolsCollection::GetSymbolIndexByName(const string name) { int total=this.m_list_all_symbols.Total(); for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; if(symbol.Name()==name) return i; } return WRONG_VALUE; } //+------------------------------------------------------------------+
在此,所要的品种名被传递给方法。 然后,在循环里遍历集合品种列表中所有品种,从列表中获得另一个品种对象。 如果其名称与所要的名称匹配,则返回循环索引。 否则,返回 -1。
该方法返回来自“市场观察”窗口的事件描述:
//+------------------------------------------------------------------+ //| Return the Market Watch window event description | //+------------------------------------------------------------------+ string CSymbolsCollection::EventDescription(const ENUM_SYMBOL_EVENT event) { return ( event==SYMBOL_EVENT_MW_ADD ? TextByLanguage("В окно \"Обзор рынка\" добавлен символ","Added symbol to \"Market Watch\" window") : event==SYMBOL_EVENT_MW_DEL ? TextByLanguage("Из окна \"Обзор рынка\" удалён символ","Removed from \"Market Watch\" window") : event==SYMBOL_EVENT_MW_SORT ? TextByLanguage("Изменено расположение символов в окне \"Обзор рынка\"","Changed arrangement of symbols in \"Market Watch\" window") : EnumToString(event) ); } //+------------------------------------------------------------------+
该方法接收事件,并根据接收到的事件返回其文本描述。
该方法返回操控品种的模式:
//+------------------------------------------------------------------+ //| Return a description of the mode of working with symbols | //+------------------------------------------------------------------+ string CSymbolsCollection::ModeSymbolsListDescription(void) { return ( this.m_mode_list==SYMBOLS_MODE_CURRENT ? TextByLanguage("Работа только с текущим символом","Work only with current symbol") : this.m_mode_list==SYMBOLS_MODE_DEFINES ? TextByLanguage("Работа с предопределённым списком символов","Work with predefined list of symbols") : this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH ? TextByLanguage("Работа с символами из окна \"Обзор рынка\"","Working with symbols from \"Market Watch\" window") : TextByLanguage("Работа с полным списком всех доступных символов","Work with full list of all available symbols") ); } //+------------------------------------------------------------------+
在此,检查 m_mode_list 变量的存在标志,并根据变量值返回操作模式的文本描述。
至此,品种事件类创建完毕。
在品种事件类投入使用之前,请记住,我们也可以在其中安排事件跟踪。 该类现在含有 CBaseObj 基准对象,而帐户类现在基于 CBaseObj,这意味着这两个类都可以调用已准备好的事件搜索功能。 所有从 CBaseObj 派生的后继对象也将含有这些属性,令您能够跟踪对象事件。
改进帐户事件类
打开 Account.mqh 帐户类文件,并进行必要的修改。
将包含 Object.mqh 文件替换为包含 BaseObj.mqh:
//+------------------------------------------------------------------+ //| Account.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 "..\BaseObj.mqh" #include "..\..\Services\DELib.mqh" //+------------------------------------------------------------------+ //| Account class | //+------------------------------------------------------------------+ class CAccount : public CBaseObj { private:
我们将 CBaseObj 设置为基类,而非 CObject。
由于我们现在能够为继承自 CBaseObj 的对象分配名称,因此利用该功能并设置帐户对象的名称。
在 CAccount 类构造函数的最后,添加一行代码来设置帐户对象名称:
//+------------------------------------------------------------------+ //| 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); //--- Account object name this.m_name=TextByLanguage("Счёт ","Account ")+(string)this.Login()+": "+this.Name()+" ("+this.Company()+")"; } //+-------------------------------------------------------------------+
如我们所见,对象名称由 Account 文本、帐号、客户名称和服务该帐户的公司名称组成。
例如,当以我的名字连接到 MetaQuotes-Demo 上的一个帐户时,该帐户对象的名称如下:“Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.)”
在显示简要帐户名的方法中输入'names' 变量值(以前,该变量的设置方法与刚才设置帐户对象的方法相同):
//+------------------------------------------------------------------+ //| 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=this.m_name+" "; string values=::DoubleToString(this.Balance(),(int)this.CurrencyDigits())+" "+this.Currency()+", 1:"+(string)+this.Leverage()+mode+", "+this.TradeModeDescription()+" "+this.ServerTypeDescription(); ::Print(names,values); } //+------------------------------------------------------------------+
CAccount类 的改既已完毕。
现在,我们来改进帐户集合类。 打开 AccountsCollection.mqh 文件,加入必要的修改。
我们将帐户集合类基准对象的角色分配给 CBaseObj 类:
//+------------------------------------------------------------------+ //| Account collection | //+------------------------------------------------------------------+ class CAccountsCollection : public CBaseObj { 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 (MarginCall) double margin_so_so; // ACCOUNT_MARGIN_SO_SO (StopOut) 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) };
删除私密的类成员变量:
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 a folder account objects are stored int m_index_current; // Index of an account object featuring the current account data //--- Tracking account changes bool m_is_account_event; // Account data event flag int m_change_code; // Account change code
将 SetChangeCode() 方法重命名为 SetEventCode() ,以便在不同类中保持相同类型的方法名称。
应将 SetTypeEvent() 方法设置为虚方法,因为该方法已经在 CBaseObj 类中声明,并且应在其后代中实现。
从类中删除 IsPresentEventFlag() 方法,因为该方法已在 CBaseObj 中实现。
在类的公开部分中删除重复的方法。
删除 GetEventCode() , GetListChanges() 和 SetChartID() 方法,而 ENUM_ACCOUNT_EVENT GetEvent(const int shift = WRONG_VALUE) 方法应如下所示:
ENUM_ACCOUNT_EVENT GetEventID(const int shift=WRONG_VALUE,const bool check_out=true);
我们现在于类实体之外研究其实现:
//+------------------------------------------------------------------+ //| Return the account event by its number in the list | //+------------------------------------------------------------------+ ENUM_ACCOUNT_EVENT CAccountsCollection::GetEventID(const int shift=WRONG_VALUE,const bool check_out=true) { CEventBaseObj *event=this.GetEvent(shift,check_out); if(event==NULL) return ACCOUNT_EVENT_NO_EVENT; return (ENUM_ACCOUNT_EVENT)event.ID(); } //+------------------------------------------------------------------+
该方法接收必要事件索引(最后一个为 -1)和检测索引超出事件列表边界的标志。
利用我们在本文开头介绍的 CBaseObj 基准对象方法 GetEvent() 获取事件对象。 如果没有事件,则返回“无事件” ,否则返回事件 ID。
在类构造函数的初始化清单中,删除所有参数的初始化(除了品种设置和设置用于存储帐户对象文件的子文件夹的名称):
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CAccountsCollection::CAccountsCollection(void) : m_symbol(::Symbol()) { 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 this.SetSubFolderName("Accounts"); ::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(); } //+------------------------------------------------------------------+
用于更新帐户数据的 Refresh() 方法应设为虚拟,因为它是在 CBaseObj 类中声明,并在其后代中实现的。
在方法实现中进行了一些修改:
//+------------------------------------------------------------------+ //| Update the current account data | //+------------------------------------------------------------------+ void CAccountsCollection::Refresh(void) { ::ResetLastError(); if(!::SymbolInfoTick(::Symbol(),this.m_tick)) { this.m_global_error=::GetLastError(); return; } if(this.m_index_current==WRONG_VALUE) return; CAccount* account=this.m_list_accounts.At(this.m_index_current); if(account==NULL) return; //--- Prepare event data this.m_is_event=false; ::ZeroMemory(this.m_struct_curr_account); this.m_hash_sum=0; this.SetAccountsParams(account); //--- First launch if(!this.m_struct_prev_account.login) { this.m_struct_prev_account=this.m_struct_curr_account; this.m_hash_sum_prev=this.m_hash_sum; return; } //--- If the account hash sum changed if(this.m_hash_sum!=this.m_hash_sum_prev) { this.m_list_events.Clear(); this.m_event_code=this.SetEventCode(); this.SetTypeEvent(); int total=this.m_list_events.Total(); if(total>0) { this.m_is_event=true; for(int i=0;i<total;i++) { CEventBaseObj *event=this.GetEvent(i,false); if(event==NULL) continue; ENUM_ACCOUNT_EVENT event_id=(ENUM_ACCOUNT_EVENT)event.ID(); if(event_id==ACCOUNT_EVENT_NO_EVENT) continue; long lparam=event.LParam(); double dparam=event.DParam(); string sparam=event.SParam(); ::EventChartCustom(this.m_chart_id,(ushort)event_id,lparam,dparam,sparam); } } this.m_hash_sum_prev=this.m_hash_sum; } } //+------------------------------------------------------------------+
我们来研究一下我们所做的修改。
首先,按品种接收报价数据(定义毫秒时间)。 如果接收失败,则退出方法。
重置帐户事件标志和当前哈希值。 在首次启动期间, 将当前哈希和保存为前一个。
修改哈希和时,清除帐户事件列表,然后执行从帐户事件列表接收事件的操作,类似于接收品种事件列表时执行的操作(于上已讨论)。
现在,对于从 CBaseObj 继承的任何对象,为接收其事件而执行的操作将相似。 所以,最好再次熟悉如何获取它们,以便后续文章中的所有内容都保持清晰,且无需返回对获取对象事件列表所采取的操作的描述。
在帐户对象和帐户数据结构中保存帐户属性的方法中,用 CBaseObj 类的哈希和变量代替对哈希和结构字段的访问,并保存对象名称:
//+------------------------------------------------------------------+ //| Write the current account data to the account object properties | //+------------------------------------------------------------------+ void CAccountsCollection::SetAccountsParams(CAccount *account) { if(account==NULL) return; //--- Name this.m_name=account.GetName(); //--- Account number this.m_struct_curr_account.login=account.Login(); //--- Leverage account.SetProperty(ACCOUNT_PROP_LEVERAGE,::AccountInfoInteger(ACCOUNT_LEVERAGE)); this.m_struct_curr_account.leverage=account.Leverage(); this.m_hash_sum+=(double)this.m_struct_curr_account.leverage; //--- Maximum allowed number of active pending orders account.SetProperty(ACCOUNT_PROP_LIMIT_ORDERS,::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS)); this.m_struct_curr_account.limit_orders=(int)account.LimitOrders(); this.m_hash_sum+=(double)this.m_struct_curr_account.limit_orders; //--- Permission to trade for the current account from the server side account.SetProperty(ACCOUNT_PROP_TRADE_ALLOWED,::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)); this.m_struct_curr_account.trade_allowed=account.TradeAllowed(); this.m_hash_sum+=(double)this.m_struct_curr_account.trade_allowed; //--- Permission to trade for an EA from the server side account.SetProperty(ACCOUNT_PROP_TRADE_EXPERT,::AccountInfoInteger(ACCOUNT_TRADE_EXPERT)); this.m_struct_curr_account.trade_expert=account.TradeExpert(); this.m_hash_sum+=(double)this.m_struct_curr_account.trade_expert; //--- Account balance in a deposit currency account.SetProperty(ACCOUNT_PROP_BALANCE,::AccountInfoDouble(ACCOUNT_BALANCE)); this.m_struct_curr_account.balance=account.Balance(); this.m_hash_sum+=(double)this.m_struct_curr_account.balance; //--- Credit in a deposit currency account.SetProperty(ACCOUNT_PROP_CREDIT,::AccountInfoDouble(ACCOUNT_CREDIT)); this.m_struct_curr_account.credit=account.Credit(); this.m_hash_sum+=(double)this.m_struct_curr_account.credit; //--- Current profit on an account in the account currency account.SetProperty(ACCOUNT_PROP_PROFIT,::AccountInfoDouble(ACCOUNT_PROFIT)); this.m_struct_curr_account.profit=account.Profit(); this.m_hash_sum+=(double)this.m_struct_curr_account.profit; //--- Equity on an account in the deposit currency account.SetProperty(ACCOUNT_PROP_EQUITY,::AccountInfoDouble(ACCOUNT_EQUITY)); this.m_struct_curr_account.equity=account.Equity(); this.m_hash_sum+=(double)this.m_struct_curr_account.equity; //--- Reserved margin on an account in the deposit currency account.SetProperty(ACCOUNT_PROP_MARGIN,::AccountInfoDouble(ACCOUNT_MARGIN)); this.m_struct_curr_account.margin=account.Margin(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin; //--- Free funds available for opening a position on an account in the deposit currency account.SetProperty(ACCOUNT_PROP_MARGIN_FREE,::AccountInfoDouble(ACCOUNT_MARGIN_FREE)); this.m_struct_curr_account.margin_free=account.MarginFree(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_free; //--- Margin level on an account in % account.SetProperty(ACCOUNT_PROP_MARGIN_LEVEL,::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)); this.m_struct_curr_account.margin_level=account.MarginLevel(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_level; //--- Margin Call level account.SetProperty(ACCOUNT_PROP_MARGIN_SO_CALL,::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL)); this.m_struct_curr_account.margin_so_call=account.MarginSOCall(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_so_call; //--- Stop Out level account.SetProperty(ACCOUNT_PROP_MARGIN_SO_SO,::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)); this.m_struct_curr_account.margin_so_so=account.MarginSOSO(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_so_so; //--- Funds reserved on an account to ensure a guarantee amount for all pending orders account.SetProperty(ACCOUNT_PROP_MARGIN_INITIAL,::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL)); this.m_struct_curr_account.margin_initial=account.MarginInitial(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_initial; //--- Funds reserved on an account to ensure a minimum amount for all open positions account.SetProperty(ACCOUNT_PROP_MARGIN_MAINTENANCE,::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE)); this.m_struct_curr_account.margin_maintenance=account.MarginMaintenance(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_maintenance; //--- Current assets on an account account.SetProperty(ACCOUNT_PROP_ASSETS,::AccountInfoDouble(ACCOUNT_ASSETS)); this.m_struct_curr_account.assets=account.Assets(); this.m_hash_sum+=(double)this.m_struct_curr_account.assets; //--- Current liabilities on an account account.SetProperty(ACCOUNT_PROP_LIABILITIES,::AccountInfoDouble(ACCOUNT_LIABILITIES)); this.m_struct_curr_account.liabilities=account.Liabilities(); this.m_hash_sum+=(double)this.m_struct_curr_account.liabilities; //--- Current sum of blocked commissions on an account account.SetProperty(ACCOUNT_PROP_COMMISSION_BLOCKED,::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED)); this.m_struct_curr_account.comission_blocked=account.ComissionBlocked(); this.m_hash_sum+=(double)this.m_struct_curr_account.comission_blocked; } //+------------------------------------------------------------------+
由于可以定义任何对象的事件,因此帐户集合类的 SetTypeEvent() 方法也得以改进和修改。 尽管定义帐户事件类型的所有操作都属于同一类型,但该方法依然很庞大。 在分析品种事件类型的定义时,我们已经研究过它们了。 所以,我仅提供启用帐户交易的示例。 该方法的完整清单可在本文所附的文件中找到:
//+------------------------------------------------------------------+ //| Set the account object event type | //+------------------------------------------------------------------+ void CAccountsCollection::SetTypeEvent(void) { this.InitChangesParams(); ENUM_ACCOUNT_EVENT event_id=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_id=ACCOUNT_EVENT_TRADE_ALLOWED_OFF; if(this.EventAdd(event_id,this.TickTime(),this.m_is_change_trade_allowed_off,this.m_name)) this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } else { this.m_is_change_trade_allowed_on=true; event_id=ACCOUNT_EVENT_TRADE_ALLOWED_ON; if(this.EventAdd(event_id,this.TickTime(),this.m_is_change_trade_allowed_on,this.m_name)) this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } } //--- Changing permission for auto trading for the account
至此,帐户集合类的修改和改进完毕。 现在是时候糅合更新的交易品种与帐户事件类来协同操作了。
您可能还记得,所有控件都从 CEngine 类开始,所有数据也都发送给它。 品种和帐户事件类也不例外。
糅合品种事件类和改良后的帐户类一起工作
打开 Engine.mqh 文件并添加必要的更改。
在类的私密部分中,声明品种事件标志和品种的最后一个事件值:
//+------------------------------------------------------------------+ //| Library basis class | //+------------------------------------------------------------------+ class CEngine : public CObject { private: CHistoryCollection m_history; // Collection of historical orders and deals CMarketCollection m_market; // Collection of market orders and deals CEventsCollection m_events; // Event collection CAccountsCollection m_accounts; // Account collection CSymbolsCollection m_symbols; // Symbol collection CArrayObj m_list_counters; // List of timer counters int m_global_error; // Global error code bool m_first_start; // First launch flag bool m_is_hedge; // Hedge account flag bool m_is_tester; // Flag of working in the tester bool m_is_market_trade_event; // Account trading event flag bool m_is_history_trade_event; // Account history trading event flag bool m_is_account_event; // Account change event flag bool m_is_symbol_event; // Symbol change event flag ENUM_TRADE_EVENT m_last_trade_event; // Last account trading event ENUM_ACCOUNT_EVENT m_last_account_event; // Last event in the account properties ENUM_SYMBOL_EVENT m_last_symbol_event; // Last event in the symbol properties //--- Return the counter index by id
在该类的公开部分,声明返回最后一次交易事件描述的方法:
//--- Return the list of historical (1) orders, (2) removed pending orders, (3) deals, //--- (4) all market orders of a position by its ID, (5) description of the last trading event CArrayObj *GetListHistoryOrders(void); CArrayObj *GetListHistoryPendings(void); CArrayObj *GetListDeals(void); CArrayObj *GetListAllOrdersByPosID(const ulong position_id); string GetLastTradeEventDescription(void);
以及处理品种事件的新方法。 另外,修改返回帐户事件标志的方法:
//--- Return the list of (1) used symbols, (2) symbol events, (3) the last symbol change event //--- (4) the current symbol, (5) symbol event description, (6) Market Watch event description CArrayObj *GetListAllUsedSymbols(void) { return this.m_symbols.GetList(); } CArrayObj *GetListSymbolsEvents(void) { return this.m_symbols.GetListEvents(); } ENUM_SYMBOL_EVENT GetLastSymbolsEvent() { return this.m_symbols.GetLastEvent(); } CSymbol *GetSymbolCurrent(void); string GetSymbolEventDescription(ENUM_SYMBOL_EVENT event); string GetMWEventDescription(ENUM_SYMBOL_EVENT event) { return this.m_symbols.EventDescription(event); } string ModeSymbolsListDescription(void) { return this.m_symbols.ModeSymbolsListDescription(); } //--- Return the list of order, deal and position events CArrayObj *GetListAllOrdersEvents(void) { return this.m_events.GetList(); } //--- Reset the last trading event void ResetLastTradeEvent(void) { this.m_events.ResetLastTradeEvent(); } //--- Return the (1) last trading event, (2) the last event in the account properties, (3) hedging account flag, (4) flag of working in the tester ENUM_TRADE_EVENT LastTradeEvent(void) const { return this.m_last_trade_event; } ENUM_ACCOUNT_EVENT LastAccountEvent(void) const { return this.m_last_account_event; } ENUM_SYMBOL_EVENT LastSymbolsEvent(void) const { return this.m_last_symbol_event; } //--- Return the (1) hedge account, (2) working in the tester, (3) account event and (4) symbol event flag bool IsHedge(void) const { return this.m_is_hedge; } bool IsTester(void) const { return this.m_is_tester; } bool IsAccountsEvent(void) const { return this.m_accounts.IsEvent(); } bool IsSymbolsEvent(void) const { return this.m_symbols.IsEvent(); } //--- Return the (1) symbol object by name, as well as the code of the last event of (2) an account and (3) a symbol CSymbol *GetSymbolObjByName(const string name) { return this.m_symbols.GetSymbolByName(name); } int GetAccountEventsCode(void) const { return this.m_accounts.GetEventCode(); } int GetSymbolsEventsCode(void) const { return this.m_symbols.GetLastEventsCode(); } //--- Return the number of (1) symbols, (2) events in the symbol collection int GetSymbolsCollectionTotal(void) const { return this.m_symbols.GetSymbolsCollectionTotal(); } int GetSymbolsCollectionEventsTotal(void) const { return this.m_symbols.GetEventsTotal(); }
在类构造函数的初始化清单中,添加品种集合中最后一个事件的初始化:
//+------------------------------------------------------------------+ //| CEngine constructor | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true), m_last_trade_event(TRADE_EVENT_NO_EVENT), m_last_account_event(ACCOUNT_EVENT_NO_EVENT), m_last_symbol_event(SYMBOL_EVENT_NO_EVENT), m_global_error(ERR_SUCCESS) { this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_is_tester=::MQLInfoInteger(MQL_TESTER); this.m_list_counters.Sort(); this.m_list_counters.Clear(); this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE); this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE); this.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1); this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2); ::ResetLastError(); #ifdef __MQL5__ if(!::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } //---__MQL4__ #else if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } #endif } //+------------------------------------------------------------------+
在类的计时器响应程序中,将修改添加到品种集合的计时器 1 和 计时器 2 响应模块:
//+------------------------------------------------------------------+ //| CEngine timer | //+------------------------------------------------------------------+ void CEngine::OnTimer(void) { //--- Timer of the collections of historical orders and deals, as well as of market orders and positions int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If unpaused, work with the order, deal and position collections events if(counter.IsTimeDone()) this.TradeEventsControl(); } //--- If this is a tester, work with collection events by tick else this.TradeEventsControl(); } } //--- Account collection timer index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If unpaused, work with the account collection events if(counter.IsTimeDone()) this.AccountEventsControl(); } //--- If this is a tester, work with collection events by tick else this.AccountEventsControl(); } } //--- Timer 1 of the symbol collection (updating symbol quote data in the collection) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If the pause is over, update quote data of all symbols in the collection if(counter.IsTimeDone()) this.m_symbols.RefreshRates(); } //--- In case of a tester, update quote data of all collection symbols by tick else this.m_symbols.RefreshRates(); } } //--- Timer 2 of the symbol collection (updating all data of all symbols in the collection and tracking symbl and symbol search events in the market watch window) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If the pause is over if(counter.IsTimeDone()) { //--- update data and work with events of all symbols in the collection this.SymbolEventsControl(); //--- When working with the market watch list, check the market watch window events if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH) this.MarketWatchEventsControl(); } } //--- If this is a tester, work with events of all symbols in the collection by tick else this.SymbolEventsControl(); } } } //+------------------------------------------------------------------+
在此,在 计时器 1 计数器完成其工作之后,我们只需简单地更新所有集合品种的报价数据,所以调用品种集合的方法 RefreshRates() 。
计时器 2 操作完成后,我们需要彻底刷新所有集合品种,并跟踪品种集合和市场观察品种列表发生的事件,因此调用 CEngine 类方法 SymbolEventsControl() ,而在测试器中不能工作时, — MarketWatchEventsControl() 。
实现操控品种集合事件的方法:
//+------------------------------------------------------------------+ //| Working with symbol collection events | //+------------------------------------------------------------------+ void CEngine::SymbolEventsControl(void) { this.m_symbols.SymbolsEventsControl(); this.m_is_symbol_event=this.m_symbols.IsEvent(); //--- If there are changes in symbol properties if(this.m_is_symbol_event) { //--- Get the last event of the symbol property change this.m_last_symbol_event=this.m_symbols.GetLastEvent(); } } //+------------------------------------------------------------------+
在此,我们调用上述讨论品种集合事件类时已研究过的品种集合方法 SymbolsEventsControl() 。 该方法完成其工作之后,若在任何集合品种中检测到事件,则在品种集合类中启用事件标志。 使用 CBaseObj 基准对象类的 IsEvent() 方法将标志状态设置到 m_is_symbol_event 品种事件标志变量,其值可在调用程序中进行跟踪。 如果品种集合中的事件已注册,则将最后一个事件写入 m_last_symbol_event 变量。 其值也可以在调用程序中跟踪。
实现处理“市场观察”窗口事件的方法:
//+------------------------------------------------------------------+ //| Working with symbol list events in the market watch window | //+------------------------------------------------------------------+ void CEngine::MarketWatchEventsControl(void) { if(this.IsTester()) return; this.m_symbols.MarketWatchEventsControl(); } //+------------------------------------------------------------------+
在此,如果是在测试器中运行,则退出,否则,调用品种集合类的 MarketWatchEventsControl() 方法,处理市场观察窗口事件。 在讨论跟踪品种集合类事件时,我们已经研究了上述方法。
实现返回最后交易事件描述的方法:
//+------------------------------------------------------------------+ //| Return the description of the last trading event | //+------------------------------------------------------------------+ string CEngine::GetLastTradeEventDescription(void) { CArrayObj *list=this.m_events.GetList(); if(list!=NULL) { if(list.Total()==0) return TextByLanguage("С момента последнего запуска ЕА торговых событий не было","There have been no trade events since the last launch of EA"); CEvent *event=list.At(list.Total()-1); if(event!=NULL) return event.TypeEventDescription(); } return DFUN_ERR_LINE+TextByLanguage("Не удалось получить описание последнего торгового события","Failed to get the description of the last trading event"); } //+------------------------------------------------------------------+
在此,我们获得了在帐户上的完整交易事件列表。 如果获得了列表,但大小为零,则返回“尚无交易事件”消息,否则,接收列表中的最后一个事件,并返回其描述。 相反,返回有关未能成功获取交易事件的消息。
该方法返回品种集合中最后一个事件的描述:
//+------------------------------------------------------------------+ //| Return the symbol event description | //+------------------------------------------------------------------+ string CEngine::GetSymbolEventDescription(ENUM_SYMBOL_EVENT event) { CArrayObj *list=this.m_symbols.GetList(); if(list!=NULL) { if(list.Total()==0) return TextByLanguage("С момента последнего запуска ЕА не было никаких событий символов","There have been no events of symbols since the last launch of EA"); CSymbol *symbol=list.At(list.Total()-1); if(symbol!=NULL) return symbol.EventDescription(event); } return DFUN_ERR_LINE+TextByLanguage("Не удалось получить описание события символа","Failed to get symbol's event description"); } //+------------------------------------------------------------------+
该方法的工作方式类似于返回我们刚刚研究过的最后一个交易事件的方法。
CEngine 类的改进已完毕。 一切准备就绪,可以测试交易品种事件,以及更新后的帐户类和帐户事件。
针对该类还进行了一些其他修改。 由于它们主要与某些方法的名称相关,因此于此无需关注它们。 引入它们是为了确保不同类的相同类型的方法具有相同的名称。 我相信,由于函数库代码在不断发展,因此没有必要在本文中描述所有这些次要的改进。 您始终可以在文章所附的文件中找到它们。
测试交易品种和账户事件
为了进行测试,我们将使用来自上一篇文章中的测试 EA,将其保存在 \MQL5\Experts\TestDoEasy\ 之下,名称为 Part16\TestDoEasyPart16.mq5,然后进行所有必要的修改。
在全局变量列表中,添加保存操控品种列表的工作模式变量:
//--- global variables CEngine engine; #ifdef __MQL5__ CTrade trade; #endif SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ulong magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint slippage; bool trailing_on; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; int used_symbols_mode; string used_symbols; string array_used_symbols[];
当选择“操控服务器上的完整品种列表”模式时,首次启动可能会花费很长时间,因为品种集合需要收集全部现有品种的所有数据。 所以,我们需要警告用户。 在函数库本身中执行此操作没有任何意义,因为它仅执行用户要求执行的操作。 所以,应在程序的 OnInit() 处理程序中发出警告。
我们按照以下方式进行操作。 如果在 EA 设置中选择使用服务器上可用的完整品种列表,则程序将显示 MessageBox() 函数的标准窗口,其中包含了警告
提示选择 “Yes” 则下载品种的完整列表,若选择 “No” 则仅使用当前品种。 用户只需做出选择:单击 “Yes” 并等待从所有可用品种中创建集合,或者单击 “No” 并使用当前品种。
我们准备能够在 EA 的 OnInit() 处理函数中发送问题的检查:
//--- Check if working with the full list is selected used_symbols_mode=InpModeUsedSymbols; if((ENUM_SYMBOLS_MODE)used_symbols_mode==SYMBOLS_MODE_ALL) { int total=SymbolsTotal(false); string ru_n="\nКоличество символов на сервере "+(string)total+".\nМаксимальное количество: "+(string)SYMBOLS_COMMON_TOTAL+" символов."; string en_n="\nThe number of symbols on server "+(string)total+".\nMaximal number: "+(string)SYMBOLS_COMMON_TOTAL+" symbols."; string caption=TextByLanguage("Внимание!","Attention!"); string ru="Выбран режим работы с полным списком.\nВ этом режиме первичная подготовка списка коллекции символов может занять длительное время."+ru_n+"\nПродолжить?\n\"Нет\" - работа с текущим символом \""+Symbol()+"\""; string en="Full list mode selected.\nIn this mode, the initial preparation of the collection symbols list may take a long time."+en_n+"\nContinue?\n\"No\" - working with the current symbol \""+Symbol()+"\""; string message=TextByLanguage(ru,en); int flags=(MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2); int mb_res=MessageBox(message,caption,flags); switch(mb_res) { case IDNO : used_symbols_mode=SYMBOLS_MODE_CURRENT; break; default: break; } }
在此,在 EA 设置中由用户选择的品种处理模式被赋值给 used_symbols_mode 全局变量。
如果选择使用完整列表,则创建警告窗口文本,然后在屏幕上显示该窗口。 接着, 检查用户单击的按钮。 如果是 "No",则当前品种的处理模式已分配到 used_symbols_mode 变量。
在其余情况下(“Yes” 按钮或 “Esc”),保留可用品种完整列表的处理模式。
接下来,创建用到的品种数组(将 used_symbols_mode 变量发送到数组创建函数):
//--- Fill in the array of used symbols used_symbols=InpUsedSymbols; CreateUsedSymbolsArray((ENUM_SYMBOLS_MODE)used_symbols_mode,used_symbols,array_used_symbols);
在函数库中设置使用列表的类型(使用品种的模式),然后将有关处理品种的应用模式的消息发送到日志:
//--- Set the type of the used symbol list in the symbol collection engine.SetUsedSymbols(array_used_symbols); //--- Displaying the selected mode of working with the symbol object collection Print(engine.ModeSymbolsListDescription(),TextByLanguage(". Количество используемых символов: ",". Number of symbols used: "),engine.GetSymbolsCollectionTotal());
从 OnInit() 处理程序中删除了用于快速检查品种集合的代码块,因为在此测试 EA 中不需要该代码块:
//--- Fast check of the symbol object collection
CArrayObj *list=engine.GetListAllUsedSymbols();
CSymbol *symbol=NULL;
if(list!=NULL)
{
int total=list.Total();
for(int i=0;i<total;i++)
{
symbol=list.At(i);
if(symbol==NULL)
continue;
symbol.Refresh();
symbol.RefreshRates();
symbol.PrintShort();
if(InpModeUsedSymbols<SYMBOLS_MODE_MARKET_WATCH)
symbol.Print();
}
}
将存储品种集合中最后一个事件的变量添加到 OnTick() 响应程序,并编写(或帐户事件发生变化的情况)帐户和品种集合事件处理模块:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Initializing the last events static ENUM_TRADE_EVENT last_trade_event=WRONG_VALUE; static ENUM_ACCOUNT_EVENT last_account_event=WRONG_VALUE; static ENUM_SYMBOL_EVENT last_symbol_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: ",engine.GetLastTradeEventDescription()); engine.ResetLastTradeEvent(); } //--- If there is an account event if(engine.IsAccountsEvent()) { //--- the 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 CArrayObj* list=engine.GetListAccountEvents(); if(list!=NULL) { //--- Get the next event in a loop int total=list.Total(); for(int i=0;i<total;i++) { //--- take an event from the list CEventBaseObj *event=list.At(i); if(event==NULL) continue; //--- Send an event to the event handler long lparam=event.LParam(); double dparam=event.DParam(); string sparam=event.SParam(); OnDoEasyEvent(CHARTEVENT_CUSTOM+event.ID(),lparam,dparam,sparam); } } } } //--- If there is a symbol collection event if(engine.IsSymbolsEvent()) { //--- the last event in the symbol collection last_symbol_event=engine.LastSymbolsEvent(); //--- If this is a tester if(MQLInfoInteger(MQL_TESTER)) { //--- Get the list of all symbol events occurred simultaneously CArrayObj* list=engine.GetListSymbolsEvents(); if(list!=NULL) { //--- Get the next event in a loop int total=list.Total(); for(int i=0;i<total;i++) { //--- take an event from the list CEventBaseObj *event=list.At(i); if(event==NULL) continue; //--- Send an event to the event handler long lparam=event.LParam(); double dparam=event.DParam(); string sparam=event.SParam(); OnDoEasyEvent(CHARTEVENT_CUSTOM+event.ID(),lparam,dparam,sparam); } } } } //--- If the trailing flag is set if(trailing_on) { TrailingPositions(); TrailingOrders(); } } //+------------------------------------------------------------------+
一切都很简单。 清单中注释了处理帐户和品种集合事件的所有必要操作。
如您所见,如今,所有对象(帐户和交易品种集合)的事件处理都是相似的。 所有一切归结到接收事件列表,然后将来自列表中的每个新事件发送到 EA 的 OnDoEasyEvent() 程序来处理事件库。 由于修改了继承自 CBaseObj 基准对象的方式,其中实现了处理后代对象的事件。
在 EA 的 OnDoEasyEvent() 响应程序中,添加处理品种集合事件的代码:
//+------------------------------------------------------------------+ //| 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_EVENT_NO_EVENT && 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_EVENT_NO_EVENT && idx<ACCOUNT_EVENTS_NEXT_CODE) { Print(TimeMSCtoString(lparam)," ",sparam,": ",engine.GetAccountEventDescription((ENUM_ACCOUNT_EVENT)idx)); //--- if this is an equity increase if((ENUM_ACCOUNT_EVENT)idx==ACCOUNT_EVENT_EQUITY_INC) { //--- Close a position with the highest profit exceeding zero 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(); //--- Select positions with the profit exceeding zero list_positions=CSelect::ByOrderProperty(list_positions,ORDER_PROP_PROFIT_FULL,0,MORE); if(list_positions!=NULL) { //--- 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 } } } } } //--- Handling symbol events else if(idx>SYMBOL_EVENT_NO_EVENT && idx<SYMBOL_EVENTS_NEXT_CODE) { string name=""; //--- Market Watch window event if(idx<SYMBOL_EVENT_TRADE_DISABLE) { string descr=engine.GetMWEventDescription((ENUM_SYMBOL_EVENT)idx); name=(idx==SYMBOL_EVENT_MW_SORT ? "" : ": "+sparam); Print(TimeMSCtoString(lparam)," ",descr,name); } //--- Symbol event else { CSymbol *symbol=engine.GetSymbolObjByName(sparam); if(symbol!=NULL) { string descr=": "+symbol.EventDescription((ENUM_SYMBOL_EVENT)ushort(idx)); Print(TimeMSCtoString(lparam)," ",sparam,descr); } } } } //+------------------------------------------------------------------+
这里只有两个选项:处理市场观察窗口事件和处理集合品种事件。
对于市场观察窗口事件,
创建必要的消息,并发送到日志,
而对于品种事件,
按其名称从列表中接收品种,该名称取自事件参数 “sparam” 字符串,从品种对象获取事件的字符串描述,将其添加到创建的文本中,然后将文本发送到日志。
我们不会为了测试执行其他任何多余动作。
至此测试 EA 的修改完毕。
在附件中找到完整的 EA 清单。
在模拟帐户上启动 EA 时,一段时间后您会看到与品种属性相关的记录发生变化。 例如,在周一交易时段的开盘前夕启动 EA 时,日志帐中会出现有关各种品种的点差变化的多条记录。
在下面的示例中,仅针对市场观察中的四个品种在一个小时的点差变化在日志中显示消息:
2019.07.15 04:02:24.167 TestDoEasyPart16 (EURUSD,H4) Working with symbols from the "Market Watch" window. The number of symbols used: 4 2019.07.15 04:02:25.762 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:27.316 GBPUSD: Spread value in points decreased by -7 (351) 2019.07.15 04:02:31.259 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:32.676 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:02:33.761 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:35.218 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:02:46.261 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:47.680 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:02:48.761 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:50.222 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:02:53.760 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:55.305 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:02:56.760 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:58.221 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:01.261 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:02.683 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:03.760 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:05.226 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:16.260 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:17.673 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:18.789 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:20.219 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:30.832 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:32.686 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:33.819 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:35.219 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:38.820 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:39.926 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:41.821 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:43.221 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:45.820 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:47.673 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:48.836 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:50.234 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:50.865 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:52.598 USDCHF: Spread value in points increased by 51 (334) 2019.07.15 04:03:58.867 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:00.450 EURUSD: Spread value in points decreased by -42 (50) 2019.07.15 04:03:58.868 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:00.430 USDCHF: Spread value in points decreased by -96 (238) 2019.07.15 04:03:59.417 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:00.934 USDCHF: Spread value in points increased by 22 (260) 2019.07.15 04:03:59.912 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:01.431 USDCHF: Spread value in points decreased by -5 (255) 2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:36.984 GBPUSD: Spread value in points decreased by -112 (239) 2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:36.985 EURUSD: Spread value in points decreased by -7 (43) 2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:36.984 USDCHF: Spread value in points decreased by -127 (128) 2019.07.15 04:04:58.460 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:00.102 GBPUSD: Spread value in points decreased by -207 (32) 2019.07.15 04:04:58.959 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:00.696 EURUSD: Spread value in points decreased by -4 (39) 2019.07.15 04:05:01.006 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:02.697 EURUSD: Spread value in points increased by 3 (42) 2019.07.15 04:05:02.037 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:03.686 EURUSD: Spread value in points decreased by -32 (10)
... 省略多条记录 ...
2019.07.15 04:55:09.780 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:11.578 GBPUSD: Spread value in points decreased by -3 (29) 2019.07.15 04:55:09.780 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:11.478 USDCHF: Spread value in points increased by 4 (32) 2019.07.15 04:55:10.482 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:11.681 USDCHF: Spread value in points decreased by -3 (29) 2019.07.15 04:55:11.623 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:13.477 USDCHF: Spread value in points increased by 3 (32) 2019.07.15 04:55:12.111 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:13.884 USDCHF: Spread value in points decreased by -5 (27) 2019.07.15 04:55:13.626 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:15.275 USDCHF: Spread value in points increased by 4 (31) 2019.07.15 04:55:19.628 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:21.381 USDCHF: Spread value in points decreased by -3 (28) 2019.07.15 04:55:20.126 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:21.882 USDCHF: Spread value in points increased by 3 (31) 2019.07.15 04:55:28.659 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:30.292 EURUSD: Spread value in points increased by 3 (20) 2019.07.15 04:55:33.690 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:35.298 EURUSD: Spread value in points decreased by -3 (17) 2019.07.15 04:55:53.298 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:55.137 EURUSD: Spread value in points increased by 3 (20) 2019.07.15 04:55:53.826 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:55.643 EURUSD: Spread value in points decreased by -3 (17) 2019.07.15 04:55:54.906 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:56.632 USDCHF: Spread value in points decreased by -3 (28) 2019.07.15 04:55:55.912 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:57.536 USDCHF: Spread value in points increased by 4 (32) 2019.07.15 04:55:56.907 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:58.636 USDCHF: Spread value in points decreased by -4 (28) 2019.07.15 04:55:57.434 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:58.832 USDCHF: Spread value in points increased by 4 (32) 2019.07.15 04:55:59.949 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:56:01.538 USDCHF: Spread value in points decreased by -3 (29)
现在,我们用两个品种在测试器中启动 EA,并查看将显示哪些记录。
在测试器设置中,对于 EA 输入参数的使用品种列表模式,从下拉列表中选择“使用指定的品种列表” ,而在使用品种列表(逗号-分隔符)参数,输入两个以逗号分隔的品种: EURUSD,GBPUSD ,并以可视模式启动 EA 测试:
有关两个品种事件的记录(特别是与所使用品种的点差变化相关的记录)将发送到日志。 当帐户属性时变化时(在我们的示例中,此为当前利润增加),则相应机里发送到日志,并将获利持仓平仓。
下一步是什么?
在下一篇文章中,我们将基于 CBaseObj 基准对象类实现从程序中方便地修改受控对象,并跟踪对象属性值。
文后附有当前版本含糊库的所有文件,以及测试 EA 文件,供您测试和下载。
请在评论中留下您的问题、意见和建议。
系列中的前几篇文章:
第一部分 概念,数据管理第二部分 历史订单和成交集合
第三部分 在场订单和持仓集合,安排搜索
第四部分 交易事件, 概念
第五部分 交易事件类和集合。 将事件发送至程序
第六部分 净持帐户事件
第七部分 StopLimit 挂单激活事件,为订单和持仓修改事件准备功能
第八部分 订单和持仓修改事件
第九部分 与 MQL4 的兼容性 - 准备数据
第十部分 与 MQL4 的兼容性 - 开仓和激活挂单事件
第十一部分 与 MQL4 的兼容性 - 平仓事件
第十二部分 帐户对象类和帐户对象集合
第十三部分 账户对象事件
第十四部分 品种对象
第十五部份 品种对象集合
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/7071