文章 "在MQL5程序中使用断言" - 页 3

 
解释。在撰写这篇文章时,MQL5 没有让程序执行紧急停止的机制。作为替代方案,runtime error 被触发,这保证了程序崩溃。
事实并非如此。一个 EA 可以通过 ExpertRemove() 停止,一个指标可以通过 ChartIndicatorDelete() 停止,这对脚本来说微不足道。
 
Alain Verleyen:
事实并非如此。一个 EA 可以通过 ExpertRemove() 停止,一个指标可以通过 ChartIndicatorDelete() 停止,这对脚本来说微不足道。

请举例说明,如何在代码中使用 ExpertRemove() 退出。

例如,我们有这样一段代码:

#property version   "1.00"
#property strict

int OnInit()
  {
   for(int i = 0; i < 100; i++)
   {
      if(i == 2)
      {
         ExpertRemove();
      }
      Print(i);
   }
      
//---
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {

      
  }

void OnTick()
  {
//---
   
  }

我们需要在 i == 2 的情况下退出,其他步骤必须停止运行。在日志中,我们必须只看到 "0 "和 "1"。如何使用该函数 实现这一目标?

现在,ExpertRemove() 不会在需要的时候停止 EA,所有步骤都将运行,之后 EA 将停止。但这对于断言机制来说是错误的,我们必须立即停止 EA。是的,我们不能只使用 "break",因为我们需要通用宏或函数来处理任何 EA 的任何部分。


关于指标--请向我展示定义指标短名的通用机制。因为如果没有这种机制,我们就无法在断言中使用该函数。是的,我们可以在我们的具体指标中定义 ShortName(例如使用全局变量,很多人都这么做,尽管这是很糟糕的做法),但我们没有通用函数 "GetShortName()"。因此,我们无法用 ChartIndicatorDelete() 制作通用机制(我指的是适用于所有指标的宏或函数,只需添加一行 "assert(...) "即可)。


请向我展示用于任何代码部分的脚本的 "琐碎 "变体。脚本的任何部分都必须是一个(!)函数或宏:

1) 对于 cicles
2) 对于任何返回类型的函数
3) 对于无返回类型(void)的函数。

因此,我们必须在脚本的任何部分添加一行 "assert(...)",就像这样:

#property version   "1.00"
#property strict

void OnStart()
  {
   assert(...);

  }

double SomeDouble()
  {
   assert(...);
   return 0.0;
  }

color SomeColor()
  {
   assert(...);
   return clrNONE;
  }

string SomeString()
  {
   assert(...);
   return "";
  }

void SomeVoid()
  {
   assert(...);
   return;
  }

void SomeCicle()
  {
   while(!IsStopped())
     {
      assert(...);
     }
  }

附注:抱歉我的英语不好。

 

或其他使用 ExpertRemove() 的 EA 示例,而不是 cicle :)

例如,如果交易量大于我们的需求,我们必须 停止应用程序(这只是一个例子,在实际情况中,我们应该以不同的方式处理这种情况):

#property version   "1.00"
#property strict

int OnInit()
  {
   OpenTrade();
//---
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {

      
  }

void OnTick()
  {
//---
   
  }
bool OpenTrade()
{
   double volume = GetVolume();
   
   if(volume > 1)
   {
      Print("Volume > 1, stop EA!");
      ExpertRemove();
   }
   
   Print("Opening position ...");
   
   return true;
}

double GetVolume()
{
   return 999.0;
}

我们必须 在代码需要的地方瞬间停止 EA(这是断言 的意思)。但 ExpertRemove() 在这种情况下不是正确的变体,我们有:

2015.12.06 10:53:22.253 Test EURUSD,H1: Volume > 1, stop EA!<br/ translate="no">2015.12.06 10:53:22.253 Test EURUSD,H1: ExpertRemove function called
2015.12.06 10:53:22.253 Test EURUSD,H1: Opening position ...


因此,请告诉我如何使用ExpertRemove() 函数(不带 return、break 等,必须通用于代码的任何部分)来处理这个顶点。

 
Sergey Eremin:

请举例说明,如何在 cicle 中使用 ExpertRemove() 退出。

例如,我们有这样一段代码:

我们需要在 i == 2 的情况下退出,而所有其他步骤都必须停止运行。在日志中,我们必须只看到 "0 "和 "1"。如何使用该函数实现这一目标?

现在,ExpertRemove() 不会在需要的时候停止 EA,所有步骤都将运行,之后 EA 将停止。但这对于断言机制来说是错误的,我们必须立即停止 EA。是的,我们不能只使用 "break",因为我们需要通用宏或函数来处理任何 EA 的任何部分。

您不必在 OnInit() 中使用ExpertRemove(),只需使用 return(INIT_FAILED);

int OnInit()
  {
//---
    ...

         if(somethign wrong)
           {
            //ExpertRemove(); 
            return(INIT_FAILED);    //--- 无需在 OnInit() 中使用 ExpertRemove()
           }
    ...
  }

在代码的其他部分,只需返回 :

            ExpertRemove();
            return;           //--- 只需返回即可完成当前事件处理程序

or

            ExpertRemove();
            return(x);        //--- 只需返回即可完成当前事件处理程序

关于指标 - 请向我展示定义指标 ShortName 的通用机制。因为如果没有这种机制,我们就无法将该函数用于断言。是的,我们可以在我们的具体指标中定义 ShortName(例如使用全局变量,很多人都这么做,尽管这是个坏习惯),但我们没有通用函数 "GetShortName()"。因此,我们无法用 ChartIndicatorDelete() 制作通用机制(我指的是适用于所有指标的宏或函数,只需添加一行 "assert(...) "即可)。

问题出在哪里?你正在处理你的指标,这是你的代码,所以你知道它的简短名称。

我发帖是想说,你说没有办法立即终止程序是不对的。你应该为你的断言项目找到解决方案。

在指示器中使用全局变量绝对不是一个坏习惯。当然,如果你想用 "这是不好的做法 "这样的断言来创造自己的新限制,你会发现很多不可能的事情。

请向我展示脚本中任何代码部分的 "琐碎 "变体。脚本的任何部分都必须是一个(!)函数或宏:

1) 对于 cicles
2) 对于任何返回类型的函数
3) 对于无返回类型(void)的函数。

因此,我们必须在脚本的任何部分添加一行 "assert(...)",就像这样:

与 EA 相同。

附加的文件:
 
Alain Verleyen:

我发帖是想说,你说没有办法立即终止程序是不对的。你应该为你的 Assertion 项目找到解决方案。

在指标中使用全局变量绝对不是一个坏习惯。当然,如果你想用 "这是不好的做法 "这样的断言来创建自己的新限制,你会发现很多不可能的事情。

好的,我明白了。谢谢,你说得对。

但在我的文章中,我指的是断言的解决方案:在代码的任何地方(包括 OnInit 和 cicles)停止 MQL4/5 应用程序的通用 机制。只需在任何 部分添加一行 即可完成。就像在许多编程语言中的任何断言机制中一样;)

是的,你的变体是正确的。但不适合我对断言 的理解,因为它不是针对任何 代码的任何部分 的通用解决方案。

谢谢你的 EA 例子。

 
Sergey Eremin:

好的,我明白了。谢谢,你说得对。

但在我的文章中,我指的是断言的解决方案:在代码的任何地方(包括 OnInit 和 cicles)停止 MQL4/5 应用程序的通用 机制。只需在任何 部分添加一行 即可完成。就像在许多编程语言中的任何断言机制中一样;)

是的,你的变体是正确的。但不适合我对断言 的理解,因为它不是针对任何 代码的任何部分 的通用解决方案。

谢谢你的 EA 例子。

我知道你想做什么,而且完全可以做到,你只需根据我提供的代码进行归纳即可。

通过分析宏中的调用上下文,检测它是 EA 还是指标,并解析__FUNCSIG__。

能否将其变成一种通用机制取决于您。

 
Alain Verleyen:

我知道你想做什么,而且完全可以做到,你只需根据我提供的代码进行归纳。

通过分析宏中的调用上下文,检测它是 EA 还是指标,并解析 __FUNCSIG__。

能否将其变成一种通用机制取决于您。

是的,起初我也考虑过这样的问题,但最终我做到了我们在文章中看到的那样:)

感谢您的评论!

 

如果有人要使用这段代码,请记住这一点:下面的脚本

   if(true)
      assert(1==1, "")
   else
      Print("Never executed");

会导致 else 分支出现 "从未执行 "的信息。

为了能正确使用assert,您应该对其进行修正,例如,以这种形式:

#define  assert(condition, message) \
       do if(!(condition)) \
        { \
         string fullMessage= \
                            #condition+", " \
                            +__FILE__+", " \
                            +__FUNCSIG__+", " \
                            +"line: "+(string)__LINE__ \
                            +(message=="" ? "" : ", "+message); \
         \
         Alert("Assertion failed! "+fullMessage); \
         double x[]; \
         ArrayResize(x, 0); \
         x[1] = 0.0; \
        } while(false)
#else
#define  assert(condition, message) 
#endif

(else分支中的宏也已更正:它返回空字符串(而不是";")。

在此变体中,应在 assert(...) 后面加上";")。