虽然语法乍一看可能
与 C 有点相似,
但 MQL4 语言却是另一回事,
它存在于一个相当特定的生态系统
中,具有许多无与伦比的双刃剑特性。
TL;博士; 至少,你已经被警告过了。
自从原始 MQL4 语言的早期状态以来,就有一些重要的概念远远超出了 C 的经典范围。
MQL4 代码单元(无论是 { EA: Expert Advisor | CI: Custom Indicator | Script: Script } 中的任何一个)正在代码执行生态系统的几种不同模式中执行,或者:
- 已被“放在”图表上,即在实时市场时间或周末
- 已在终端的 [策略测试器] 回测工具中“设置”为普通模式
- 在 [策略测试器]中“设置”了优化模块的复杂模式
虽然这对于核心 MetaTrader Quant Modellers来说似乎很明显,但人们也可能同意这是 O/P 上下文的隐藏部分,仅通过解码有点神秘的第二句(引文)即可阅读:
“只是一个简单的 MT4 EA”。
那么,MQL4 使用外部变量的方法是什么?
所有{ extern | input | sinput }
声明都应该在 MQL4 代码顶部附近的某个位置,具有有效范围的文件级别。
将相同的extern
声明放在文件的底部仍然可以工作,编译器知道正确的范围(因为它的设计还必须小心处理所有潜在的变量名(s)屏蔽/取消屏蔽( s) 如果在某些调用接口声明或“内部”某个更深的嵌入式代码块中也使用了相同的名称)。
这种非正统的做法应该被认为是相当不人道的,因为我们还努力为人类理解我们设计的代码单元创建一个良好的做法,而不管编译器处理尾部定义的能力是否相同它对头部定义的方式,对吧?

除了属于某个有效范围(在相关范围内)的变量定义的琐碎性之外{ code-block }
,还有一些主要的含义,适用于extern
和input
MQL4sinput
特定的声明修饰符。
//+------------------------------------------------------------------+
//| StackOverflow__test_EA_extern.mq4 |
//| Copyright © 1987-2017 [MS] |
//| nowhere.no |
//+------------------------------------------------------------------+
#property copyright "Copyright © 1987-2017 [MS]"
#property link "nowhere.no"
#property version "1.00"
#property strict // New-MQL4.56789 <--- this CHANGES SOME RUN-TIME FEATURES OF THE SAME SOURCE-CODE (!!!)
//--- extern parameters --- MQL4 declared <extern>-variables have at least DUAL-INTERFACE ROLE
extern double ama_red; // _RED /*| (1) is a LIVE, knowingly bidirectional INTERFACE */
extern double ama_blue; // _BLUE /*| between a code-execution ecosystem */
extern double ama_purple; // _PURPLE /*| & MT4 GUI user-interactions */
// ^ (2) is an ITERATOR, unidirectional INTERFACE ROLE
// ^ from MetaTrader Terminal 4 [StrategyTester]
// ^ into MetaTrader Terminal 4 Optimisation Tool
// ^
// comment^-strings are DISPLAYED in GUI dialogue boxes ( on #property strict // mode )
// + each user-interaction, done via GUI, RESETs the STATE of the so far running EA (!!!)
// + variables are always RE-INITIALISED immediately before the OnInit() is called
// ^^^^^^^^^^^^^^^^^^^^^
//
// - Arrays[] and variables of complex types can't act as <extern>-variables.
/*
//--- input parameters --- New-MQL4.56789 Build 1065+ EA-templates started to be proposed as <input>-based
input double ama_red; // can never be assigned a value to <input>-defined variables
input double ama_blue; // can never be used for a man-machine user-interaction
input double ama_purple; //
*/
#property show_inputs
int aTracePointNUMBER(){ static int aTracePointORDINAL = EMPTY; return( ++aTracePointORDINAL ); }
void aTracePointREPORT( const string aTracePointCALLER,
const double aTracePointDOUBLE_VALUE,
const string aTracePointDOUBLE_NAME
){
PrintFormat( "[%d] In(%s): <_%s_> == %f", // PrintFormat( "[%d] In(%s): <_%s_> == %f",
aTracePointNUMBER(), // aTracePointNUMBER(),
aTracePointCALLER, // __FUNCTION__,
aTracePointDOUBLE_NAME, // "ama_red"
aTracePointDOUBLE_VALUE // ama_red
); // );
}
/*
#include MQL4_Project_common_HEADERS_FILE.mqh // may help with #define-s, but not that much with { extern | input | sinput }-s in MQL4
*/
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
aTracePointREPORT( __FUNCTION__, ama_red, "ama_red" );
ama_red = iMA( NULL, 0, 6, 0, MODE_EMA, PRICE_CLOSE, 0 );
aTracePointREPORT( __FUNCTION__, ama_red, "ama_red" );
ama_red = EMPTY;
aTracePointREPORT( __FUNCTION__, ama_red, "ama_red" );
return( INIT_SUCCEEDED ); }
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit( const int reason ) {
// aTracePointREPORT( __FUNCTION__, ama_red, "ama_red" );
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// uponEntry: // EACH TIME anExternalFxEventSTREAM QUOTE.ARRIVAL
aTracePointREPORT( __FUNCTION__, ama_red, "ama_red" );
// ... EA code ...
ama_red = iMA( NULL, 0, 6, 0, MODE_EMA, PRICE_CLOSE, 0 );
// ...
}
//+------------------------------------------------------------------+
/*
2017.04.15 14:40:45.030 2013.01.01 00:00:00 StackOverflow__test_EA_extern inputs: ama_red=-123456789; ama_blue=-987654321; ama_purple=918273645;
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [0] In(OnInit): <_ama_red_> == -123456789.000000
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [1] In(OnInit): <_ama_red_> == 1608.298571
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [2] In(OnInit): <_ama_red_> == -1.000000
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [3] In(OnTick): <_ama_red_> == -1.000000
2017.04.15 14:43:14.764 2013.03.21 13:20:02 StackOverflow__test_EA_extern XAUUSD,M1: [4] In(OnTick): <_ama_red_> == 1608.298571
2017.04.15 14:43:16.827 2013.03.21 13:20:05 StackOverflow__test_EA_extern XAUUSD,M1: [5] In(OnTick): <_ama_red_> == 1608.296000
2017.04.15 14:43:18.889 2013.03.21 13:20:07 StackOverflow__test_EA_extern XAUUSD,M1: [6] In(OnTick): <_ama_red_> == 1608.293428
2017.04.15 14:43:20.952 2013.03.21 13:20:10 StackOverflow__test_EA_extern XAUUSD,M1: [7] In(OnTick): <_ama_red_> == 1608.295142
2017.04.15 14:43:23.014 2013.03.21 13:20:12 StackOverflow__test_EA_extern XAUUSD,M1: [8] In(OnTick): <_ama_red_> == 1608.296857
2017.04.15 14:43:25.077 2013.03.21 13:20:15 StackOverflow__test_EA_extern XAUUSD,M1: [9] In(OnTick): <_ama_red_> == 1608.293428
*/
通过跟踪这个微不足道的代码,您可能会意识到一些事实:
- 虽然由于明显的编译时原因,不能
ema_red
声明一个分配给非(编译时)常量初始化的 et al,但仍然有一种方法可以实现这样的目标,并且可以为此使用强制调用到OnInit(){...}
事件处理程序代码块,以将这样的非常量值提供给预期的extern
变量。
列出了来自这种构造的EAextern
的跟踪报告,显示了在代码执行到达事件触发处理程序之前和之后声明的输入的每次更改(不再使用OnTick(){...}
原始处理程序,但历史上仍然在 MQL4 代码中存在很多 -start()
根据 ):
2017.04.15 14:40:45.030 2013.01.01 00:00:00 StackOverflow__test_EA_extern inputs: ama_red=-123456789; ama_blue=-987654321; ama_purple=918273645;
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [0] In(OnInit): <_ama_red_> == -123456789.000000
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [1] In(OnInit): <_ama_red_> == 1608.298571
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [2] In(OnInit): <_ama_red_> == -1.000000
2017.04.15 14:40:45.030 2013.03.21 13:20:00 StackOverflow__test_EA_extern XAUUSD,M1: [3] In(OnTick): <_ama_red_> == -1.000000
2017.04.15 14:43:14.764 2013.03.21 13:20:02 StackOverflow__test_EA_extern XAUUSD,M1: [4] In(OnTick): <_ama_red_> == 1608.298571
2017.04.15 14:43:16.827 2013.03.21 13:20:05 StackOverflow__test_EA_extern XAUUSD,M1: [5] In(OnTick): <_ama_red_> == 1608.296000
2017.04.15 14:43:18.889 2013.03.21 13:20:07 StackOverflow__test_EA_extern XAUUSD,M1: [6] In(OnTick): <_ama_red_> == 1608.293428
2017.04.15 14:43:20.952 2013.03.21 13:20:10 StackOverflow__test_EA_extern XAUUSD,M1: [7] In(OnTick): <_ama_red_> == 1608.295142
2017.04.15 14:43:23.014 2013.03.21 13:20:12 StackOverflow__test_EA_extern XAUUSD,M1: [8] In(OnTick): <_ama_red_> == 1608.296857
2017.04.15 14:43:25.077 2013.03.21 13:20:15 StackOverflow__test_EA_extern XAUUSD,M1: [9] In(OnTick): <_ama_red_> == 1608.293428
当心,extern
是一个双向接口(!!!)
鉴于上述情况,如果用户使用 GUI 将设置 extern 修改为新值,则当前实时运行的“EA 交易”的代码执行将重置为新的初始化值。这可能会在分布式系统的处理中引起很多问题,并且应该注意将这种“不可见”的重置传播到正确处理返回方格 [1]。

实时市场会话 EA 代码执行重置的影响确实可能是灾难性的,因此请务必小心,您的代码是否被设计为对此类意外事件具有鲁棒性,从而导致Deus Ex Machina神秘的行为变化,非常类似于来自晴朗蓝天的突然雷声。
如果人们没有预料到这种习惯,那么系统日志中的隐藏评论通常不足以让人们了解实时会话发生了什么以及此类事件触发了哪些额外的副作用。

结语:
在掌握了微不足道extern
的同时它也是复杂设置的外部迭代器替代方案,用于 [策略测试器] 优化器(无论是完全正交的蛮力还是有点神奇地标记为遗传模式的),完全双-变量的定向接口角色是extern
MQL4 量化建模期间人机交互的一个非常强大的工具。