0
votes

I'm able to get the value of Moving Average from Shift 1 to Shift n (n = amount of bars) and shows their value with Alert every 5 minute bar, but when I added the 'if (Direction == "Up")' and so on, the code shows last shift value only and hit 'break'. The most important is, I can't use them into a boolean operations.

I want the code to show Alert() when values of EMA are rising up orderly, and vice versa (for a "Trend Down"). Whenever one of their value vary (one or more bars have higher or lower value than the others), then it's "No trend".

Let's say amount of TrendBar is more than 5 bars; [] array is Bar Shift.

The algorithm for "Trend Up" is:

if Slow[n] <= Slow[...] <= Slow[3] <= Slow[2] <= Slow[1] then true

else false

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);
}

When I run the code, it only shows Alert( "Trend Up bias" ). It means the code always hit 'break' when iteration starts. It doesn't care whether the trend is in real trending up (all MA values in Slow[] array are orderly up) or not.

Q1: How to make the code work?

Q2: How to write correct code for accessing array with Boolean operations inside iteration?

Q3: What is the solution, please?

1

1 Answers

0
votes

Summary:

Q1: How to make the code work?

A1: Rewrite the iteration for-loop so as not to exit instantly in the first loop
( ref. the illustrated iteration flow / barrier below )

Q2: How to write correct code for accessing array with Boolean operations inside iteration?

A2: There is no such problem at all. If possible, always avoid testing array values, before being assigned some value
( ref. the trap below )

Q3: What is the solution, please?

A3: Repair the ill-formed for-loop + always assign a meaningful value into a variable before using it's value in further processing or comparison.


How the algorithmisation may approach the unambiguous part of the features:

//+------------------------------------------------------------------+
//|                                                      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" );

         }
}

Problem is not an access to Array cell[i] from inside for loop

As given above, your code as-is does not meet what you strive to do.

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 );
}

It starts to iterate over an i-range ( 5, 4, 3, 2 ) in bool MA()
and test a sequence of comparisons:
only in an "Up"-case:
[5]<=[4] |-> RET .T., _____________ either this
[5]> [4] |-> RET .F., _____________ or this is & must be a reason for RET {.T. | .F.}
. . . . . . . . . . . . . . . . . . . . . . _ _ _ _ _ _ _ _ _ code never gets past this
[4]<=[3] |-> RET .T.,
[4]> [3] |-> RET .F.,
[3]<=[2] |-> RET .T.,
[3]> [2] |-> RET .F.

You might already noticed, that dynamic arrays in MQL4 do not have initialised value known, the more after ArrayResize().

This makes the conditions { [5]<=[4] | [5]> [4] } fairly vulnerable to issues out of your control, as your code has assigned a value into Slow[5] but not into [4] yet and there you go.

Dynamic array memory-allocation / resize lottery side-effects expose your code to a principally uncontrollable value, accessed in [4] in both comparisons { [5]<=[4] | [5]> [4] }, which in principle is anything else but the iMA(...).

As your observations indicate the [4] being lower than an already assigned iMA() value into [5], you were sort of lucky that the randomness of the un-initialised memory ( containing uncontrollable residual binary values ) contained by no other means but just by chance some residual-bitmap, that happily was interpreted as a IEEE-float32 number, lower than the calculated & stored iMA() value compared in cell [5] with.


Update:

What would I do if I were to implement the idea?

After several hundred man*years in the MQL4-domain, Technical Indicators have taught us to rather spend some time to separate computationaly expensive parts from cheaper parts of the algo and focus the design tuning around the more expensive parts.

So:

rather think about avoiding a waste to re-calculate values already once computed a static double Slow[] would allow you to save the values once computed on a NewBar() event or use the same idea step forwards to save not the "tail" of Slow[5..2], and re-compare them upon deciding in [0], but produce & re-use not the iMA() 4B-values, but rather their already made pair-wise comparisons, which solely decide the actual return value:

static bool aTrendUpPrevGT[];
static bool aTrendDnPrevLT[];
which will re-articulate the if MA() to update just the recent bar step and

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

A proper use of ArraySetAsSeries() and correct indexing steps are obvious to be adapted