概述
: U7 W, v9 y+ P& h在上一篇文章我们曾做过一些修正和调整。 不过,依旧还有错误,如该文所附的视频所示。1 K; Y5 W% {$ N
在本文中,我们将亲眼见证如何修复此错误。 虽然表面上看这似乎很简单,但我们需要遵循若干个步骤。 这个过程将是奇妙和有趣的。 我们的目标是令指标专门应用于特定的图表和品种。 即使用户尝试,他们也无法将指标应用于另外的图表,或在一个会话中多次打开它。
3 V; N: |$ `# j. d) _ N( c% B我鼓励您继续阅读,因为内容承诺非常实用。
8 V1 B# W8 {8 V& m将指标锁定在特定品种上。, n' c! N: D( n! X
第一步是将控制指标链接到进行市场回放的品种。 这一步虽然看起来很简单,但对于开发我们的主要任务是必要的。 我们来看看指标代码在上下文中会是什么样子:
; V, [0 N$ Y% D6 ?. Z7 E; {; U#property copyright "Daniel Jose"3 W6 ^% l2 v |+ y6 P
#property indicator_chart_window6 ` F% ]0 V( ]$ ~9 }( l( a/ ^
#property indicator_plots 0: P" K8 _; E; S) x4 _9 J7 n( {
//+------------------------------------------------------------------+4 J3 ]0 x: F; t5 d7 |3 f
#include <Market Replay\C_Controls.mqh>
9 }& X+ r2 x; R. m! T1 S//+------------------------------------------------------------------+6 x. d. H' G: l6 s; l( V
C_Controls Control;
: g3 ?$ A8 K9 G) @: D) U% }% u//+------------------------------------------------------------------+
) z! R0 ?/ f. n& g6 Q% a% |! n( v+ zint OnInit()
' G% V- L& ^% K3 T. I{& ` J& y3 e8 L; J' W
u_Interprocess Info;% b P1 k2 s2 x$ F
IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);$ p* k$ g$ O! A
if (_Symbol != def_SymbolReplay)6 H+ W6 D ~% K8 t* F
{4 Z; g0 J' l! T! l' s' n1 q
ChartIndicatorDelete(ChartID(), 0, def_ShortName);5 O( ?& v& K! M6 A4 w6 ]5 f
return INIT_FAILED;
8 Y5 j7 Y) H) _/ i! g& T/ ]}
1 v% D* a' I* L" f1 R* Fif (GlobalVariableCheck(def_GlobalVariableReplay)) Info.Value = GlobalVariableGet(def_GlobalVariableReplay); else Info.Value = 0;
. d; z. s8 _; q. ]+ rControl.Init(Info.s_Infos.isPlay);- Z" m& v* v: \) v2 J7 `
return INIT_SUCCEEDED;
, U5 c7 I* j6 w5 Q' f}6 v& ^* M3 M( l# X" B: w
//+------------------------------------------------------------------+
* C4 _8 U6 A; m* Uint OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
* M; R* `: s& b! ]7 v) t{
5 l' M+ N$ t! o" Q! lreturn rates_total;1 G) l8 a- }1 r2 b# {3 v4 c
}1 T0 ?+ O% m3 V$ O1 f# I
//+------------------------------------------------------------------+
7 j/ a# h p" J" w# avoid OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam), p- \3 }% c! D9 M; H+ f
{+ M) `0 a2 [1 p# S: V& r
Control.DispatchMessage(id, lparam, dparam, sparam);
/ [+ G7 P( ?. e9 b' b}
: }2 k/ a0 ~1 k Y; u) G- }//+------------------------------------------------------------------+8 j a, o: ~+ {; \( O
void OnDeinit(const int reason)
; v% O( F+ h+ [- `+ @{* O7 x4 m- n7 {+ c* d" o$ {. u% _
switch (reason)8 @. }, X- A3 p" @
{
" j! R( l% j0 W# ocase REASON_REMOVE:9 z/ z. p/ i+ ~+ k+ x7 t. d
case REASON_CHARTCLOSE:' d" V% h6 `1 h2 R) Z/ B" Y
if (_Symbol != def_SymbolReplay) break;0 E' p& ?% ^' \ p) f" J2 Q
GlobalVariableDel(def_GlobalVariableReplay);4 i, V) Z/ K! e' F
ChartClose(ChartID());
/ \, w% M/ i. d) b4 S+ f8 `. O R6 qbreak;% _( j, {4 W# f: _& p1 _
}5 \. D5 `# T9 L3 t( l7 J+ O
}
+ G" j1 v' m$ {* k' `//+------------------------------------------------------------------+7 _& j' {" l! u5 w
我们首先检查针对的品种是否要进行市场回放。 如果不是这种情况,指标将自动关闭。 请注意,知道指标的名称很重要。 因此,初始化期间执行的第一个函数调用我们的指标,这令我们能够轻松删除它。
( a8 }( G6 P2 _8 A. ^2 N( n现在重要的一点是:当您将其从图表中删除时,MetaTrader 5 会生成 DeInit 事件。 此事件触发 OnDeInit 函数,而标记为 REASON_REMOVE 的事件表示从图表中删除指标。 这是因为该品种与指标设计绑定的品种不同。 如果我们不重新检查并阻止代码运行,品种图表将关闭。 不过,幸亏我们的检查,它将保持开放状态。
; W. N) e7 y$ r' W如果指标代码与上一篇文章中提供的代码不同,请不要感到惊讶:上一篇文章重点在于其它改进和修复。 不过,在编写了文章和代码,并录制了本文随附的视频后,我意识到尽管其中一个问题已解决,但另一个问题仍未被发现。 这就是为什么我不得不修改代码。/ i5 w" ~/ ^5 {6 G8 }% l
尽管进行了修改,但我们不会在此处详述所做的全部修改。 必须删除很大一部分,因为它对于此处讨论的锁定方面无效。 因此,上面的代码与以前的代码有很大差别。 不过,我相信上一篇文章中讲演的知识在某些时候可能对某些人有用。 我保存了那篇文章,以表明有时我们都会犯错误,但我们依旧应该努力把事情做好。
; `9 Z. }/ }0 U; r) j: W* N5 A$ e因此,我们来建立第一个锁定步骤,即确保控制指标仅存在于市场回放品种的图表上。 然而,该衡量值并不会阻止向同一图表或不同图表添加多个指标,因此必须进行调整。
. i# c3 {, u$ l W我们应该避免在同一图表上多次使用指标。; I2 N8 b) J! ]
我们已经解决了一个问题,现在我们来应对另一个问题。 这里有各种解决方案,这取决于我们真正想要和愿意做什么。 就个人而言,我没有看到这个问题的理想和最终解决方案。 不过,我将尝试提出一种方式,读者能感到熟悉和理解。 最重要的是,该解决方案将完全基于 MQL5。 我甚至考虑过使用外部编码的可能性,但最终决定使用纯 MQL5。 诉诸外部编码,并利用 DLL 进行锁定的想法很诱人,但这太容易了。
- Q, \5 f4 w* f# f, `我认为在诉诸外部 DLL 来填补 MQL5 语言无法胜任的空白之前,我们在 MQL5 中还有很多东西需要学习。 这将提供一个在使用外部代码时看起来“更干净”的解决方案。 只是,这并无助于更好地理解 MQL5。 此外,这可能会强化 MetaTrader 5 是一个受限平台的误解。 对平台的误解和效力利用不足助长了这种误解。
9 {, K8 j0 h% u, k u8 V- k为了应用我们提议的解决方案,您不得不进行一些修改,并撤回其它更改。 第一步是更改 InterProcess.mqh 头文件,令其拥有以下结构:
& a0 b; s, q0 f1 ~+ w$ p0 G#property copyright "Daniel Jose") G1 x/ ^/ C7 G5 p' g% {
//+------------------------------------------------------------------+
0 [0 h0 o2 e" r& f* S#define def_GlobalVariableReplay "Replay Infos": b9 A0 Y0 W# E. ~2 \; j8 V
#define def_GlobalVariableIdGraphics "Replay ID"
( `) x& H& T2 g0 ]: g#define def_SymbolReplay "RePlay"
+ [7 j/ E N4 [8 K! H- C' J9 o#define def_MaxPosSlider 400
0 F3 O4 W# ~ e- N. n#define def_ShortName "Market Replay"
" A3 }6 L0 ^2 F# j) Y//+------------------------------------------------------------------+5 w- ^! ]0 a( `: i3 z# {' e
union u_Interprocess
7 F8 e: z, l) J; a; ?{6 o" K5 p, r6 o$ ~* g* d# W
union u_0
2 u) Z4 ?3 Z0 n5 c% p: K& ]{/ Q& E6 e8 d4 x& k1 a
double df_Value;0 k6 U" `$ f0 b/ D$ p7 A; p
long IdGraphic;
0 z, |4 k/ ^& k, y}u_Value;
* h- n9 `- q4 ]3 Rstruct st_0
! D W! N. w S! _9 K8 v4 g{
0 s: v" F" R8 k- x f( S2 q2 U$ |bool isPlay;/ U+ U6 {6 a, f {4 Y& e0 p
int iPosShift;
& s; A4 y4 F) f8 k% I}s_Infos;4 J8 A1 K8 k% O) B" v8 A
};
2 }7 r+ ^. J4 \. a# a//+------------------------------------------------------------------+
7 ~, [( @- D' ^; l对于许多不熟悉编程的人来说,这似乎有点奇怪,但令人惊讶的是,上述结构仅占用 8 字节的内存。 您也许已经注意到,从上一篇文章的结构中删除了一个变量。 原因是我们将不再使用这种锁定方法。 我们将采取一种不同的方式,稍微复杂一些,但对于把控制指标限定于单个图表方面则有效得多。 这将是一个非常具体和明确的回放服务。
* h( V c( p! s5 t注意: 如果 MetaTrader 5 平台和 MQL5 语言的开发人员为该服务提供了向特定图表添加指标的能力,或者允许该服务在图表上调用和执行脚本,那将会很有趣。 使用脚本,我们可以将指标添加到特定图表当中,但目前服务无法做到这一点。我们可以打开图表,但不能向其内添加指标。 当尝试执行此动作时,即使我们使用 MQL5 函数,也始终显示错误消息。 在撰写本文时,MetaTrader 5 版本为 build 3280。
4 m1 j! ~. G) Y" B重要提示:在撰写本章的这个阶段,这是一个更高级的阶段,由此我才能够实现这一点。 不过,当我撰写这篇文章时,我找不到任何可以帮助解决这个问题的参考资料。 因此,请关注这个回放/模拟系列,看看我是如何想出解决方案的。( p7 b+ L- D/ O
在这种关联境况下,通过运行下面的脚本,我们就能够打开指标,并将其添加到图表之中:
: m* y5 G% E8 W3 E$ p6 N: q//+------------------------------------------------------------------+9 }8 \/ w. v: u& J5 X1 ? A6 O4 D
//| Script program start function |% \8 d# _0 r% n6 s& I1 L$ a
//+------------------------------------------------------------------+
0 ?* A2 d' i6 K& Q, F: _! K. d# |void OnStart()
3 I% E* @4 }# ^{
3 Q3 n: n. \+ B3 D' L, s/ i2 C V( eENUM_TIMEFRAMES time = PERIOD_D1;
/ L4 R2 e. p; T6 Y4 `# ustring szSymbol = "EURUSD";
' r2 s0 f6 R. I% B/ v* \- tlong id = ChartOpen(szSymbol, time);: `$ Z5 w+ N* K( d
ChartRedraw(id);* @4 W: W, F K# _+ D# }0 n
ChartIndicatorAdd(id, 0, iCustom(szSymbol, time, "Media Movel.ex5"));8 ^4 ^8 Z5 U/ v- ~7 T2 e( W7 Y( D5 Z
}7 S/ |5 n- G1 g, A
然而,如果我们将相同的脚本转换为服务,我们就不会得到相同的结果。 |