概述
5 T( k9 V; r- [在上一篇文章我们曾做过一些修正和调整。 不过,依旧还有错误,如该文所附的视频所示。& Z3 k9 J4 Y2 j1 Y
在本文中,我们将亲眼见证如何修复此错误。 虽然表面上看这似乎很简单,但我们需要遵循若干个步骤。 这个过程将是奇妙和有趣的。 我们的目标是令指标专门应用于特定的图表和品种。 即使用户尝试,他们也无法将指标应用于另外的图表,或在一个会话中多次打开它。
/ j; o1 O' \$ G$ q, ~我鼓励您继续阅读,因为内容承诺非常实用。" m. G" S; ]" ^7 U+ D9 X; I5 U
将指标锁定在特定品种上。2 X+ k! h+ S8 h1 J& Z7 h
第一步是将控制指标链接到进行市场回放的品种。 这一步虽然看起来很简单,但对于开发我们的主要任务是必要的。 我们来看看指标代码在上下文中会是什么样子:# T2 C1 z/ N6 \- D4 h+ t6 V! h9 P5 T/ o
#property copyright "Daniel Jose"
3 h" Y- n2 a8 N$ ^4 |: C#property indicator_chart_window
7 a6 P, I2 d: o. f1 G# s* P* P/ E9 @& w, t#property indicator_plots 0
6 t2 M, d; z) `3 S: W1 C- U$ d//+------------------------------------------------------------------+
2 k* D$ D" e# \ e$ E' t#include <Market Replay\C_Controls.mqh>
/ H7 E" V) P' [" Z5 K$ k* r2 f//+------------------------------------------------------------------+
9 h, o/ G Y {$ \C_Controls Control;
3 ]2 B( K3 [/ l/ Q& T//+------------------------------------------------------------------+
4 q( |$ o: [' f3 }int OnInit()# v: G; n! E4 q
{
, M, _% ]7 c) W3 Eu_Interprocess Info;
0 N' q/ ^$ i% tIndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);0 ?! z O8 x1 c
if (_Symbol != def_SymbolReplay)
( X) P: @; `- H& u2 I2 C: a{
0 M" ?/ e/ |% S" xChartIndicatorDelete(ChartID(), 0, def_ShortName);- K3 O Q8 g8 A$ T/ A& P
return INIT_FAILED;
+ ]5 \! Z: a0 A$ i& S}
7 i' Q- p$ b# c% i6 [& `if (GlobalVariableCheck(def_GlobalVariableReplay)) Info.Value = GlobalVariableGet(def_GlobalVariableReplay); else Info.Value = 0;4 P+ g, ]8 j/ ^9 V3 t1 g
Control.Init(Info.s_Infos.isPlay);
: _" N! F0 V- A$ H& R( r+ [+ L1 Ureturn INIT_SUCCEEDED;: K: m3 X& Q N7 ]0 f
}
; n2 a# H) h. N//+------------------------------------------------------------------+6 [4 c; w3 }5 M+ }
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
! R/ e6 E) _* {{- E! R0 ~. q; f, k" b7 g8 A( N, \: B
return rates_total;
1 ^- B X3 q6 \. K7 P3 A6 X% @: C8 o}
: s7 c, W% }7 W1 X//+------------------------------------------------------------------+% ^* T7 q5 x% g6 o8 W
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
7 g$ Q( L) L& G. ]( x. Q{
1 s* Y+ v6 F/ x' @- H7 @* iControl.DispatchMessage(id, lparam, dparam, sparam);9 X M" I: g: Y2 F& V
}5 n5 E5 X/ E) c) u/ |; j
//+------------------------------------------------------------------+
( w; }- N8 `3 _. j5 F' r% Qvoid OnDeinit(const int reason)# c! ?) s6 H7 d3 Q- }
{
6 D! h: D8 ?( P( O( Nswitch (reason), s% @ q( C% a% G+ l
{6 d: w; [$ z8 e: f# I! I
case REASON_REMOVE:
3 Y5 V+ P: j3 T, M7 f1 M* f$ ccase REASON_CHARTCLOSE:
8 s8 F& |: @" Y* q8 |9 J/ Oif (_Symbol != def_SymbolReplay) break;
0 l! `9 O( e0 @* j- G' H- f& m/ cGlobalVariableDel(def_GlobalVariableReplay);
6 ]! R3 I9 u1 V3 i3 w: l, o" eChartClose(ChartID());+ }9 |* }4 {! a+ X. p
break;
5 Y8 h- |" e3 T# S2 t: w1 D}
4 P6 g1 ^, |) }}7 N, T! L9 |/ b: |6 ?/ r) N0 f
//+------------------------------------------------------------------+7 b' I4 ?5 E& A! A* X7 g; d
我们首先检查针对的品种是否要进行市场回放。 如果不是这种情况,指标将自动关闭。 请注意,知道指标的名称很重要。 因此,初始化期间执行的第一个函数调用我们的指标,这令我们能够轻松删除它。
7 Z& }- E) t* z1 J8 [( N C现在重要的一点是:当您将其从图表中删除时,MetaTrader 5 会生成 DeInit 事件。 此事件触发 OnDeInit 函数,而标记为 REASON_REMOVE 的事件表示从图表中删除指标。 这是因为该品种与指标设计绑定的品种不同。 如果我们不重新检查并阻止代码运行,品种图表将关闭。 不过,幸亏我们的检查,它将保持开放状态。8 h) N- e" |3 Z) d- Q' P8 b/ e
如果指标代码与上一篇文章中提供的代码不同,请不要感到惊讶:上一篇文章重点在于其它改进和修复。 不过,在编写了文章和代码,并录制了本文随附的视频后,我意识到尽管其中一个问题已解决,但另一个问题仍未被发现。 这就是为什么我不得不修改代码。
. m/ P8 z7 A/ g尽管进行了修改,但我们不会在此处详述所做的全部修改。 必须删除很大一部分,因为它对于此处讨论的锁定方面无效。 因此,上面的代码与以前的代码有很大差别。 不过,我相信上一篇文章中讲演的知识在某些时候可能对某些人有用。 我保存了那篇文章,以表明有时我们都会犯错误,但我们依旧应该努力把事情做好。
( W- S0 z9 M3 @5 P1 ]$ Q因此,我们来建立第一个锁定步骤,即确保控制指标仅存在于市场回放品种的图表上。 然而,该衡量值并不会阻止向同一图表或不同图表添加多个指标,因此必须进行调整。
/ y+ r5 @; }3 t我们应该避免在同一图表上多次使用指标。
7 s2 G3 h. f4 ~& l- v0 b7 Y我们已经解决了一个问题,现在我们来应对另一个问题。 这里有各种解决方案,这取决于我们真正想要和愿意做什么。 就个人而言,我没有看到这个问题的理想和最终解决方案。 不过,我将尝试提出一种方式,读者能感到熟悉和理解。 最重要的是,该解决方案将完全基于 MQL5。 我甚至考虑过使用外部编码的可能性,但最终决定使用纯 MQL5。 诉诸外部编码,并利用 DLL 进行锁定的想法很诱人,但这太容易了。0 Y( j; h% d. @
我认为在诉诸外部 DLL 来填补 MQL5 语言无法胜任的空白之前,我们在 MQL5 中还有很多东西需要学习。 这将提供一个在使用外部代码时看起来“更干净”的解决方案。 只是,这并无助于更好地理解 MQL5。 此外,这可能会强化 MetaTrader 5 是一个受限平台的误解。 对平台的误解和效力利用不足助长了这种误解。3 a! E S. F* p6 ~* K/ M; C# C
为了应用我们提议的解决方案,您不得不进行一些修改,并撤回其它更改。 第一步是更改 InterProcess.mqh 头文件,令其拥有以下结构:
2 M7 C1 b) ?& e; w9 i( P I#property copyright "Daniel Jose"2 h0 H4 U! Z2 j! P+ Z5 C! T
//+------------------------------------------------------------------+. m1 m5 Y5 t9 T+ \
#define def_GlobalVariableReplay "Replay Infos"" _0 r* P) i& V( Z- U
#define def_GlobalVariableIdGraphics "Replay ID"$ C2 Z% f+ V4 D- s! I/ a+ `
#define def_SymbolReplay "RePlay"
' M& n4 ~ T" R8 H# Y5 K#define def_MaxPosSlider 400
/ E8 l! i! U% ?, A#define def_ShortName "Market Replay"
3 ^$ t, b5 e) A C, E* X* I//+------------------------------------------------------------------+
; v. V$ M9 C; Y! X. m, E* Ounion u_Interprocess- ^, s% G' l& L& d, {6 ^" ]" w& n
{5 i: ?. e% v" p
union u_0$ @3 Y, V! K4 }: h" d2 Z
{
& x6 I" w! Z' ^+ L6 odouble df_Value;1 k4 d- ]! U" |- `. Q
long IdGraphic;
" b! h0 e/ S7 S! V4 ?7 n}u_Value;- z+ H' H+ p+ Z, I6 A
struct st_0
7 S1 s. Q2 D4 u- O8 {& Z{
+ \- ]8 J/ l# g. Ibool isPlay;
; }" D: \& a4 h1 v% Q6 D' X$ zint iPosShift;5 T: {: u+ W1 A0 i( s# e+ d
}s_Infos;
- Q* B! d1 w" x! Z- p};
3 }8 Q; b; z. g4 V9 _- \* t) P//+------------------------------------------------------------------+
" A1 f. b8 F/ t% ], E, D8 J对于许多不熟悉编程的人来说,这似乎有点奇怪,但令人惊讶的是,上述结构仅占用 8 字节的内存。 您也许已经注意到,从上一篇文章的结构中删除了一个变量。 原因是我们将不再使用这种锁定方法。 我们将采取一种不同的方式,稍微复杂一些,但对于把控制指标限定于单个图表方面则有效得多。 这将是一个非常具体和明确的回放服务。
6 b5 v5 K% Q' C$ B6 L7 ]注意: 如果 MetaTrader 5 平台和 MQL5 语言的开发人员为该服务提供了向特定图表添加指标的能力,或者允许该服务在图表上调用和执行脚本,那将会很有趣。 使用脚本,我们可以将指标添加到特定图表当中,但目前服务无法做到这一点。我们可以打开图表,但不能向其内添加指标。 当尝试执行此动作时,即使我们使用 MQL5 函数,也始终显示错误消息。 在撰写本文时,MetaTrader 5 版本为 build 3280。+ T7 h5 z# m" x: W
重要提示:在撰写本章的这个阶段,这是一个更高级的阶段,由此我才能够实现这一点。 不过,当我撰写这篇文章时,我找不到任何可以帮助解决这个问题的参考资料。 因此,请关注这个回放/模拟系列,看看我是如何想出解决方案的。% S. P( g3 w( c9 V7 n( w e8 E" Q
在这种关联境况下,通过运行下面的脚本,我们就能够打开指标,并将其添加到图表之中:/ g* R! H' R6 U6 z6 i
//+------------------------------------------------------------------+
' P9 `9 F( i j5 i//| Script program start function |
$ Y+ X- J2 Q. d5 m( R( h+ f2 `- ?) m//+------------------------------------------------------------------+
7 W1 x# D7 T/ K3 s& Kvoid OnStart()4 M4 b$ y6 ]7 @1 f
{. ]+ r+ ^: W7 ]2 M6 j
ENUM_TIMEFRAMES time = PERIOD_D1;# i; \4 j( w c
string szSymbol = "EURUSD";
$ v5 J$ E2 r- V) Y/ Z0 Glong id = ChartOpen(szSymbol, time);
- k1 h4 l. F! a1 j# VChartRedraw(id);
5 g. _. [; u& h5 K/ X7 P. `ChartIndicatorAdd(id, 0, iCustom(szSymbol, time, "Media Movel.ex5"));3 v$ s6 x, g5 g: S( x
}
" L9 I: q0 }! B, ]" B然而,如果我们将相同的脚本转换为服务,我们就不会得到相同的结果。 |