嘿,丹尼尔,晚上好!
丹尼尔,我遇到了以下情况:我可以运行并调试服务。但我无法调试指标,因为当我运行服务时,它已经加载了指标的可执行文件。
我不知道我做错了什么,但是据我所知,你不能运行指标代码来调试它。真的是这样吗?能给我一点提示吗?
丹尼尔,晚上好
丹尼尔,我遇到了以下情况:我可以运行并调试服务。但我无法调试指标,因为当我运行服务时,它已经加载了指标的可执行文件。
我不知道我做错了什么,但是据我所知,你不能运行指标代码来调试它。真的是这样吗?能给我一点提示吗?
您绝对没有 做错任何事。
事实上,一旦一切准备就绪,用户可以使用服务,服务就会初始化控制指标。
我不太明白您为什么要调试指示器。它实际上什么也没运行。它只是用户与服务之间的一种交互形式。没有它,我们就很难控制何时播放或暂停服务。无论如何,你尝试研究系统的工作原理并没有错。但作为提示,我建议您仔细阅读这些文章。它们详细解释了系统是如何工作的,这将为您节省大量精力来了解交互是如何发生的。😁👍
嘿,丹尼尔,早上好!
丹尼尔,我对您在 Metatrader 5 平台上的代码和开发进行了一些研究,以便在您文章中提出的重播/模拟器上运行一个机器人。
这个机器人是基于输入数据流的,也就是说,它会计算输入的刻度线,并通过计算来决定是否执行交易。
我已经在其他帖子中讨论过同样的问题,在此为我的坚持提前道歉。 事实上,我已经做了一些研究,并进行了我认为必要的实现,以便机器人(EA)可以从回放服务中接收刻度。
但我遇到了以下问题:机器人能正确地逐个接收到第一个刻度线,但在接收到前 47 个刻度线后(我输入了一个计数器),它开始接收到非常分散的刻度线,我不明白这是为什么。
如果可能的话,我想向您展示一下实现方法,并请您帮助解决问题。
以下是我所做的更改:
- 在 C_Replay 类中(黄色线条):
- 在 Event_OnTime 方法中:
- 我创建了一个 MqlTick 类型的变量,用于接收将发送到图形的 tick;
- 在发送条形图更新(CustomRatesUpdate)后,我输入了一段代码,将刻度线发送到图表,并等待通过全局变量 "def_GlobalVariableTick "进行处理;
inline int Event_OnTime(void) { bool bNew; int mili, iPos; u_Interprocess Info; MqlTick TickToAdd[1]; static MqlRates Rate[1]; static datetime _dt = 0; if (m_ReplayCount >= m_Ticks.nTicks) return -1; if (bNew = (_dt != m_Ticks.Info[m_ReplayCount].time)) { _dt = m_Ticks.Info[m_ReplayCount].time; Rate[0].real_volume = 0; Rate[0].tick_volume = 0; } mili = (int) m_Ticks.Info[m_ReplayCount].time_msc; do { while (mili == m_Ticks.Info[m_ReplayCount].time_msc) { Rate[0].close = m_Ticks.Info[m_ReplayCount].last; Rate[0].open = (bNew ? Rate[0].close : Rate[0].open); Rate[0].high = (bNew || (Rate[0].close > Rate[0].high) ? Rate[0].close : Rate[0].high); Rate[0].low = (bNew || (Rate[0].close < Rate[0].low) ? Rate[0].close : Rate[0].low); Rate[0].real_volume += (long) m_Ticks.Info[m_ReplayCount].volume_real; bNew = false; m_ReplayCount++; } mili++; }while (mili == m_Ticks.Info[m_ReplayCount].time_msc); Rate[0].time = m_Ticks.Info[m_ReplayCount].time; CustomRatesUpdate(def_SymbolReplay, Rate, 1); iPos = (int)((m_ReplayCount * def_MaxPosSlider) / m_Ticks.nTicks); GlobalVariableGet(def_GlobalVariableReplay, Info.u_Value.df_Value); if (Info.s_Infos.iPosShift != iPos) { Info.s_Infos.iPosShift = (ushort) iPos; GlobalVariableSet(def_GlobalVariableReplay, Info.u_Value.df_Value); } // Apenas plotará o tick no grafico se o robo tiver criado a variavel "def_GlobalVariableTick" if (GlobalVariableCheck(def_GlobalVariableTick)) { TickToAdd[0]=m_Ticks.Info[m_ReplayCount]; Print("Tick enviado: Time: ", TickToAdd[0].time, " Time_msc: ", TickToAdd[0].time_msc, " Bid: ", TickToAdd[0].bid, " Ask: ", TickToAdd[0].ask, " Last: ", TickToAdd[0].last, " Volume: ", TickToAdd[0].volume_real); GlobalVariableSet(def_GlobalVariableTick, 1); // Quando o EA receber o tick (OnTick) irá alterar para ZERO CustomTicksAdd(def_SymbolReplay, TickToAdd); short ctd=0; while (GlobalVariableGet(def_GlobalVariableTick) > 0 && (!_StopFlag) && ctd <= 50) { ctd++; Sleep(50) }; } return (int)(m_Ticks.Info[m_ReplayCount].time_msc < mili ? m_Ticks.Info[m_ReplayCount].time_msc + (1000 - mili) : m_Ticks.Info[m_ReplayCount].time_msc - mili); }
- 机器人(EA)的代码,用于接收刻度线以进行处理:
#define def_GlobalVariableTick "ReplayTick" //+------------------------------------------------------------------+ int OnInit() { GlobalVariableTemp(def_GlobalVariableTick); Print("Variavel Criada: ", def_GlobalVariableTick); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { GlobalVariableDel(def_GlobalVariableTick); } //+------------------------------------------------------------------+ void OnTick() { MqlTick mTick; static int ctd=0; SymbolInfoTick(Symbol(),mTick); ctd++; Print(Symbol(), " Tick Recebido ", ctd, ": Time: ", mTick.time, " Time_msc: ", mTick.time_msc, " Bid: ", mTick.bid, " Ask: ", mTick.ask, " Last: ", mTick.last, " Volume: ", mTick.volume); // . // . // 标记处理代码 // . // . // 将全局变量的值改为零,以接收下一个刻度线 GlobalVariableSet(def_GlobalVariableTick, 0); }
继续 ....
这样,当您需要停止机器人进行调试时,重放将一直等待,直到您通过将全局变量 "def_GlobalVariableTick "设置为零的那一行;
明白了吗?
细节在于,这一机制已经发生了变化。请查看较新的文章,因为它们向你展示了如何正确地释放 ticks。您甚至可以在市场观察窗口 DOM 中跟踪它们。目前,我们已经用葡萄牙语发布了第 28 部分的文章。因此,您试图调整和操作的代码已经完全过时。您需要关注这些文章,以跟上系统的发展。在系列文章完全出版之前,不要对文章中的任何代码产生依赖。因为随着时间的推移,它们将经历多次修改,以便能够实现所承诺的内容:开发 REPLAY / SIMULATOR,这样就可以使用您已有的或正在开发的用于模拟或真实账户的任何程序。无论是股票市场还是外汇市场。
请勿尝试 将您的智能交易系统、指标或脚本与重放/模拟器相结合,至少现在还不要。因为它将对代码进行重大修改...只需创建您的代码,无需担心 REPLAY / SIMULATOR ...总有一天,我会短暂停止开发,向您展示如何创建一些支持模块。到那时,你就可以开始将你的代码整合到其中了。即使到那时也会非常缓慢,因为当我向您展示如何开发的模块达到一定的功能级别时,它们就会集成到 REPLAY / SIMULATOR 中 ...这时,你才真正需要了解整个系统将如何工作。否则,您将无法将代码集成到 REPLAY / SIMULATOR 服务中。
因此,请放松心情,认真阅读文章,始终跟上正在开发的内容......😁👍
新文章 开发回放系统 — 市场模拟(第 10 部分):仅用真实数据回放已发布:
在此,我们将查看如何在回放系统中使用更可靠的数据(交易跳价),而不必担心它是否被调整。
在下面的视频中,您可以看到本文讲解的工作结果。 虽然有些东西也许还不可见,但观看视频会令您清楚地了解所有这些文章中回放/模拟系统的实现进度。 只需观看视频,并比较从一开始到现在的变化。
在下一篇文章中,我们将继续开发该系统,因为还有一些真正必要的功能需要实现。
作者:Daniel Jose