Search code examples
arraysmql4metatrader4forexmt4

Defining an array, depending on Symbol(), in MQL4 MetaTrader4 [Expert Advisor]


I have an EA that trades breakouts. I run this on multiple pairs. The problem arises when two pairs with high correlation trades the same direction ( or opposite, if negative correlation ). That doubles my risk. So, I added a snippet in my EA that prevents opening a new trade if there is already an open position of a symbol that is highly correlated with the current symbol.

( this is what I tried ):

string       strSymbol;
string       HighCorrelationPairs[];

int OnInit() {
   strSymbol = Symbol();
   if (  strSymbol == "EURAUD" ) {
         ArrayResize( HighCorrelationPairs, 1 );
         string HighCorrelationPairs[1] = { "EURJPY" };
   }
   else if (  strSymbol == "EURJPY" ) {
              ArrayResize( HighCorrelationPairs, 2 );
              string HighCorrelationPairs[2] = { "EURAUD", "EURUSD" };
        }
        else if (  strSymbol == "EURUSD" ) {
                   ArrayResize( HighCorrelationPairs, 2 );
                   string HighCorrelationPairs[2] = { "EURJPY", "USDCHF" };
             }
             else if (  strSymbol == "GBPJPY" ) {
                        ArrayResize( HighCorrelationPairs, 1 );
                        string HighCorrelationPairs[1] = { "GBPUSD" };
                  }
                  else if (  strSymbol == "GBPUSD" ) {
                             ArrayResize( HighCorrelationPairs, 1 );
                             string HighCorrelationPairs[1] = { "GBPJPY" };
                       }
                       else if (  strSymbol == "USDCHF" ) {
                                  ArrayResize( HighCorrelationPairs, 1 );
                                  string HighCorrelationPairs[1] = { "EURUSD" };
                            }
                            else if (  strSymbol == "USDJPY" ) {
                                       ArrayResize( HighCorrelationPairs, 1 );
                                       string HighCorrelationPairs[1] = {};
                                 }
                                 else {
                                        ArrayResize( HighCorrelationPairs, 1 );
                                        string HighCorrelationPairs[1] = {};
                                 }
}

void OnTick() {          //--- Check Correlation and Number of Trades
   for ( k = OrdersTotal() - 1; k >= 0; k-- ) {
         if (  OrderSelect( k, SELECT_BY_POS, MODE_TRADES ) ) {
               if (  OrderType() == OP_BUY
                  || OrderType() == OP_SELL
                     ) {
                     if (  OrderSymbol()      == Symbol()
                        && OrderMagicNumber() == MagicNumber
                           ) {
                           return;
                     }
                     if (  TimeCurrent() - OrderOpenTime() <= 18000 ) {
                           for ( int i = 0;i <  ArraySize( HighCorrelationPairs ); i++ ) {
                                 if (  OrderSymbol() == HighCorrelationPairs[i] ) { return; }
                           }
                     }
               }
         }
   }
}

Upon compiling, this is the warning/s that I got

variable 'HighCorrelationPairs' not used
declaration of 'HighCorrelationPairs' hides global declaration at line 120

It's only a warning, not an error.


Solution

  • The primary problem is called a variable "scope-of-declaration"

    given a code instructs the compiler to do this:

    if (  strSymbol == "EURAUD" ) {
             ArrayResize( HighCorrelationPairs, 1 );
             string HighCorrelationPairs[1] = { "EURJPY" };
       }
    

    the last row inside the lexical-scope of the if's body -- the if(){...} body-part, being the {...} -- is the only ephemeral zone, where the newly "locally" created statically pre-sized object, into which a value is going to get assigned string HighCorrelationPairs[1] = ... ; is immediatelly lost
    once the "scope-of-declaration" will be crossed ( i.e. immediately after it's creation / assignment )

    Next comes the variable name masking:

    Next after a new, "local" string HighCorrelationPairs[] is created, the compiler has to at least inform you, that any colliding object-name, defined on any other level ( higher in the already visited hierarchy ) becomes un-available at the same time, thus leaving the most recently declared object's name to effectively mask all previously defined objects, bearing the lexically "same" name. So, you have been warned.

    Refine your code, so as to avoid variable names' masking and do obey the variable lexical "scope-of-declaration".

    switch( _Symbol ){
         case "EURAUD" : {  ArrayResize( HighCorrelationPairs, 1 );
                                         HighCorrelationPairs[0] = "EURJPY";
                            break;
                            }
         case "EURUSD" : {  ArrayResize( HighCorrelationPairs, 2 );
                                         HighCorrelationPairs[0] = "EURJPY";
                                         HighCorrelationPairs[1] = "USDCHF";
                            break;
                            }
         ...
    }
    

    Well, right, MQL4 documentation was not clear in this. The specification stated a switch( selector ) must have the selector part as an expression ( which was met ).

    Switch Operator
    Compares the expression value with constants in all the case variants and passes control to the operator that corresponds to the expression value. Each variant of case can be marked with an integer constant, a literal constant or a constant expression.

    Nevertheless, the compiler rejects any other but int type to serve in this syntax-constructor.

    So, best to use some trivial HASH-function to get int:

    int   Symbol2HASH( const string aSymbol = "EURUSD" ) {
    // -----------------------------------
    // NAIVE, BUT WORKING:
    // ------------------UUID--------------
    #define DEF_EURUSD      0
    #define DEF_EURJPY      1
    #define DEF_EURAUD      2
    #define DEF_EURCHF      3
    //          ...       ...
    // ------------------UUID--------------
    // MAINTAIN HERE ALL UUID #s PLUS aSymbol MAPPINGS:
    // --------vvvvvvv----------------------vvvvvvvvvv
          if ( aSymbol == "EURUSD" ) return DEF_EURUSD;
          if ( aSymbol == "EURJPY" ) return DEF_EURJPY;
          if ( aSymbol == "EURAUD" ) return DEF_EURAUD;
          if ( aSymbol == "EURCHF" ) return DEF_EURCHF;
    
          return EMPTY;
      }
    

    switch( Symbol2HASH( _Symbol ) ) {
           case DEF_EURAUD: {  ArrayResize( HighCorrelationPairs, 1 );
                                            HighCorrelationPairs[0] = "EURJPY";
                               break;
                               }
           case DEF_EURUSD: {  ArrayResize( HighCorrelationPairs, 2 );
                                            HighCorrelationPairs[0] = "EURJPY";
                                            HighCorrelationPairs[1] = "USDCHF";
                               break;
                               }
           case EMPTY: {       PrintFormat( "Symbol()==[%s] not included inside Symbol2HASH() function. Edit source.", _Symbol );
                               ExpertRemove();
                               }
           default:    {       PrintFormat( "Symbol()==[%s] code [%d] was not served inside switch(){ case-s }. Edit source.", _Symbol, Symbol2HASH( _Symbol ) );
                               ExpertRemove();
                               }
      }