概述% ^5 @1 U$ ?7 k. L: d
在上一篇文章我们曾做过一些修正和调整。 不过,依旧还有错误,如该文所附的视频所示。+ m4 U- M/ m& J
在本文中,我们将亲眼见证如何修复此错误。 虽然表面上看这似乎很简单,但我们需要遵循若干个步骤。 这个过程将是奇妙和有趣的。 我们的目标是令指标专门应用于特定的图表和品种。 即使用户尝试,他们也无法将指标应用于另外的图表,或在一个会话中多次打开它。
( l0 k; h- L) n, i! Z0 X我鼓励您继续阅读,因为内容承诺非常实用。, p! w, F3 i8 r7 h2 O, @$ e' K5 Q
将指标锁定在特定品种上。
+ _+ S4 d! k( I$ ^第一步是将控制指标链接到进行市场回放的品种。 这一步虽然看起来很简单,但对于开发我们的主要任务是必要的。 我们来看看指标代码在上下文中会是什么样子:
" d, e0 O2 m) f( g6 ]& B- _: h#property copyright "Daniel Jose") K- P7 l7 x: t' z2 J
#property indicator_chart_window
) ^) V4 D# a) Q p4 d: v- d#property indicator_plots 0
' q; X: }1 s& e5 ^//+------------------------------------------------------------------+
6 e1 w. E( Y- b/ C#include <Market Replay\C_Controls.mqh>
% G5 }' F- s) q/ t' J$ w+ j//+------------------------------------------------------------------+
9 s0 C" P; \& M+ x l9 dC_Controls Control;* S5 k) {1 P* d' ?9 c: j, G$ i2 C
//+------------------------------------------------------------------+1 g: b% z; _+ S; j: q' R
int OnInit()4 u7 O+ [; b/ O$ J$ k. |3 B, ^# t
{3 |8 m5 y; l& c
u_Interprocess Info;
4 U! E$ M3 k- X3 @% ~3 g; B4 AIndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);/ {. B; [8 Q& J. t8 Q, b. W
if (_Symbol != def_SymbolReplay)6 @9 D, E; z* i: ]# B
{- _% Q3 I1 \+ v: o8 {6 T8 M
ChartIndicatorDelete(ChartID(), 0, def_ShortName);8 ` {( i6 ^, l) U5 s$ w4 T
return INIT_FAILED;4 U, g2 D6 m6 I0 D5 K
}
7 t$ a- ^3 K Y$ V/ r* y( A T# ~if (GlobalVariableCheck(def_GlobalVariableReplay)) Info.Value = GlobalVariableGet(def_GlobalVariableReplay); else Info.Value = 0;: I, D, g8 ? ~$ p c% ?. |
Control.Init(Info.s_Infos.isPlay);; b. G& @, c, [' M# _
return INIT_SUCCEEDED;
0 J5 Y& K) ^2 a4 D8 f' c}
8 ?6 \ L7 \2 E% j' U! u3 i9 ]//+------------------------------------------------------------------++ o1 a$ |5 v, v* b L
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
/ q. y7 d. @/ X7 m; Y& d- {{
, y6 Y8 q7 @. H) ~ O$ {return rates_total;/ k- a, w k* y# `6 \9 q" V) o* O5 ]
}
3 {! f# S1 C0 e- S! m* O//+------------------------------------------------------------------+8 }- ?/ Q& D/ g
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)2 p( b e* Y z M8 a; F% ]) t- w
{$ Z& M# \0 _+ }5 c% K
Control.DispatchMessage(id, lparam, dparam, sparam); T4 d- m' n3 P
}
: b. J4 b- q. W; `//+------------------------------------------------------------------+3 f) N6 l$ Y/ x. V4 l/ d5 v" w
void OnDeinit(const int reason)8 [. _& D" u- s5 D& [ e
{
5 F3 o1 i9 r; ^! R1 F$ T. _switch (reason)
* O0 T1 x1 c* q) L{
& ?# m% e0 B% b% f8 K: ^7 t: r% hcase REASON_REMOVE:
2 a7 `" n1 l7 B7 Q8 F; wcase REASON_CHARTCLOSE:
4 X7 Q8 V- W( d- q, n1 Eif (_Symbol != def_SymbolReplay) break;6 @, e6 B9 k: T. A* n
GlobalVariableDel(def_GlobalVariableReplay);( h0 p5 o/ z5 I1 O$ h: g: Q, f3 b
ChartClose(ChartID());0 T1 W, I9 r6 w1 G6 d
break;
/ N7 y% \& E0 x, q R, D}
" i) p5 z" S, B' @+ H}
! T0 h/ Q: g1 e+ W* H+ S//+------------------------------------------------------------------+
' ~! G6 p- o, r) ~+ }我们首先检查针对的品种是否要进行市场回放。 如果不是这种情况,指标将自动关闭。 请注意,知道指标的名称很重要。 因此,初始化期间执行的第一个函数调用我们的指标,这令我们能够轻松删除它。
# T2 h; D {5 U) q L现在重要的一点是:当您将其从图表中删除时,MetaTrader 5 会生成 DeInit 事件。 此事件触发 OnDeInit 函数,而标记为 REASON_REMOVE 的事件表示从图表中删除指标。 这是因为该品种与指标设计绑定的品种不同。 如果我们不重新检查并阻止代码运行,品种图表将关闭。 不过,幸亏我们的检查,它将保持开放状态。 e. c; z4 [4 J" q r* v/ d
如果指标代码与上一篇文章中提供的代码不同,请不要感到惊讶:上一篇文章重点在于其它改进和修复。 不过,在编写了文章和代码,并录制了本文随附的视频后,我意识到尽管其中一个问题已解决,但另一个问题仍未被发现。 这就是为什么我不得不修改代码。" D/ c. |0 c! j8 i
尽管进行了修改,但我们不会在此处详述所做的全部修改。 必须删除很大一部分,因为它对于此处讨论的锁定方面无效。 因此,上面的代码与以前的代码有很大差别。 不过,我相信上一篇文章中讲演的知识在某些时候可能对某些人有用。 我保存了那篇文章,以表明有时我们都会犯错误,但我们依旧应该努力把事情做好。
; Q4 U! {- l C5 [. G R因此,我们来建立第一个锁定步骤,即确保控制指标仅存在于市场回放品种的图表上。 然而,该衡量值并不会阻止向同一图表或不同图表添加多个指标,因此必须进行调整。
2 ^8 e2 q& q' S& c. D9 _! ^6 o我们应该避免在同一图表上多次使用指标。
0 i6 n k8 Q# Z/ R我们已经解决了一个问题,现在我们来应对另一个问题。 这里有各种解决方案,这取决于我们真正想要和愿意做什么。 就个人而言,我没有看到这个问题的理想和最终解决方案。 不过,我将尝试提出一种方式,读者能感到熟悉和理解。 最重要的是,该解决方案将完全基于 MQL5。 我甚至考虑过使用外部编码的可能性,但最终决定使用纯 MQL5。 诉诸外部编码,并利用 DLL 进行锁定的想法很诱人,但这太容易了。: z/ t& [9 H% X! A) D
我认为在诉诸外部 DLL 来填补 MQL5 语言无法胜任的空白之前,我们在 MQL5 中还有很多东西需要学习。 这将提供一个在使用外部代码时看起来“更干净”的解决方案。 只是,这并无助于更好地理解 MQL5。 此外,这可能会强化 MetaTrader 5 是一个受限平台的误解。 对平台的误解和效力利用不足助长了这种误解。8 F9 J8 I$ c8 W& ^# y
为了应用我们提议的解决方案,您不得不进行一些修改,并撤回其它更改。 第一步是更改 InterProcess.mqh 头文件,令其拥有以下结构:2 Z6 i& x& J- r
#property copyright "Daniel Jose": g0 s4 `0 ?( G
//+------------------------------------------------------------------+
: d3 j( r" {9 `#define def_GlobalVariableReplay "Replay Infos"
9 W N; l% r' @- }#define def_GlobalVariableIdGraphics "Replay ID"
/ l2 t) B% s' s% B/ S#define def_SymbolReplay "RePlay"
1 j3 ^$ j/ R4 x1 I) `# b# U! b#define def_MaxPosSlider 4003 \( E7 u% ^/ g) @5 C* C0 i
#define def_ShortName "Market Replay"8 t' [9 r" p; n z O
//+------------------------------------------------------------------+
1 ]) u. Y: n2 J5 V0 M0 t; T! nunion u_Interprocess
9 R; X: c3 T. l* L5 ]8 U{
7 V) }4 x4 {$ `- n4 p- Q/ Q* Lunion u_0: X+ a* j' I- m4 X/ T" L6 l; }
{. b2 {1 [( a8 J% p
double df_Value;
3 @) X' c& ?& |, B3 D3 xlong IdGraphic;) v, w' ^! [* X( D8 G
}u_Value;
0 M3 r1 N5 Y5 U- U$ M* Dstruct st_0
4 w) i8 d! z9 S( @{
' |/ P) e/ A% E7 s9 pbool isPlay;4 j/ U. H9 y# d7 V
int iPosShift;
7 f- Q6 O. h/ | g" Z; V}s_Infos;
- G5 X7 S% a% K6 R$ l/ q4 J};! ?% ^! O8 T: e% w
//+------------------------------------------------------------------+
" T( ?5 E9 c% X; z' h对于许多不熟悉编程的人来说,这似乎有点奇怪,但令人惊讶的是,上述结构仅占用 8 字节的内存。 您也许已经注意到,从上一篇文章的结构中删除了一个变量。 原因是我们将不再使用这种锁定方法。 我们将采取一种不同的方式,稍微复杂一些,但对于把控制指标限定于单个图表方面则有效得多。 这将是一个非常具体和明确的回放服务。4 J# I7 f' w+ m4 W9 z* U
注意: 如果 MetaTrader 5 平台和 MQL5 语言的开发人员为该服务提供了向特定图表添加指标的能力,或者允许该服务在图表上调用和执行脚本,那将会很有趣。 使用脚本,我们可以将指标添加到特定图表当中,但目前服务无法做到这一点。我们可以打开图表,但不能向其内添加指标。 当尝试执行此动作时,即使我们使用 MQL5 函数,也始终显示错误消息。 在撰写本文时,MetaTrader 5 版本为 build 3280。) n7 g9 L1 E3 I' R; o/ |
重要提示:在撰写本章的这个阶段,这是一个更高级的阶段,由此我才能够实现这一点。 不过,当我撰写这篇文章时,我找不到任何可以帮助解决这个问题的参考资料。 因此,请关注这个回放/模拟系列,看看我是如何想出解决方案的。
, D7 `3 t4 k4 J在这种关联境况下,通过运行下面的脚本,我们就能够打开指标,并将其添加到图表之中:. W- e. r. `! ]9 k4 e5 q
//+------------------------------------------------------------------+
5 C% W) ^6 [" v8 ] P1 U' M//| Script program start function |
4 v4 b0 h7 ^$ S- v, n3 L//+------------------------------------------------------------------+
0 k; @3 t7 X3 U( E$ F. [% `! q6 wvoid OnStart()
5 l$ u" k3 g. u{
8 }" e8 F4 r# v; V. hENUM_TIMEFRAMES time = PERIOD_D1; }; R/ ]$ [: Y' c$ s
string szSymbol = "EURUSD";
: e! N5 Z n% p) t; D: Xlong id = ChartOpen(szSymbol, time);
5 E. _5 M+ H# t: K/ t8 s: L8 iChartRedraw(id);
& c |/ g: `; L* M1 OChartIndicatorAdd(id, 0, iCustom(szSymbol, time, "Media Movel.ex5"));
' ]; q3 D. O9 d9 G" e}
, J# Z& P0 y& @ x; e( j9 F然而,如果我们将相同的脚本转换为服务,我们就不会得到相同的结果。 |