【问题标题】:How to access array with boolean operation inside iteration in MQL4?如何在 MQL4 的迭代中使用布尔运算访问数组?
【发布时间】:2015-11-03 05:39:44
【问题描述】:

我能够获得从 Shift 1 到 Shift n 的移动平均线的值(n = 柱的数量),并每 5 分钟柱显示一次警报值,但是当我添加了 'if (Direction == " Up")' 以此类推,代码仅显示最后一个移位值并点击'break'。最重要的是,我不能将它们用于布尔运算。

EMA 的值有序上升时,我希望代码显示Alert(),反之亦然(对于“趋势下降”)。每当它们的一个值发生变化(一个或多个柱的值高于或低于其他柱)时,它就是 "无趋势"

假设TrendBar 的数量超过 5 条; [] 数组是 Bar Shift。

“趋势向上”的算法是:

如果慢[n]

否则为假

int TrendBar    = 5,
    SlowPeriod  = 14;

void OnTick()
{
    if (NewBar(PERIOD_M5) == true) 
    {
        if (MA("Up", PERIOD_M5) == true) Alert ("Trend Up good");
        else if (MA("Up", PERIOD_M5) == false) Alert ("Trend Up bias");
        else Alert ("No Trend");
    }
}

bool MA(string Direction, int TF)
{
    double Slow[];
    ArrayResize(Slow, TrendMinDurationBar + 1);

    for (int i = TrendBar; i > 1; i--)
        {
            Slow[i] = NormalizeDouble(iMA(Symbol(), TF, SlowPeriod, 0, MODE_EMA, PRICE_OPEN, i), Digits);
            Alert("DataSlow" + (string)i + ": " + DoubleToStr(Slow[i], Digits));
            if (Direction == "Up")
            {
                if (Slow[i] <= Slow[i-1]) return(true);
                else if (Slow[i] > Slow[i-1]) {return(false); break;}
            }
        }
    return(false);
}

bool NewBar(int TF)
{
    static datetime lastbar = 0;
    datetime curbar = iTime(Symbol(), TF, 0);

    if (lastbar != curbar)
        {
            lastbar = curbar; 
            return(true);
        }
    else return(false);
}

当我运行代码时,它只显示Alert( "Trend Up bias" )。这意味着当迭代开始时代码总是点击'break'。不关心趋势是否真的在上升(Slow[] 数组中的所有 MA 值都是有序上升的)。

Q1:如何让代码工作?

Q2:如何编写正确的代码以在迭代中使用布尔运算访问数组?

Q3:请问有什么解决办法?

【问题讨论】:

    标签: quantitative-finance algorithmic-trading mql4 metatrader4 forex


    【解决方案1】:

    总结:

    Q1:如何让代码工作?

    A1:重写迭代for-loop,以免在第一个循环中立即退出
    (参考下图所示的迭代流程/障碍)

    Q2:如何编写正确的代码以在迭代中使用布尔运算访问数组?

    A2:完全没有这个问题。如果可能,请始终避免在分配某个值之前测试数组值
    ( 参考下面的陷阱 )

    Q3:请问有什么解决办法?

    A3:修复格式不正确的for-loop + 在将其值用于进一步处理或比较之前,始终将有意义的值分配给变量。


    算法如何处理特征的明确部分:

    //+------------------------------------------------------------------+
    //|                                                      MQL4 strict |
    //+------------------------------------------------------------------+ 
    #property strict              // MQL4 compilation mode { strict }
    
    //+------------------------------------------------------------------+
    //|                                                   a global-scope |
    //+------------------------------------------------------------------+
    bool     aTrendUpGTprev[],    // MQL4 dynamic array
             aTrendDnLTprev[];    // MQL4 dynamic array
    
    int      TrendBar    =  5,
             SlowPeriod  = 14;
    
    void     OnInit()
    {        ArraySetAsSeries( aTrendDnLTprev, True );  // MQL4 Reference / Array Functions / ArraySetAsSeries 
             ArraySetAsSeries( aTrendUpGTprev, True );
    }
    
    bool     isNewBar( const int TF = PERIOD_CURRENT )
    {        
             static datetime lastBar = EMPTY;
                    datetime currBar = iTime( _Symbol, TF, 0 );
    
             if (    lastBar != currBar )               // .TEST
             {       lastBar  = currBar;                // .UPD
                     updateMA( TF );                    // .UPD
                     return( true );                    // .RET .T.
             }
             return( false );                           // .RET .F.
    }
    
    void     updateMA( const int TF = PERIOD_CURRENT )
    {
             static bool    isFirstCall = True;
             static double  SlowMA_0,
                            SlowMA_1;
    
             if (  isFirstCall )                    // .TEST
             {     isFirstCall = False;             // .SET / LOCK FOREVER
                // --------------------------------------------------------------------------------------------------------
                // INITIAL PRE-FILL FOR ANY-DEPTH TREND-CALCULUS
                // SHUFFLE-LOGIC LATCH-MOV PRINCIPALLY AVOIDS ANY-DEPTH RE-CALCULATION(S) - COMPUTATIONALLY EFFICIENT
    
                   SlowMA_0 = NormalizeDouble( iMA( _Symbol,
                                                    TF,
                                                    SlowPeriod,
                                                    0,
                                                    MODE_EMA,
                                                    PRICE_OPEN, // OPEN ?
                                                    TrendBar
                                                    ),
                                               Digits           // no need to Normalize here, as the values do not enter any XTO
                                               );
                   for ( int iii = TrendBar - 1; iii > 0, iii-- )
                   {     SlowMA_1 = SlowMA_0;
                         SlowMA_0 = SlowMA_0 = NormalizeDouble( iMA( _Symbol, TF, SlowPeriod, 0, MODE_EMA, PRICE_OPEN, iii ), Digits ); // no need to Normalize here, as the values do not enter any XTO
                         aTrendUpGTprev[iii] = (  SlowMA_0 >= SlowMA_1 );   // bi-state { True | False }
                         aTrendDnLTprev[iii] = (  SlowMA_0 <= SlowMA_1 );   // bi-state { True | False }
                   }
             }
    
          // -------------------------------------------------------------------------------------------------------------
          // SHUFFLE-LOGIC LATCH-MOV PRINCIPALLY AVOIDS ANY-DEPTH RE-CALCULATION(S)  - COMPUTATIONALLY EFFICIENT
          // PROTECTED FROM DESYNC/ARTIFACTS FROM RE-ENTRY(-IES) WITHIN THE SAME BAR - SAFE-MODE
    
             static datetime lastBar = EMPTY;
                    datetime currBar = iTime( _Symbol, TF, 0 );
    
             if (    lastBar != currBar )              // .TEST
             {       lastBar  = currBar;               // .UPD
                     SlowMA_1 = SlowMA_0;              // .MOV [1] << [0]
                     SlowMA_0 = SlowMA_0 = NormalizeDouble( iMA( _Symbol, TF, SlowPeriod, 0, MODE_EMA, PRICE_OPEN, 0 ), Digits ); // .NEW [0]
                     aTrendUpGTprev[0] = (  SlowMA_0 >= SlowMA_1 );         // bi-state { True | False }
                     aTrendDnLTprev[0] = (  SlowMA_0 <= SlowMA_1 );         // bi-state { True | False }
             }
    
          // -------------------------------------------------------------------------------------------------------------
          // MQL4 ( "new" MQL4 ) requirement to return even from a void fun() >>> MQL4 Reference / Updated MQL4
             return( NULL );
    }
    
    void     OnTick()
    {
             if (  isNewBar( PERIOD_M5 ) )              // returns bool value per-se
             {  
                // if       (   MA( "Up", PERIOD_M5 ) ) Alert ( "Trend Up good" );   // Either this
                // else if  (  !MA( "Up", PERIOD_M5 ) ) Alert ( "Trend Up bias" );   // or this.
                // else                                 Alert ( "No Trend" );        // This is an un-reachable state within above defined logic
                // ----------------------------------------------------------------- // --------------------------------------------------------
                                                        // There is no principal chance
                                                        // to get a tri-state logic
                                                        // under one boolean var
    
                   bool  isUP = aTrendUpGTprev[TrendBar];
                   bool  isDN = aTrendDnLTprev[TrendBar];
    
                   for ( int iii = TrendBar - 1; iii > 0; iii-- )
                   {
                         isUP &= aTrendUpGTprev[iii];
                         isDN &= aTrendDnLTprev[iii];
                   }
                   if (  isUP )  Alert ( "Trend Up good" );  // if Slow[n] <= Slow[...] <= Slow[3] <= Slow[2] <= Slow[1] then true
                   if (  isDN )  Alert ( "Trend Dn good" );
    
             }
    }
    

    问题不是从 for 循环内部访问数组 cell[i]

    如上所述,您的代码原样不符合您的目标。

    bool MA( const string Direction, const int TF )
    {
         double       Slow[];
         ArrayResize( Slow, TrendMinDurationBar + 1 );
    
         for ( int  i  = TrendBar; i > 1; i-- )
         {     Slow[i] = NormalizeDouble( iMA( _Symbol, TF, SlowPeriod, 0, MODE_EMA, PRICE_OPEN, i ),
                                          Digits
                                          );
            // Alert( "DataSlow" + (string)i + ": " + DoubleToStr( Slow[i], Digits ) );
    
               if (  Direction == "Up" )
               {
                     if      ( Slow[i] <= Slow[i-1] ) return( true  );
                     else if ( Slow[i] >  Slow[i-1] ) return( false );
               }
        }
        return( false );
    }
    

    它开始在 bool MA() 中迭代 i-range ( 5, 4, 3, 2 )
    并测试一系列比较:
    仅在 "Up"-case 中:
    [5]&lt;=[4] |-&gt; RET .T., _____________ 要么​​这个
    [5]&gt; [4] |-&gt; RET .F., _____________ 或这 & 必须是 RET {.T. | .F.}的原因
    。 . . . . . . . . . . . . . . . . . . . . . _ _ _ _ _ _ _ _ _ 代码从不超过这个
    [4]&lt;=[3] |-&gt; RET .T.,
    [4]&gt; [3] |-&gt; RET .F.,
    [3]&lt;=[2] |-&gt; RET .T.,
    [3]&gt; [2] |-&gt; RET .F.

    您可能已经注意到,MQL4 中的动态 数组没有已知的初始化值,ArrayResize() 之后越多。

    这使得条件{ [5]&lt;=[4] | [5]&gt; [4] } 很容易受到您无法控制的问题的影响,因为您的代码已将值分配给Slow[5],但没有 分配给[4],然后就可以了。

    动态数组内存分配/调整大小彩票副作用暴露您的代码为一个主要不可控的值,在两个比较{ [5]&lt;=[4] | [5]&gt; [4] } 中访问[4],这原则上除了iMA(...) 之外的其他任何东西。

    由于您的观察表明 [4] 低于已分配给 [5]iMA() 值,您有点幸运未初始化内存的随机性(包含不可控残留二进制值)包含没有其他方式,只是偶然一些残留位图,很高兴地被解释为IEEE-float32数字,低于单元格@中比较计算和存储的iMA()值987654350@与。


    更新:

    如果我要实现这个想法,我会怎么做?

    MQL4 域中经历了数百人*年之后,Technical Indicators 教会我们宁愿花一些时间将计算成本高昂的部分与算法的廉价部分分开,并将设计调整集中在更昂贵的部分上。

    所以:

    而是考虑避免浪费重新计算已经计算过的值 static double Slow[] 将允许您保存在 NewBar() 事件上计算过的值,或者使用相同的想法向前一步来保存而不是“尾部”的Slow[5..2],并在决定[0] 时重新比较它们,但生成和重复使用的不是iMA() 4B 值,而是它们已经进行的成对比较,这仅决定实际返回值:

    static bool aTrendUpPrevGT[];
    static bool aTrendDnPrevLT[];
    这将重新表达if MA() 以仅更新最近的栏步骤 和

    return (  aTrendUpPrevGT[5]
           && aTrendUpPrevGT[4]
           && aTrendUpPrevGT[3]
           && aTrendUpPrevGT[2]
              )
    

    ArraySetAsSeries()的正确使用和正确的索引步骤显然可以适应

    【讨论】:

    • 我得到了图片,但我仍然没有得到它。假设,Slow[5] 是 1.1230,Slow[4] 是 1.1231,那么代码将运行 Slow[i] &lt;= Slow[i-1] 然后返回 true,对吗?之后,代码将不会运行Slow[i] &gt; Slow[i-1] 并给出错误,对吗?为什么代码在不正确的情况下也会运行第二个条件?那么我应该在循环内写下什么代码来显示趋势是向上的(n 个柱的 MA 值有序向上)?我需要摆脱阵列吗?同样,如果您说我需要摆脱数组,我必须使用哪些代码?
    • 正如您所建议的:“假设Slow[5]1.1230Slow[4] 1.1231,” 请注意,您不是在Slow[4] 内有任何已知值,您将1.230 的值存储到Slow[5] 中。这就是陷阱。
    • 这是一个陷阱。我现在注意到,第一次迭代只知道 MA shift 5 的值。关于您的最后一次更新,您是否建议我必须写下所有 aTrendUpPrev[n]?如果 n 大于 5,比方说,一百呢? :(
    • 正如 [更新] 中所回答的 - 正确使用 ArraySetAsSeries() 将允许您将所有这些值保存在与 TOHLCV 时间序列平行的逐步增长的数组中。另一种方法是将这部分处理移动到自定义指标中。 无论如何,我很高兴您已经意识到您所询问的问题的根本原因。
    • 对不起,我来晚了。每当你写下“陷阱”时,我也很高兴。无论如何,你介意给我一些使用ArraySetAsSeries() 的例子吗?
    猜你喜欢
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    相关资源
    最近更新 更多