文章 "轻松快捷开发 MetaTrader 程序的函数库(第十部分):与 MQL4 的兼容性 - 开仓和激活挂单的事件" - 页 3 123456 新评论 Artyom Trishkin 2019.05.27 16:52 #21 Alexey Viktorov:Artem,请告诉我突出显示的代码部分起什么作用。如果定时器没有启用,如何执行这段代码?如果删除这部分代码,事件信息就不会打印出来。但有了它,一切都能正常运行。我希望在获得事件消息的同时,还能获得票据、价格以及仓位 和订单的其他属性。我认为您修改了注释。在OnTimer() 中,EA 被检查, 而不是 在测试器中: /************************Expert tick function************************/ void OnTick() { //-- 上次交易事件初始化 static ENUM_TRADE_EVENT last_event=WRONG_VALUE; //--- 如果在测试仪中工作 if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(); } //--- 如果最后一次交易事件发生变化 if(engine.LastTradeEvent()!=last_event) { last_event=engine.LastTradeEvent(); Comment("last_event: ",EnumToString(last_event)); Print(__FUNCTION__, " last_event: ",EnumToString(last_event)); //engine.ResetLastTradeEvent(); //Print("last_event: ",EnumToString(last_event)); } } /***************************Timer function***************************/ void OnTimer() { //-- 上次交易事件初始化 static ENUM_TRADE_EVENT last_event=WRONG_VALUE; //--- 如果工作 不是 в тестере if(!MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(); } } /*******************************************************************/ 比较这两个处理程序:在OnTick() 中,库定时器只在测试器中 启动,而在OnTimer() 中,库定时器只在 测试器中启动,而 不 在 测试器中启动 - 因为在 MQL4 中,测试器中的定时器不起作用,而我们在测试器中处理 ticks。 我现在举个例子。 Alexey Viktorov 2019.05.27 17:04 #22 Artyom Trishkin:我想你改了评论。评论是自己改的,我没动过。)))))) 我只是复制了一个地方,然后粘贴到不同的地方,并没有注意。但后来用了!和不重要的否定形式,就没动了。 但问题仍然没有得到解答:如果定时器没有在 OnInit() 中启动,那么 OnTimer() 处理程序有什么意义,为什么其中的代码至少要执行一次。 基本上,我已将信息记录到日志中。剩下的就是获取项目的属性。类型、票据、价格以及打开、关闭和修改的时间。 Artyom Trishkin 2019.05.27 17:25 #23 Alexey Viktorov:我希望能在获得事件消息的同时,还能获得票据、价格以及仓位 和订单的一些其他属性。在测试版中,您无法在 OnChartEvent() - 参数 lparam 中获取最后一个事件的订单。在 dparam 中存储的是价格。在 sparam 中 - 符号。 要在测试器中获取数据,目前应使用 engine.LastTradeEvent() 获取的事件代码 - 因为一切都取决于事件 - 如果是修改,则需要获取修改列表;如果是订单数量的变化,则需要获取这些新订单的列表。 我们需要添加 CEngine 来向程序返回必要的值。我还没有讲到向程序发送信息这一点--我还在描述必要数据的准备工作。在今后的文章中,我们将介绍如何轻松访问所有必要数据。现在--如果你急需它,你需要在 CEngine 中添加事件类集合的返回列表--类本身有这个列表的接收器,它们在这里--所有列表都在公共部分 CEventCollection 中: public: //--- 从事件集合中选择时间范围在 begin_time 到 end_time 之间的事件 CArrayObj *GetListByTime(const datetime begin_time=0,const datetime end_time=0); //--- "按原样 "返回事件的完整列表集合 CArrayObj *GetList(void) { return &this.m_list_events; } //--- 根据满足比较标准的所选 (1) 整数、(2) 实数和 (3) 字符串属性,返回一个列表 CArrayObj *GetList(ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode); } 所有事件都存储在 m_list_events 列表中,这些方法要么返回完整列表,要么按给定标准过滤后返回。 要获取最后一个事件,只需在 CEngine 中创建将该列表返回给程序的方法,并在程序中从列表中获取所需的事件。 所有这一切都将很快实现自动化--目前还没有排到队列中。 如果您还需要制作拐杖,可以私下讨论。这在这里不值得--它不适用于图书馆,因为图书馆还在开发中,将进一步开展正常和适当的工作,以便在程序中获取所有和任何所需的事件。 Artyom Trishkin 2019.05.27 17:28 #24 Alexey Viktorov:评论是自己改的,我没动它。)))))我只是复制了一个地方,然后粘贴到不同的地方,并没有注意。但后来我又用!的形式加上了一个否定,却没有动重要的那个。但问题仍然没有得到解答:如果计时器没有在 OnInit() 中启动,那么 OnTimer() 处理程序的意义何在,为什么其中的代码至少要执行一次。基本上,我已将信息记录到日志中。剩下的就是获取项目的属性。类型、票据、价格以及打开、关闭和修改的时间。请解释一下您的意思?您是在说创建计时器吗?定时器 是在 CEngine 构造函数中创建的: //+------------------------------------------------------------------+ //| CEngine 构造函数| //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT) { this.m_list_counters.Sort(); this.m_list_counters.Clear(); this.CreateCounter(COLLECTION_COUNTER_ID,COLLECTION_COUNTER_STEP,COLLECTION_PAUSE); 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); ::ResetLastError(); #ifdef __MQL5__ if(!::EventSetMillisecondTimer(TIMER_FREQUENCY)) ::Print(DFUN,"创建计时器失败。错误:","Could not create timer. Error: ",(string)::GetLastError()); //---__MQL4__ #else if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY)) ::Print(DFUN,"创建计时器失败。错误:","Could not create timer. Error: ",(string)::GetLastError()); #endif } //+------------------------------------------------------------------+ Alexey Viktorov 2019.05.27 17:47 #25 Artyom Trishkin:在测试版中无法通过OnChartEvent()- 参数 lparam 获取最后一个事件的订单。在 dparam 中存储价格。在 sparam 中 - 符号。我已经找到了,谢谢。您只需获得一张票,就可以获得所需的一切。除了价格的修改。或者制作一个真正的拐杖来了解修改前的价格。原则上还不是很有必要。 Artyom Trishkin 2019.05.27 17:48 #26 Alexey Viktorov:基本上,我得到了日志信息。我只需要获取头寸的属性。类型、票据、价格以及开仓、平仓和修改的时间。不过,为了快速解决问题,可以在 CEngine 的公共部分添加事件列表返回: public: //--- 返回市场 (1) 头寸、(2) 挂单和 (3) 市场订单的列表 CArrayObj* GetListMarketPosition(void); CArrayObj* GetListMarketPendings(void); CArrayObj* GetListMarketOrders(void); //--- 返回某个仓位的 (1) 订单、(2) 已删除挂单、(3) 交易、(4) 所有市场订单的历史列表(按其标识符)。 CArrayObj* GetListHistoryOrders(void); CArrayObj* GetListHistoryPendings(void); CArrayObj* GetListDeals(void); CArrayObj* GetListAllOrdersByPosID(const ulong position_id); //--- 返回事件列表 CArrayObj* GetListAllEvents(void) { return this.m_events.GetList(); } //-- 重置上次交易事件 void ResetLastTradeEvent(void) { this.m_events.ResetLastTradeEvent(); } //--- 返回 (1) 上次交易事件,(2) 对冲账户标志,(3) 测试仪操作标志 ENUM_TRADE_EVENT LastTradeEvent(void) const { return this.m_last_trade_event; } bool IsHedge(void) const { return this.m_is_hedge; } bool IsTester(void) const { return this.m_is_tester; } //--- 创建一个定时器计数器 void CreateCounter(const int id,const ulong frequency,const ulong pause); //--- 定时器 void OnTimer(void); //-- 构造函数/析构函数 CEngine(); ~CEngine(); }; //+------------------------------------------------------------------+ 在 EA 中添加此代码: //+------------------------------------------------------------------+ //| 专家勾选功能| //+------------------------------------------------------------------+ void OnTick() { //-- 上次交易事件初始化 static ENUM_TRADE_EVENT last_event=WRONG_VALUE; //--- 如果在测试仪中工作 if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(); PressButtonsControl(); } //--- 如果最后一次交易事件发生变化 if(engine.LastTradeEvent()!=last_event) { last_event=engine.LastTradeEvent(); Comment("\nlast_event: ",EnumToString(last_event)); CArrayObj* list=engine.GetListAllEvents(); if(list!=NULL) { if(list.Total()>0) { CEvent* event=list.At(list.Total()-1); if(event!=NULL) { event.Print(); } } } } //--- 如果设置了拖尾标志 if(trailing_on) { TrailingPositions(); TrailingOrders(); } } //+------------------------------------------------------------------+ 最后一个事件将被打印在日志中 Alexey Viktorov 2019.05.27 17:49 #27 Artyom Trishkin:请解释一下您的意思?您是在说创建计时器吗?定时器 是在 CEngine 构造函数中创建的:好吧,那你就得翻遍整个程序库了。))) Artyom Trishkin 2019.05.27 17:49 #28 Alexey Viktorov:我已经找到了,谢谢。如果你拿到了票,你就可以得到你想要的一切。除了改装的价格。或者制作一个真正的拐杖,在改装前就知道价格。我现在还不需要我已经把代码给你了 - 那里什么都有,还有改装前的价格。 Artyom Trishkin 2019.05.27 17:50 #29 Alexey Viktorov:好吧,你得把整个图书馆都翻一遍才行。)))不,只需阅读文章 Alexey Viktorov 2019.05.27 17:59 #30 事情是这样的: 当我在演示版上运行这段代码时,设置并删除了一个限价订单 443342388 2019.05.27 14:54:10 buy limit 0.01 eurusd 1.11835 0.00000 0.00000 2019.05.27 15:01:14 1.11972 cancelled 突然,在下一次模拟中,一个仓位被修改,一个仓位被打开,一个仓位被关闭。但删除已删除订单的记录从何而来? 2019.05.27 18:34:11.903 00 EURUSD,H1: OnChartEvent: id=1002, event=TRADE_EVENT_PENDING_ORDER_REMOVED, lparam=443342388, dparam=1.11835, sparam=EURUSD 2019.05.27 18:34:11.903 00 EURUSD,H1: OnChartEvent: id=1024, event=TRADE_EVENT_POSITION_CLOSED, lparam=443417294, dparam=1.11933, sparam=EURUSD 2019.05.27 18:34:11.903 00 EURUSD,H1: - Отложенный ордер удалён: 2019.05.27 14:54:10.000 - EURUSD Удалён 0.01 Buy Limit #443342388 по цене 1.11835 2019.05.27 18:34:11.903 00 EURUSD,H1: - Позиция закрыта: 2019.05.27 18:33:02.000 - EURUSD Закрыт Sell #443417294 по цене 1.11912, профит -0.21 USD 2019.05.27 18:33:02.755 00 EURUSD,H1: OnChartEvent: id=1022, event=TRADE_EVENT_POSITION_OPENED, lparam=443417294, dparam=1.11912, sparam=EURUSD 2019.05.27 18:33:02.755 00 EURUSD,H1: - Позиция открыта: 2019.05.27 18:33:02.000 - EURUSD Открыт 0.01 Sell #443417294 [0.01 Market order Sell #443417294] по цене 1.11912 2019.05.27 18:29:21.913 00 EURUSD,H1: OnChartEvent: id=1050, event=TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT, lparam=443218277, dparam=1.12218, sparam=EURUSD 2019.05.27 18:29:21.913 00 EURUSD,H1: - Модифицирован TakeProfit позиции: 2019.05.27 18:27:45.000 - EURUSD Buy #443218277: модифицирован TakeProfit: [1.12240 --> 1.12218] 123456 新评论 您错过了交易机会: 免费交易应用程序 8,000+信号可供复制 探索金融市场的经济新闻 注册 登录 拉丁字符(不带空格) 密码将被发送至该邮箱 发生错误 使用 Google 登录 您同意网站政策和使用条款 如果您没有帐号,请注册 可以使用cookies登录MQL5.com网站。 请在您的浏览器中启用必要的设置,否则您将无法登录。 忘记您的登录名/密码? 使用 Google 登录
Artem,请告诉我突出显示的代码部分起什么作用。
如果定时器没有启用,如何执行这段代码?
如果删除这部分代码,事件信息就不会打印出来。但有了它,一切都能正常运行。
我希望在获得事件消息的同时,还能获得票据、价格以及仓位 和订单的其他属性。
我认为您修改了注释。在OnTimer() 中,EA 被检查, 而不是 在测试器中:
比较这两个处理程序:在OnTick() 中,库定时器只在测试器中 启动,而在OnTimer() 中,库定时器只在 测试器中启动,而 不 在 测试器中启动 - 因为在 MQL4 中,测试器中的定时器不起作用,而我们在测试器中处理 ticks。
我现在举个例子。
我想你改了评论。
评论是自己改的,我没动过。))))))
我只是复制了一个地方,然后粘贴到不同的地方,并没有注意。但后来用了!和不重要的否定形式,就没动了。
但问题仍然没有得到解答:如果定时器没有在 OnInit() 中启动,那么 OnTimer() 处理程序有什么意义,为什么其中的代码至少要执行一次。
基本上,我已将信息记录到日志中。剩下的就是获取项目的属性。类型、票据、价格以及打开、关闭和修改的时间。
我希望能在获得事件消息的同时,还能获得票据、价格以及仓位 和订单的一些其他属性。
在测试版中,您无法在 OnChartEvent() - 参数 lparam 中获取最后一个事件的订单。在 dparam 中存储的是价格。在 sparam 中 - 符号。
要在测试器中获取数据,目前应使用 engine.LastTradeEvent() 获取的事件代码 - 因为一切都取决于事件 - 如果是修改,则需要获取修改列表;如果是订单数量的变化,则需要获取这些新订单的列表。
我们需要添加 CEngine 来向程序返回必要的值。我还没有讲到向程序发送信息这一点--我还在描述必要数据的准备工作。在今后的文章中,我们将介绍如何轻松访问所有必要数据。现在--如果你急需它,你需要在 CEngine 中添加事件类集合的返回列表--类本身有这个列表的接收器,它们在这里--所有列表都在公共部分 CEventCollection 中:
所有事件都存储在 m_list_events 列表中,这些方法要么返回完整列表,要么按给定标准过滤后返回。
要获取最后一个事件,只需在 CEngine 中创建将该列表返回给程序的方法,并在程序中从列表中获取所需的事件。
所有这一切都将很快实现自动化--目前还没有排到队列中。
如果您还需要制作拐杖,可以私下讨论。这在这里不值得--它不适用于图书馆,因为图书馆还在开发中,将进一步开展正常和适当的工作,以便在程序中获取所有和任何所需的事件。
评论是自己改的,我没动它。)))))
我只是复制了一个地方,然后粘贴到不同的地方,并没有注意。但后来我又用!的形式加上了一个否定,却没有动重要的那个。
但问题仍然没有得到解答:如果计时器没有在 OnInit() 中启动,那么 OnTimer() 处理程序的意义何在,为什么其中的代码至少要执行一次。
基本上,我已将信息记录到日志中。剩下的就是获取项目的属性。类型、票据、价格以及打开、关闭和修改的时间。
请解释一下您的意思?您是在说创建计时器吗?定时器 是在 CEngine 构造函数中创建的:
在测试版中无法通过OnChartEvent()- 参数 lparam 获取最后一个事件的订单。在 dparam 中存储价格。在 sparam 中 - 符号。
我已经找到了,谢谢。您只需获得一张票,就可以获得所需的一切。除了价格的修改。或者制作一个真正的拐杖来了解修改前的价格。原则上还不是很有必要。
基本上,我得到了日志信息。我只需要获取头寸的属性。类型、票据、价格以及开仓、平仓和修改的时间。
不过,为了快速解决问题,可以在 CEngine 的公共部分添加事件列表返回:
在 EA 中添加此代码:
最后一个事件将被打印在日志中
请解释一下您的意思?您是在说创建计时器吗?定时器 是在 CEngine 构造函数中创建的:
好吧,那你就得翻遍整个程序库了。)))
我已经找到了,谢谢。如果你拿到了票,你就可以得到你想要的一切。除了改装的价格。或者制作一个真正的拐杖,在改装前就知道价格。我现在还不需要
我已经把代码给你了 - 那里什么都有,还有改装前的价格。
好吧,你得把整个图书馆都翻一遍才行。)))
不,只需阅读文章
事情是这样的:
当我在演示版上运行这段代码时,设置并删除了一个限价订单
突然,在下一次模拟中,一个仓位被修改,一个仓位被打开,一个仓位被关闭。但删除已删除订单的记录从何而来?