概述* z7 V1 h: o- A) I: Z
在上一篇文章我们曾做过一些修正和调整。 不过,依旧还有错误,如该文所附的视频所示。
% T( t" I8 u/ O( b4 d3 C1 Q在本文中,我们将亲眼见证如何修复此错误。 虽然表面上看这似乎很简单,但我们需要遵循若干个步骤。 这个过程将是奇妙和有趣的。 我们的目标是令指标专门应用于特定的图表和品种。 即使用户尝试,他们也无法将指标应用于另外的图表,或在一个会话中多次打开它。3 H5 Y1 d4 e) G' k! Z+ H3 k
我鼓励您继续阅读,因为内容承诺非常实用。
9 [' n. S' X* ~6 \' X1 d' T& ~将指标锁定在特定品种上。 n% Q$ F1 ?% I; i- V3 z2 v
第一步是将控制指标链接到进行市场回放的品种。 这一步虽然看起来很简单,但对于开发我们的主要任务是必要的。 我们来看看指标代码在上下文中会是什么样子:3 h" d, Y6 \8 A
#property copyright "Daniel Jose"3 I' F' `9 j) q B' F
#property indicator_chart_window* C( Y2 e$ J4 L- n5 o
#property indicator_plots 0
i5 L( t2 p" h//+------------------------------------------------------------------+
% e0 L+ G$ s: u! V$ \, p#include <Market Replay\C_Controls.mqh>" |- v' J6 {8 z8 u) i' d5 N$ X, u
//+------------------------------------------------------------------+) h% ^5 X, X E
C_Controls Control;
% L. N7 P5 n0 a& s. a//+------------------------------------------------------------------+
8 n# U( C( i% h3 I7 w) v& wint OnInit()
6 r5 g+ [# }* n8 _{
! P R) M. b+ k; y, d8 l$ M) D$ Pu_Interprocess Info;
2 l9 Z% H( b$ A" `. a$ ZIndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);
" o4 N5 C {, ^ Q. }1 C. H+ H$ lif (_Symbol != def_SymbolReplay)$ O# N1 i2 W5 v" s
{3 l9 P% I7 R) S4 j
ChartIndicatorDelete(ChartID(), 0, def_ShortName);
9 m- D- o' C M/ Rreturn INIT_FAILED;7 F `& W" n% k0 d8 j' j1 Q
}
# ?2 M5 E6 U( l) \; E7 x0 wif (GlobalVariableCheck(def_GlobalVariableReplay)) Info.Value = GlobalVariableGet(def_GlobalVariableReplay); else Info.Value = 0;% X% u! M0 {) o+ n6 H
Control.Init(Info.s_Infos.isPlay);9 S' F8 @2 B9 s: f
return INIT_SUCCEEDED;3 a$ ~9 [1 u3 g% f
}. \( U, g- u, _* n6 E
//+------------------------------------------------------------------+( m+ V% z% O* j
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])6 J8 {* Z: D$ A' ?
{
- d0 j/ s7 s- b/ h$ _- Z6 ~return rates_total;' g# M3 N" K+ I1 u
}
! x0 m" ?0 b9 T' S% T1 j//+------------------------------------------------------------------+- l/ q' F' _- y6 F! @ x; l/ J
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
8 d$ ~9 j# u g$ v{
% i8 }+ g1 B2 M4 M6 Q( p' y$ JControl.DispatchMessage(id, lparam, dparam, sparam);% l8 p5 e; U/ q7 O. k
}
% D9 B1 o* \2 B" m5 o/ C4 k//+------------------------------------------------------------------+/ m. ~" a/ Q! j- l# {: Y
void OnDeinit(const int reason): ]5 u/ Y& g. Z. f) y: z0 `% @9 Y
{4 f& Y& \7 P" F, A+ j2 H
switch (reason)
a7 C$ [* }# d. ~+ \" z{
2 y0 {9 M4 I7 ?/ h- h0 v! `0 {case REASON_REMOVE:6 h- @& v. F, C4 F) r2 N* X
case REASON_CHARTCLOSE:
6 b+ Q; n6 g9 d6 P' d5 bif (_Symbol != def_SymbolReplay) break;
( u- _4 p9 o& hGlobalVariableDel(def_GlobalVariableReplay);
3 Q8 C4 A7 y7 G4 T* A" W0 m, u* _ChartClose(ChartID());
( b" U5 I3 S" H/ Q+ X/ {! Sbreak;
+ j4 ~( c( H# H: L( ?' A3 B3 E}- `+ U: d9 _% q' h5 Y( I2 d
}' G# U2 B0 B6 b( [ e/ [( Y
//+------------------------------------------------------------------+
8 y" f9 V7 G; K8 `4 }7 `我们首先检查针对的品种是否要进行市场回放。 如果不是这种情况,指标将自动关闭。 请注意,知道指标的名称很重要。 因此,初始化期间执行的第一个函数调用我们的指标,这令我们能够轻松删除它。% a9 G- K$ S! A
现在重要的一点是:当您将其从图表中删除时,MetaTrader 5 会生成 DeInit 事件。 此事件触发 OnDeInit 函数,而标记为 REASON_REMOVE 的事件表示从图表中删除指标。 这是因为该品种与指标设计绑定的品种不同。 如果我们不重新检查并阻止代码运行,品种图表将关闭。 不过,幸亏我们的检查,它将保持开放状态。
7 J* g) n# e h5 _如果指标代码与上一篇文章中提供的代码不同,请不要感到惊讶:上一篇文章重点在于其它改进和修复。 不过,在编写了文章和代码,并录制了本文随附的视频后,我意识到尽管其中一个问题已解决,但另一个问题仍未被发现。 这就是为什么我不得不修改代码。* x, ?7 x. d: f/ d: |8 [
尽管进行了修改,但我们不会在此处详述所做的全部修改。 必须删除很大一部分,因为它对于此处讨论的锁定方面无效。 因此,上面的代码与以前的代码有很大差别。 不过,我相信上一篇文章中讲演的知识在某些时候可能对某些人有用。 我保存了那篇文章,以表明有时我们都会犯错误,但我们依旧应该努力把事情做好。" `5 i" @6 c- w! O- I; @
因此,我们来建立第一个锁定步骤,即确保控制指标仅存在于市场回放品种的图表上。 然而,该衡量值并不会阻止向同一图表或不同图表添加多个指标,因此必须进行调整。 B. b( n) _4 i* x0 G+ I4 R- K
我们应该避免在同一图表上多次使用指标。: C, t- f& ^: n, q0 q# r6 v" n$ N8 y
我们已经解决了一个问题,现在我们来应对另一个问题。 这里有各种解决方案,这取决于我们真正想要和愿意做什么。 就个人而言,我没有看到这个问题的理想和最终解决方案。 不过,我将尝试提出一种方式,读者能感到熟悉和理解。 最重要的是,该解决方案将完全基于 MQL5。 我甚至考虑过使用外部编码的可能性,但最终决定使用纯 MQL5。 诉诸外部编码,并利用 DLL 进行锁定的想法很诱人,但这太容易了。
0 v, k* q+ E V5 C我认为在诉诸外部 DLL 来填补 MQL5 语言无法胜任的空白之前,我们在 MQL5 中还有很多东西需要学习。 这将提供一个在使用外部代码时看起来“更干净”的解决方案。 只是,这并无助于更好地理解 MQL5。 此外,这可能会强化 MetaTrader 5 是一个受限平台的误解。 对平台的误解和效力利用不足助长了这种误解。
) y' ^7 |9 m# [0 K' V为了应用我们提议的解决方案,您不得不进行一些修改,并撤回其它更改。 第一步是更改 InterProcess.mqh 头文件,令其拥有以下结构:' _ w. ~! o5 p v! m3 {
#property copyright "Daniel Jose"
* V& p; J; o' D& v//+------------------------------------------------------------------+) u) p7 i N8 i, e) L+ z0 s% ^
#define def_GlobalVariableReplay "Replay Infos"
# W" Z- h, {! K#define def_GlobalVariableIdGraphics "Replay ID"
" Y1 r* E/ h3 G. v#define def_SymbolReplay "RePlay"
7 p" D9 a: _. w/ T! `#define def_MaxPosSlider 4001 i+ g' N& i+ J
#define def_ShortName "Market Replay"3 D% i) s% ]$ F( r
//+------------------------------------------------------------------+
+ F% i4 O$ h3 M% a' Dunion u_Interprocess/ z" T$ B1 m1 |9 \
{
" |3 ]3 k) V; O1 nunion u_0; I9 D' l E5 x3 O3 {1 W0 P; i
{" L) r3 U/ z6 b5 r
double df_Value;
3 m. f. Y$ J' R4 E* h) along IdGraphic;
& p- P0 w( b& d# v}u_Value;
. M3 q# X7 _7 `8 J$ Mstruct st_0
; O$ }$ G; W/ G% o{6 g- h/ X6 b. L; q
bool isPlay;
; P& Q& y5 g5 ~6 A0 Hint iPosShift;2 h# D* Q1 w. @4 l# A( j* F& q
}s_Infos;; K$ }2 u. F& f
};( F# m& O$ R7 T# e
//+------------------------------------------------------------------+
) [9 L! x5 e! I1 C, d% X对于许多不熟悉编程的人来说,这似乎有点奇怪,但令人惊讶的是,上述结构仅占用 8 字节的内存。 您也许已经注意到,从上一篇文章的结构中删除了一个变量。 原因是我们将不再使用这种锁定方法。 我们将采取一种不同的方式,稍微复杂一些,但对于把控制指标限定于单个图表方面则有效得多。 这将是一个非常具体和明确的回放服务。 Y# O& ~2 I4 L5 n q0 V, X4 a
注意: 如果 MetaTrader 5 平台和 MQL5 语言的开发人员为该服务提供了向特定图表添加指标的能力,或者允许该服务在图表上调用和执行脚本,那将会很有趣。 使用脚本,我们可以将指标添加到特定图表当中,但目前服务无法做到这一点。我们可以打开图表,但不能向其内添加指标。 当尝试执行此动作时,即使我们使用 MQL5 函数,也始终显示错误消息。 在撰写本文时,MetaTrader 5 版本为 build 3280。& o- J+ C! g ?- J6 ~! C
重要提示:在撰写本章的这个阶段,这是一个更高级的阶段,由此我才能够实现这一点。 不过,当我撰写这篇文章时,我找不到任何可以帮助解决这个问题的参考资料。 因此,请关注这个回放/模拟系列,看看我是如何想出解决方案的。3 R6 l4 u+ T6 K5 Y, @7 C
在这种关联境况下,通过运行下面的脚本,我们就能够打开指标,并将其添加到图表之中:
! u; h: v) T! S2 h//+------------------------------------------------------------------+
0 f& T$ ~4 E) p( P% a//| Script program start function |
5 l/ e7 f& v& y4 }9 @7 Z8 a//+------------------------------------------------------------------+
3 t- j3 {* Q! k9 F9 `7 Lvoid OnStart()
9 S5 n7 o. L/ t" ~: Y& Q{
/ w: R) j/ P9 q8 O. dENUM_TIMEFRAMES time = PERIOD_D1;
" ?; X- x6 `; u: D. W, _string szSymbol = "EURUSD";
* v8 z! P) X- [& Nlong id = ChartOpen(szSymbol, time);& _# D/ \% a% J6 b, [
ChartRedraw(id);. h F. N {8 A! r' I- [
ChartIndicatorAdd(id, 0, iCustom(szSymbol, time, "Media Movel.ex5"));
v: ^$ M2 `- x# E' K! N$ }" f; k}
* K" z' O7 ]/ u, n! U: \& W然而,如果我们将相同的脚本转换为服务,我们就不会得到相同的结果。 |