期货量化的开发智能交易系统提供系统健壮性

把 Times & Trade 转换到一个指标

赫兹量化交易软件的目标是创建可以在 EA 和指标中都能用的代码,这并不那么简单。 作为在子窗口中操作的指标,将其转换为指标似乎很容易。 而正因为它是在子窗口中操作,其实这并不容易。 主要问题是,如果我们像前面的情况一样完成所有事情,那么我们将在指标窗口中得到以下结果:

添加图片注释,不超过 140 字(可选)

不建议将此类内容放在指标窗口中,因为如果用户想从屏幕中删除指标,这会让用户感到困惑。 因此,应该以不同的方式完成这件事情。 在这条路径的末端,也许看起来很困惑,但实际上是一组简单的指令和一些剪辑,我们将在指标窗口中得到以下结果。

添加图片注释,不超过 140 字(可选)

这正是用户所期望的 — 而不是上图中看到的混乱。

以下是 Times & Trade 指标的完整代码:

 
 

#property copyright "Daniel Jose" #property version "1.00" #property indicator_separate_window #property indicator_plots 0 //+------------------------------------------------------------------+ #include <NanoEA-SIMD\Tape Reading\C_TimesAndTrade.mqh> //+------------------------------------------------------------------+ C_Terminal Terminal; C_TimesAndTrade TimesAndTrade; //+------------------------------------------------------------------+ input int user1 = 2; //Scale //+------------------------------------------------------------------+ bool isConnecting = false; int SubWin; //+------------------------------------------------------------------+ int OnInit() { IndicatorSetString(INDICATOR_SHORTNAME, "Times & Trade"); SubWin = ChartWindowFind(); Terminal.Init(); TimesAndTrade.Init(user1); EventSetTimer(1); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { if (isConnecting) TimesAndTrade.Update(); return rates_total; } //+------------------------------------------------------------------+ void OnTimer() { if (TimesAndTrade.Connect()) { isConnecting = true; EventKillTimer(); } } //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { switch (id) { case CHARTEVENT_CHART_CHANGE: Terminal.Resize(); TimesAndTrade.Resize(); break; } } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); } //+------------------------------------------------------------------+

该代码似乎与 EA 中所用的代码相似,除了高亮显示的行在 EA 代码中不存在。 那有什么收获呢? 还是一无所获? 实际上,有一些收获:代码不完全相同,其中存在差异,它并不在指标或 EA 代码里,而是在类代码之中。 但在研究差别之前,我们先思考以下几点:赫兹量化交易软件如何告诉编译器要编译什么,以及不要编译什么? 也许,在编程时,您根本不担心这一点 — 也许,您只管简单地创建代码,如果您不喜欢任何东西,直接删掉就好了。

添加图片注释,不超过 140 字(可选)

经验丰富的程序员有一条规则:只在肯定不起作用时才会删除某些内容,否则即使它们实际上没有被编译,也要保留片段。 但是,当我们希望编写的函数始终工作时,如何在线性代码中做到这一点呢? 此处的问题是:您知道如何告诉编译器要编译什么,和不要编译什么吗? 如果答案是“否”,那就无妨。 当我开始时,我个人也不知道该怎么做。 但它有很大帮助。 故此,我们来找出如何做到这一点。

某些语言具有编译指令,根据作者的不同,这些指令也可能称为预处理器。 但思路是一致的:告诉编译器要编译什么,以及如何进行编译。 有一种非常特殊类型的指令可用来有意隔离代码,以便我们可以测试特定的东西。 这些就是条件编译指令。 如果使用得当,它们允许我们在编译相同的代码时走不同的途径。 这恰恰是 Times & Trade 示例中所做到的。赫兹量化交易软件可选择谁来负责生成条件编译:EA 或指标。 定义该参数后,创建 #define 指令,然后使用条件指令 #ifdef #else #endif 通知编译器如何去编译代码。

这可能难于理解,那么我们就看看它是如何操作的。

在 EA 代码中,定义并添加下面高亮显示的行:

 
 

#define def_INTEGRATION_WITH_EA //+------------------------------------------------------------------+ #include <NanoEA-SIMD\Trade\Control\C_IndicatorTradeView.mqh> #ifdef def_INTEGRATION_WITH_EA #include <NanoEA-SIMD\Auxiliar\C_Wallpaper.mqh> #include <NanoEA-SIMD\Tape Reading\C_VolumeAtPrice.mqh> #include <NanoEA-SIMD\Tape Reading\C_TimesAndTrade.mqh> #endif //+------------------------------------------------------------------+

发生以下情况:如果您想编译 EA 时包含 MQH 文件中的类,则在智能系统中保留预定义的 #ifdefine def_INTEGRATION_WITH_EA 指令。 这样就会令 EA 包含我们需要的所有类,原本它们是插入在指标当中。 如果您要删除指标,无需删除代码,而只需简单地注释掉预定义语句即可。 这可简单地通过将声明指令的行转换成注释行来完成。 如此编译器就无视该指令,并认为不存在;且由于它不存在,每次碰到条件指令 #ifdef def_INTEGRATION_WITH_EA 时,都会完全忽略它,而它和上面示例中 #endif 部分之间的代码也不会被编译。

这是我们在 C_TimesAndTrade 类中所要实现的思路。 以下是新类的样子。 我只展示一点来引起您的注意力:

 
 

#property copyright "Daniel Jose" //+------------------------------------------------------------------+ #include <NanoEA-SIMD\Auxiliar\C_Canvas.mqh> #ifdef def_INTEGRATION_WITH_EA #include <NanoEA-SIMD\Auxiliar\C_FnSubWin.mqh> class C_TimesAndTrade : private C_FnSubWin #else class C_TimesAndTrade #endif { //+------------------------------------------------------------------+ #define def_SizeBuff 2048 #define macro_Limits(A) (A & 0xFF) #define def_MaxInfos 257 #define def_ObjectName "TimesAndTrade" //+------------------------------------------------------------------+ private : string m_szCustomSymbol; // ... The rest of the class code.... }

对于未用过编译指令的人来说,代码可能看起来很奇怪。 def_INTEGRATION_WITH_EA 指令是在 EA 中声明。 然后发生以下情况。 当编译器依此文件生成目标代码时,它将假定以下关系:如果正在编译的文件是 EA,并且含有声明的指令,则编译器将生成的目标代码会包含介于条件指令 #ifdef def_INTEGRATION_WITH_EA 和 #else 之间的部分。 通常在这种情况下,我们要用 #else 指令。 如果编译另一个文件的情况,例如,未定义指令 def_INTEGRATION_WITH_EA 的指标,则将编译指令 #else 和 #endif 之间的所有内容。 这就是它如何操作的。

当编译 EA 或指标时,查看 C_TimesAndTrade 类的整个代码,从而了解这些测试和常规操作中的每个部分。 因此,MQL5 编译器将完成所有设置,从而节省我们维护两个不同文件所需的时间和精力。

2.0.4. 令 EA 更敏捷

如前所述,EA 应当仅与订单系统协同操作。 迄今为止,它所具备的功能,现在已能演变为指标。 这样做的原因非常个人化,这与 EA 所做事情涉及的计算有关。 但是这个计算系统已经被修改,并转移至另一种方法。 有因于此,我注意到由 EA 接管订单处理,订单系统受到一些事情的损害。 问题最严重之处是 OnTick 事件:

 
 

void OnTick() { Chart.DispatchMessage(CHARTEVENT_CHART_CHANGE, 0, TradeView.SecureChannelPosition(), C_Chart_IDE::szMsgIDE[C_Chart_IDE::eRESULT]); #ifdef def_INTEGRATION_WITH_EA TimesAndTrade.Update(); #endif }

该事件现可受控于条件指令,如此,那些在高波动期间不做交易的人,若需要的话,就能拥有一个包含所有原始指标的 EA。 但在您认为这是一个好主意之前,我要提醒您 Times & Trade 更新功能是如何工作的。

 
 

inline void Update(void) { MqlTick Tick[]; MqlRates Rates[def_SizeBuff]; int i0, p1, p2 = 0; int iflag; long lg1; static int nSwap = 0; static long lTime = 0; if (m_ConnectionStatus < 3) return; if ((i0 = CopyTicks(Terminal.GetFullSymbol(), Tick, COPY_TICKS_ALL, m_MemTickTime, def_SizeBuff)) > 0) { // ... The rest of the code... } }

上面的代码是 C_TimesAndTrade 类中存在的更新函数的一部分。 问题出在高亮显示的部分。 每次它在执行时,都会向服务器发送一个请求,并返回自某个时间点以来完成的所有交易单号,顺便说一下,这并不是问题所在。 问题在于,该调用有时会与另两个事件重合。

第一个也是最明显的事件是发生大量交易占用,这会导致 OnTick 函数的调用次数大增。 除了必须运行 C_TimesAndTrade 类中存在的上述代码外,此函数还将应对另一个问题:调用 C_IndicatorTradeView 类中存在的 SecureChannelPosition 函数。 故此,这是另一个小问题,但这还不是全部。 我曾一次次说过,尽管波动性很低,但我们会遇到两个事件的重合,第一个就是该事件。

第二个是在 OnTime 事件中,该事件已被更新,如下所示:

 
 

#ifdef def_INTEGRATION_WITH_EA void OnTimer() { VolumeAtPrice.Update(); TimesAndTrade.Connect(); } #endif

如果您打算按照设计的方式使用 EA,还考虑让它接收更多的代码,那么由于重合事件,它有时可能会出现问题。 当这种情况发生时,EA 就会停顿(即使一秒钟)转而去做与订单系统无关的事情。

与 C_TimesAndTrade 中出现的函数不同,此函数存在于 C_VolumeAtPrice 类中,且在管理订单时确实会损害 EA 性能。 发生这种情况的原因如下:

 
 

inline virtual void Update(void) { MqlTick Tick[]; int i1, p1; if (macroCheckUsing == false) return; if ((i1 = CopyTicksRange(Terminal.GetSymbol(), Tick, COPY_TICKS_TRADE, m_Infos.memTimeTick)) > 0) { if (m_Infos.CountInfos == 0) { macroSetInteger(OBJPROP_TIME, m_Infos.StartTime = macroRemoveSec(Tick[0].time)); m_Infos.FirstPrice = Tick[0].last; } for (p1 = 0; (p1 < i1) && (Tick[p1].time_msc == m_Infos.memTimeTick); p1++); for (int c0 = p1; c0 < i1; c0++) SetMatrix(Tick[c0]); if (p1 == i1) return; m_Infos.memTimeTick = Tick[i1 - 1].time_msc; m_Infos.CurrentTime = macroRemoveSec(Tick[i1 - 1].time); Redraw(); }; };

原因在于高亮显示的部分,但其中最糟糕的是重绘。 它极大地损害了 EA 性能,因为每次所接受跳价的交易量高于指定阈值时,整个价格对应的交易量都会从屏幕上删除、重新计算、并在原位重绘。 它会每 1 秒左右发生一次。 这样就很可能与其它事情重合,这就是为什么要把所有指标都从 EA 里删除的原因。 虽然我保留了它们,这是为了让您可以直接在 EA 中使用它们;但由于前面解释的原因,我仍然不建议这样做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值