概述
' {1 j# n. v" ]0 R8 Y4 A6 x在上一篇文章我们曾做过一些修正和调整。 不过,依旧还有错误,如该文所附的视频所示。
$ v- A: `. |. `1 |3 o# [( t在本文中,我们将亲眼见证如何修复此错误。 虽然表面上看这似乎很简单,但我们需要遵循若干个步骤。 这个过程将是奇妙和有趣的。 我们的目标是令指标专门应用于特定的图表和品种。 即使用户尝试,他们也无法将指标应用于另外的图表,或在一个会话中多次打开它。, @/ P. o5 ^3 O8 Z1 B
我鼓励您继续阅读,因为内容承诺非常实用。
! ]* H9 q$ ^2 m, n7 ^9 {将指标锁定在特定品种上。$ B4 l8 K$ r# J1 G
第一步是将控制指标链接到进行市场回放的品种。 这一步虽然看起来很简单,但对于开发我们的主要任务是必要的。 我们来看看指标代码在上下文中会是什么样子:
/ ]" E2 g! M4 v M5 t$ S#property copyright "Daniel Jose", ]. ^0 y, w1 [6 X
#property indicator_chart_window) L: p' E4 N9 D6 R5 @( q
#property indicator_plots 0
8 b6 v2 E7 y: V//+------------------------------------------------------------------+4 y/ B7 s6 b, g" l) J
#include <Market Replay\C_Controls.mqh>+ N5 I& V( X9 S7 ~5 m
//+------------------------------------------------------------------+
, A9 I2 }) N P6 eC_Controls Control;$ r) G8 S: y% Z1 L
//+------------------------------------------------------------------+; D* A. \1 M: [1 u$ A
int OnInit()2 O) T( e* ]5 E& Q, W* p+ c- k! k
{! k. ?; X' p6 `
u_Interprocess Info;1 p& W* P% j* g7 o! q2 `
IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);
+ g% z6 Q" j& \+ r" x% [; s1 _8 Xif (_Symbol != def_SymbolReplay)
3 G! g; Y8 z, B* ?{
2 Q( ^3 V& N4 z T, N( [! MChartIndicatorDelete(ChartID(), 0, def_ShortName);
$ F" U. q& y! F+ V% e% Z; b+ ireturn INIT_FAILED;
: q3 Y: M6 k/ e" f. w& [9 ^}- [( x7 F6 ?- r; Y L3 a$ y
if (GlobalVariableCheck(def_GlobalVariableReplay)) Info.Value = GlobalVariableGet(def_GlobalVariableReplay); else Info.Value = 0;
; p! P/ P3 M$ j1 ]% M4 GControl.Init(Info.s_Infos.isPlay);
# R. {3 ~! e" _2 ireturn INIT_SUCCEEDED;
2 _& i" ]9 Q# p$ d" @0 x1 d/ y, T}
0 X- k6 ^# V4 ^& E( t//+------------------------------------------------------------------+
& h+ J2 x1 K. H! s; {1 Yint OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])' X+ ]* \8 x$ o! p# o1 r
{
% [2 ~1 a" d! v B: v# ireturn rates_total;
' z. P" |- z0 M! e( {; ?}% h1 ~! u" B( M$ ^9 i7 C
//+------------------------------------------------------------------+( ]$ i: d+ g B: c
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)# l' E) M# F! {$ |: w6 W
{
( Z# Y' i% O ?- J/ R5 w* mControl.DispatchMessage(id, lparam, dparam, sparam);
) R6 i: `1 D( O! |% M9 u}3 o2 \8 S4 `2 u! J5 s
//+------------------------------------------------------------------+6 A7 |* \: z, D8 v$ u- ~$ J
void OnDeinit(const int reason)
Z& L# A# \5 | Y, S) N4 v{* L& w) ~0 \! t( H( g: | i
switch (reason)
X T0 T$ ~1 X$ g; X. x7 u$ a2 @{
9 `) z- s" |* ~/ L! Z4 O- O# v0 u* I7 p/ [9 ncase REASON_REMOVE:3 m# x7 u' p1 h
case REASON_CHARTCLOSE:
; g# h2 H7 n! m3 o Eif (_Symbol != def_SymbolReplay) break;+ g: M' A0 j+ d$ {' a3 h) j
GlobalVariableDel(def_GlobalVariableReplay);
' r) Z$ T7 C2 j7 g* XChartClose(ChartID());
# Q) Y7 C; q1 k8 P" Nbreak;
: ^' P& t8 s* v}& Y j* @6 Q c t6 @& B
}
% U+ x5 Y0 K5 H X//+------------------------------------------------------------------+9 m1 A+ [# {7 l) F( h$ E+ `! C; O6 k7 P
我们首先检查针对的品种是否要进行市场回放。 如果不是这种情况,指标将自动关闭。 请注意,知道指标的名称很重要。 因此,初始化期间执行的第一个函数调用我们的指标,这令我们能够轻松删除它。
! D6 [7 k/ N" H/ d# J+ U现在重要的一点是:当您将其从图表中删除时,MetaTrader 5 会生成 DeInit 事件。 此事件触发 OnDeInit 函数,而标记为 REASON_REMOVE 的事件表示从图表中删除指标。 这是因为该品种与指标设计绑定的品种不同。 如果我们不重新检查并阻止代码运行,品种图表将关闭。 不过,幸亏我们的检查,它将保持开放状态。
5 r2 p6 ~+ o+ p V如果指标代码与上一篇文章中提供的代码不同,请不要感到惊讶:上一篇文章重点在于其它改进和修复。 不过,在编写了文章和代码,并录制了本文随附的视频后,我意识到尽管其中一个问题已解决,但另一个问题仍未被发现。 这就是为什么我不得不修改代码。+ H# @ k9 A" o( u" G8 S) Z" _: S0 C# o- D
尽管进行了修改,但我们不会在此处详述所做的全部修改。 必须删除很大一部分,因为它对于此处讨论的锁定方面无效。 因此,上面的代码与以前的代码有很大差别。 不过,我相信上一篇文章中讲演的知识在某些时候可能对某些人有用。 我保存了那篇文章,以表明有时我们都会犯错误,但我们依旧应该努力把事情做好。
2 y; \2 `+ {9 I" `6 p因此,我们来建立第一个锁定步骤,即确保控制指标仅存在于市场回放品种的图表上。 然而,该衡量值并不会阻止向同一图表或不同图表添加多个指标,因此必须进行调整。
. n7 o4 q, O2 \ q, V/ U6 I; ^我们应该避免在同一图表上多次使用指标。
J& U$ P' P$ k# c我们已经解决了一个问题,现在我们来应对另一个问题。 这里有各种解决方案,这取决于我们真正想要和愿意做什么。 就个人而言,我没有看到这个问题的理想和最终解决方案。 不过,我将尝试提出一种方式,读者能感到熟悉和理解。 最重要的是,该解决方案将完全基于 MQL5。 我甚至考虑过使用外部编码的可能性,但最终决定使用纯 MQL5。 诉诸外部编码,并利用 DLL 进行锁定的想法很诱人,但这太容易了。0 T* n; G7 t5 Z4 f
我认为在诉诸外部 DLL 来填补 MQL5 语言无法胜任的空白之前,我们在 MQL5 中还有很多东西需要学习。 这将提供一个在使用外部代码时看起来“更干净”的解决方案。 只是,这并无助于更好地理解 MQL5。 此外,这可能会强化 MetaTrader 5 是一个受限平台的误解。 对平台的误解和效力利用不足助长了这种误解。, @. O8 E. q/ ~% Y) w# q
为了应用我们提议的解决方案,您不得不进行一些修改,并撤回其它更改。 第一步是更改 InterProcess.mqh 头文件,令其拥有以下结构:& [6 N; m; ~4 _
#property copyright "Daniel Jose"
3 P2 p7 a0 V2 G//+------------------------------------------------------------------++ K% n3 A e, F3 ?$ o0 w8 r
#define def_GlobalVariableReplay "Replay Infos"" |/ N* H5 U$ h' a' @
#define def_GlobalVariableIdGraphics "Replay ID"
# m6 h; Z, [( J) t#define def_SymbolReplay "RePlay"
2 q; ~$ h y# }0 k#define def_MaxPosSlider 400% @3 ^4 C9 k/ U* S# \. `
#define def_ShortName "Market Replay"
0 { F4 B; W2 l; ?$ h: C, Q+ `//+------------------------------------------------------------------+
9 Y0 q/ ]1 I; R( g( l/ g4 i0 j0 Runion u_Interprocess
% s# t3 F- e$ d{
) K5 h& b' C* @9 ~3 Z1 Aunion u_0
4 d( l( F3 @* W; t1 P9 h2 L: U{
/ Z* O% M9 q1 I" K5 d& bdouble df_Value;
, v; o) {( G6 f. q/ N- i' Y% |long IdGraphic;
: W5 W" Z5 B2 i5 c8 x/ I}u_Value;4 |+ E. G) K# U) A; v; N
struct st_0( {7 E8 E) @) J) m( }9 ^3 X
{
1 y! I: p, M/ O8 y+ zbool isPlay;6 W! P1 J' o: M3 l5 ]9 A) f+ l+ Z
int iPosShift;+ B4 B$ Y& M+ v# d; j- {8 O2 V
}s_Infos;
( z$ J8 n* N( G};% ]6 v+ l; d: o. V; A0 N* G5 G# k
//+------------------------------------------------------------------+
, y' U+ @; Z& l+ X' G/ T对于许多不熟悉编程的人来说,这似乎有点奇怪,但令人惊讶的是,上述结构仅占用 8 字节的内存。 您也许已经注意到,从上一篇文章的结构中删除了一个变量。 原因是我们将不再使用这种锁定方法。 我们将采取一种不同的方式,稍微复杂一些,但对于把控制指标限定于单个图表方面则有效得多。 这将是一个非常具体和明确的回放服务。
( t- G7 y$ R- Y& V. ^8 t- F注意: 如果 MetaTrader 5 平台和 MQL5 语言的开发人员为该服务提供了向特定图表添加指标的能力,或者允许该服务在图表上调用和执行脚本,那将会很有趣。 使用脚本,我们可以将指标添加到特定图表当中,但目前服务无法做到这一点。我们可以打开图表,但不能向其内添加指标。 当尝试执行此动作时,即使我们使用 MQL5 函数,也始终显示错误消息。 在撰写本文时,MetaTrader 5 版本为 build 3280。
. g2 Q; S* O& B$ N0 Q9 b4 m- U重要提示:在撰写本章的这个阶段,这是一个更高级的阶段,由此我才能够实现这一点。 不过,当我撰写这篇文章时,我找不到任何可以帮助解决这个问题的参考资料。 因此,请关注这个回放/模拟系列,看看我是如何想出解决方案的。$ L3 ^0 Z: X/ Z. O& W( o
在这种关联境况下,通过运行下面的脚本,我们就能够打开指标,并将其添加到图表之中:
+ z( V4 }) O8 Z# W' `) s/ U7 }//+------------------------------------------------------------------++ E% m0 q2 r8 t. E3 j3 g y
//| Script program start function |
1 L1 k5 A8 n/ o! Q! w//+------------------------------------------------------------------+
8 E/ d% l$ i' n% m7 mvoid OnStart()
[/ N3 b/ o8 r; G7 c6 [% [: X( j{
/ L. @6 q/ s, t, q" r2 N4 t1 NENUM_TIMEFRAMES time = PERIOD_D1;
9 B4 ~# W6 A |) u( u7 z" B1 k3 Tstring szSymbol = "EURUSD";! d1 \0 N7 r2 j. N7 I& f I( p
long id = ChartOpen(szSymbol, time);
! z( X" ]. S9 g) y( @/ |9 H- A1 GChartRedraw(id);
5 u; D! B: S/ \; p8 P6 T6 iChartIndicatorAdd(id, 0, iCustom(szSymbol, time, "Media Movel.ex5"));4 e8 Y) D! T" { Y& U0 Y
}
0 |8 @* [* P" u3 R然而,如果我们将相同的脚本转换为服务,我们就不会得到相同的结果。 |