我在哪里放置 MQL4 语言的外部变量?

Where do I place external variables in MQL4 language?

我是编程新手,无法弄清楚为什么代码无法编译以及如何编译。

这是 MetaTrader Terminal 4 中的简单 EA。

我觉得问题出在位置上,我声明和初始化变量的地方,我试着把它们放在不同的函数下(在代码中用注释表示),但代码仍然无法编译,代码附上。任何帮助将不胜感激。

#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

extern double ema_red    = iMA( NULL, 0,  6, 0, MODE_EMA, PRICE_CLOSE, 0 );
extern double ema_purple = iMA( NULL, 0, 30, 0, MODE_EMA, PRICE_CLOSE, 0 );
extern double ema_blue   = iMA( NULL, 0,  8, 1, MODE_EMA, PRICE_CLOSE, 0 );

// int point;
/*
void start()
{
  double ema_red    = iMA( NULL, 0,  6, 0, MODE_EMA, PRICE_CLOSE, 0 );
  double ema_purple = iMA( NULL, 0, 30, 0, MODE_EMA, PRICE_CLOSE, 0 );
  double ema_blue   = iMA( NULL, 0,  8, 1, MODE_EMA, PRICE_CLOSE, 0 );
  return;
 }
*/
void OnTick()
{
 // double ema_red    = iMA( NULL, 0,  6, 0, MODE_EMA, PRICE_CLOSE, 0 );
 // double ema_purple = iMA( NULL, 0, 30, 0, MODE_EMA, PRICE_CLOSE, 0 );
 // double ema_blue   = iMA( NULL, 0,  8, 1, MODE_EMA, PRICE_CLOSE, 0 );
 if (OrdersTotal()<=21)
   {   
      if (ema_red == ema_purple)&&(ema_red > ema_blue) // check when the ea's cross/meet
        Buy_Order();
      if (ema_red == ema_purple)&&(ema_red < ema_blue) // check when the ea's cross/meet
        Sell_Order();                                
   }
  }
void Buy_Order()
{ 
         double TP = Ask +(PipsToPointFactor()*15);
         double SL = (MarketInfo(Symbol(),MODE_TICKVALUE)) - (PipsToPointFactor()*5);
         OrderSend(Symbol(),OP_BUY,0.6,Ask,(3*PipsToPointFactor()),SL,TP,"",0,0,Green);  
  }
void Sell_Order()
{  
         double TP = (Bid - (15*PipsToPointFactor()));
         double SL = ((MarketInfo(Symbol(),MODE_TICKVALUE)) + (PipsToPointFactor()*5 );
         OrderSend(Symbol(),OP_SELL,0.6,Bid,(3*PipsToPointFactor()),SL,TP,"",0,0,Red); 
  }
int OnInit()
{
    return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
{  
  }
int PipsToPointFactor()              // NOT MY OWN FUNCTION, takes care of pips to points issue
{
   int point;
   if(Digits==5 || Digits==3)        // Check whether it's a 5 digit broker ( 3 digits for Yen )
   point=10;                         // 1 pip to 10 point if 5 digit
   else if(Digits==4 || Digits==2)
   point=1;                          // 1 pip to 1 point if 4 digit
   return(point);
  }

您将一些变量声明为“extern”:

extern double ema_red    = iMA(NULL, 0,  6, 0, MODE_EMA, PRICE_CLOSE, 0);
extern double ema_purple = iMA(NULL, 0, 30, 0, MODE_EMA, PRICE_CLOSE, 0);
extern double ema_blue   = iMA(NULL, 0,  8, 1, MODE_EMA, PRICE_CLOSE, 0);

如果算上函数 start(),您在函数内部使用它们,在多个函数内部使用。因此,至少需要在文件范围内定义它们。看来你没地方定义它们。

定义它们,除了声明它们还是仅仅定义它们:

/* extern */ double ema_red =    iMA(NULL, 0,  6, 0, MODE_EMA, PRICE_CLOSE, 0);
/* extern */ double ema_purple = iMA(NULL, 0, 30, 0, MODE_EMA, PRICE_CLOSE, 0);
/* extern */ double ema_blue =   iMA(NULL, 0,  8, 1, MODE_EMA, PRICE_CLOSE, 0);

所有代码文件(那些包含访问这些变量的函数的文件)都需要 "see" 声明,即带有“extern”的行。如果您有多个这样的代码文件,则该声明应该在 header.
中 然后只有一个代码文件必须进行定义,即没有“extern”的行。那就是所谓的"global variables"。

如果您只有一个这样的代码文件,但还有其他几个,并且想确保无法从其他任何地方访问变量(这是一种干净编码和 "safety" 的功能),那么您不要使用a header 并将可见性限制为执行定义的一个代码文件。您可以通过使用关键字“static”来做到这一点,这正是您现在拥有“extern”的地方。有时称为 "file scope variables".

正如另一个答案所说,在定义时初始化只能使用静态值。 如果你想在运行时重新初始化,也许使用特定于用例的值,你的函数“start()”恰好是这样做的方法。您只需将定义行更改为正常的写访问。然后需要调用该函数来更改用例。

注:
这个答案仅指 C,并且比对问题的编辑更早,这使得 MT4 范围更加突出并删除了 C 标签。
因此,如果您的需求与 MT4 密切相关,请务必小心。
由于包括 OP 在内的某些人认为答案有用,因此在提供良好的 MT4 答案之前我不会删除。

这个问题最初被标记为 C,所以这就是这个答案所要解决的问题。

一个紧迫的问题 - 在文件范围内声明的对象(在任何函数的主体之外),如

extern double ema_red = iMA(NULL, 0, 6, 0, MODE_EMA, PRICE_CLOSE, 0);
extern double ema_purple = iMA(NULL, 0, 30, 0, MODE_EMA, PRICE_CLOSE, 0);
extern double ema_blue = iMA(NULL, 0, 8, 1, MODE_EMA, PRICE_CLOSE, 0);

只能用常量表达式初始化(可以在编译时求值的东西)。如果 iMA 是一个函数调用(或者是一个扩展为除常量表达式以外的东西的宏),这将导致编译器出错。

而且,这里不需要 extern

虽然语法乍一看
有点类似于 C,
MQL4 语言是另一种风格,
它存在于一个相当特定的生态系统
具有许多无与伦比的双刃剑功能。

TL;DR;至少,你已经被警告过了。

自原始 MQL4 语言的早期状态以来,有一些重要的概念,远远超出了 C 的经典。

MQL4 代码的单位(可以是任何 { EA: Expert Advisor | CI: 自定义指标 | Script: Script } ) 在代码执行生态系统的几种不同模式下执行,或者:

  • 已 "put on" 成为 图表 ,即在实时市场时间或周末
  • 已经"setup in"在终端
  • 的[Strategy Tester]回测设施中处于琐碎模式
  • 已经"setup in"复杂[策略测试器]中优化模块的模式

虽然这对于硬核 MetaTrader 量化建模者 来说似乎是显而易见的,但人们也可能同意这是 O/P 上下文的隐藏部分,仅可读从解码有点神秘的第二句 ( cit. orig. ) :

"just a simple EA in MT4".


那么,使用外部变量的 MQL4 方法有哪些?

所有 { extern | input | sinput } 声明都应该位于 MQL4 代码顶部附近的某个位置,具有文件级别的有效性范围。

将相同的 extern 声明放在文件底部仍然有效,编译器知道适当的范围(因为它的设计也必须仔细处理所有潜在的变量名(s ) masking(s) / un-masking(s) 以防在某些调用接口声明或某处"inside" 一些更深的嵌入式代码块中也使用了相同的名称)。

这种非正统的做法应该被认为是相当不人道的,因为我们还努力为我们设计的代码单元创造一种良好的做法,无论编译器处理尾部的能力如何-定义与头部定义的方式完全相同,对吧?

除了属于某个有效范围(在相关 { code-block } 范围内)的变量定义的琐碎之外,还有一些对 externinputsinput MQL4 特定声明修饰符。

//+------------------------------------------------------------------+
//|                                Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__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  Whosebug__test_EA_extern XAUUSD,M1: [9] In(OnTick): <_ama_red_> == 1608.293428

*/

通过跟踪这段微不足道的代码,您可能会发现一些事实:

  • 虽然 不能 ,但出于明显的编译时原因,声明一个 ema_red 等并分配给一个非(编译时)常量初始化,仍然是一种实现此类目标的方法,为此可以强制调用OnInit(){...} 事件处理程序代码块,为预期的 extern 变量提供这样一个非常量值。

列出了来自此类构造的 EA 的跟踪报告,显示了 extern 声明的输入的每个更改,之前在代码执行到达事件触发的 OnTick(){...} 处理程序后(不再使用原始 start() 处理程序,但历史上在 MQL4 代码中仍然存在很多 -基地):

2017.04.15 14:40:45.030 2013.01.01 00:00:00 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__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 Whosebug__test_EA_extern XAUUSD,M1: [9] In(OnTick): <_ama_red_> == 1608.293428

注意,extern 是一个双向接口 (!!!)

鉴于上述情况,在用户使用 GUI 将外部设置修改为新值的情况下,当前实时 运行 EA 交易程序的代码执行将重置为新的初始化值。这可能会在分布式系统的处理中引起很多问题,并且应该适当注意传播这样的 "invisible" 重置以正确处理返回到 square [ 1 ].

实时市场会话 Expert Advisor 代码执行重置的影响确实可能是灾难性的,因此请始终小心,您的代码是否被设计为对此类意外事件具有鲁棒性,从而导致 Deus Ex Machina 行为的神秘变化,非常类似于晴朗的蓝天突然打雷。

如果一个人没有预料到这样的习惯,系统日志中的隐藏评论通常不足以让人意识到实时会话发生了什么以及此类事件触发了什么级联的额外副作用。


结语:

在掌握了琐碎的 extern 以及复杂设置的外部迭代器替代方案后,在 [Strategy Tester] 优化器中使用(无论是完全- 正交暴力或有点神奇地标记为遗传模式 ), extern 变量的完全双向接口角色是 MQL4 期间人机交互的非常强大的工具量化建模。