fxDreema

    • Register
    • Login
    • Search
    • Back to the main page
    • Categories
    • Recent
    • Tags
    • Popular
    • Search

    Multi-Symbol EAs Strategy Tester code

    Bug Reports
    3
    11
    1978
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J
      JamesDaly last edited by

      Please add this logic into the base code of fxdreema to allow multi symbol/account management testing EXAMPLE BELOW

      https://www.youtube.com/watch?v=ec6-LAtlrOc

      This will be extremely beneficial to all users who can then use the strategy tester in MQL5 to test a strategy with management on multiple pairs at the same time showing the effect on the whole account and not just one symbol.

      //NOTE 2: Testing using multiple symbols takes longer than testing a single symbol because the EA
      // needs to process multiple price data streams, multiple indicators etc.

      //NOTE 3: Backtesting multiple symbols simultaneously can increase the demand for resources considerably on
      // the host PC. Monitor memory to ensure this is not causing paging to occur since this will slow down
      // the process considerably. If paging does occur, additional memory may need to be purchased.

      #include <StdLibErr.mqh>

      //INPUTS
      input string TradeSymbols = "AUDCAD|AUDJPY|AUDNZD|AUDUSD|EURUSD"; //Symbol(s) or ALL or CURRENT
      input int BBandsPeriods = 20; //Bollinger Bands Periods
      input double BBandsDeviations = 1.0; //Bollinger Bands Deviations

      //GENERAL GLOBALS
      string AllSymbolsString = "AUDCAD|AUDJPY|AUDNZD|AUDUSD|CADJPY|EURAUD|EURCAD|EURGBP|EURJPY|EURNZD|EURUSD|GBPAUD|GBPCAD|GBPJPY|GBPNZD|GBPUSD|NZDCAD|NZDJPY|NZDUSD|USDCAD|USDCHF|USDJPY";
      int NumberOfTradeableSymbols;
      string SymbolArray[];
      int TicksReceivedCount = 0;

      //INDICATOR HANDLES
      int handle_BollingerBands[];
      //Place additional indicator handles here as required
      //OPEN TRADE ARRAYS
      ulong OpenTradeOrderTicket[]; //To store 'order' ticket for trades
      //Place additional trade arrays here as required to assist with open trade management

      int OnInit()
      {
      if(TradeSymbols == "CURRENT") //Override TradeSymbols input variable and use the current chart symbol only
      {
      NumberOfTradeableSymbols = 1;

           ArrayResize(SymbolArray, 1);
           SymbolArray[0] = Symbol(); 
           Print("EA will process ", SymbolArray[0], " only");
        }
        else
        {  
           string TradeSymbolsToUse = "";
           
           if(TradeSymbols == "ALL")
              TradeSymbolsToUse = AllSymbolsString;
           else
              TradeSymbolsToUse = TradeSymbols;
           
           //CONVERT TradeSymbolsToUse TO THE STRING ARRAY SymbolArray
           NumberOfTradeableSymbols = StringSplit(TradeSymbolsToUse, '|', SymbolArray);
           
           Print("EA will process: ", TradeSymbolsToUse);
        }
        
        //RESIZE OPEN TRADE ARRAYS (based on how many symbols are being traded)
        ResizeCoreArrays();
        
        //RESIZE INDICATOR HANDLE ARRAYS
        ResizeIndicatorHandleArrays();
        
        Print("All arrays sized to accomodate ", NumberOfTradeableSymbols, " symbols");
        
        //INITIALIZE ARAYS
        for(int SymbolLoop=0; SymbolLoop < NumberOfTradeableSymbols; SymbolLoop++)
           OpenTradeOrderTicket[SymbolLoop] = 0;
        
        //INSTANTIATE INDICATOR HANDLES
        if(!SetUpIndicatorHandles())
           return(INIT_FAILED); 
        
        return(INIT_SUCCEEDED);     
      

      }

      void OnDeinit(const int reason)
      {
      Comment("\n\rMulti-Symbol EA Stopped");
      }
      void OnTick()
      {
      TicksReceivedCount++;
      string indicatorMetrics = "";

        //LOOP THROUGH EACH SYMBOL TO CHECK FOR ENTRIES AND EXITS, AND THEN OPEN/CLOSE TRADES AS APPROPRIATE
        for(int SymbolLoop = 0; SymbolLoop < NumberOfTradeableSymbols; SymbolLoop++)
        {
           string CurrentIndicatorValues; //passed by ref below
           
           //GET OPEN SIGNAL (BOLLINGER BANDS SIMPLY USED AS AN EXAMPLE)
           string OpenSignalStatus = GetBBandsOpenSignalStatus(SymbolLoop, CurrentIndicatorValues);      
           StringConcatenate(indicatorMetrics, indicatorMetrics, SymbolArray[SymbolLoop], "  |  ", CurrentIndicatorValues, "  |  OPEN_STATUS=", OpenSignalStatus, "  |  ");
           
           //GET CLOSE SIGNAL (BOLLINGER BANDS SIMPLY USED AS AN EXAMPLE)
           string CloseSignalStatus = GetBBandsCloseSignalStatus(SymbolLoop);
           StringConcatenate(indicatorMetrics, indicatorMetrics, "CLOSE_STATUS=", CloseSignalStatus, "\n\r");
           
           //PROCESS TRADE OPENS
           if((OpenSignalStatus == "LONG" || OpenSignalStatus == "SHORT") && OpenTradeOrderTicket[SymbolLoop] == 0)
              ProcessTradeOpen(SymbolLoop, OpenSignalStatus);
           
           //PROCESS TRADE CLOSURES
           else if((CloseSignalStatus == "CLOSE_LONG" || CloseSignalStatus == "CLOSE_SHORT") && OpenTradeOrderTicket[SymbolLoop] != 0)
              ProcessTradeClose(SymbolLoop, CloseSignalStatus);
        }
        
        //OUTPUT INFORMATION AND METRICS TO THE CHART (No point wasting time on this code if in the Strategy Tester)
        if(!MQLInfoInteger(MQL_TESTER))
           OutputStatusToChart(indicatorMetrics);   
      

      }

      void ResizeCoreArrays()
      {
      ArrayResize(OpenTradeOrderTicket, NumberOfTradeableSymbols);
      //Add other trade arrays here as required
      }

      void ResizeIndicatorHandleArrays()
      {
      //Indicator Handles
      ArrayResize(handle_BollingerBands, NumberOfTradeableSymbols);
      //Add other indicators here as required by your EA
      }

      //SET UP REQUIRED INDICATOR HANDLES (arrays because of multi-symbol capability in EA)
      bool SetUpIndicatorHandles()
      {
      //Bollinger Bands
      for(int SymbolLoop=0; SymbolLoop < NumberOfTradeableSymbols; SymbolLoop++)
      {
      //Reset any previous error codes so that only gets set if problem setting up indicator handle
      ResetLastError();

           handle_BollingerBands[SymbolLoop] = iBands(SymbolArray[SymbolLoop], Period(), BBandsPeriods, 0, BBandsDeviations, PRICE_CLOSE);
           
           if(handle_BollingerBands[SymbolLoop] == INVALID_HANDLE) 
           { 
              string outputMessage = "";
              
              if(GetLastError() == 4302)
                 outputMessage = "Symbol needs to be added to the MarketWatch";
              else
                 StringConcatenate(outputMessage, "(error code ", GetLastError(), ")");
      
              MessageBox("Failed to create handle of the iBands indicator for " + SymbolArray[SymbolLoop] + "/" + EnumToString(Period()) + "\n\r\n\r" + 
                          outputMessage +
                          "\n\r\n\rEA will now terminate.");
                           
              //Don't proceed
              return false;
           } 
           
           Print("Handle for iBands / ", SymbolArray[SymbolLoop], " / ", EnumToString(Period()), " successfully created");
        }
        
        //All completed without errors so return true
        return true;
      

      }

      string GetBBandsOpenSignalStatus(int SymbolLoop, string& signalDiagnosticMetrics)
      {
      string CurrentSymbol = SymbolArray[SymbolLoop];

        //Need to copy values from indicator buffers to local buffers
        int    numValuesNeeded = 3;
        double bufferUpper[];
        double bufferLower[];
        
        bool fillSuccessUpper = tlamCopyBuffer(handle_BollingerBands[SymbolLoop], UPPER_BAND, bufferUpper, numValuesNeeded, CurrentSymbol, "BBANDS");
        bool fillSuccessLower = tlamCopyBuffer(handle_BollingerBands[SymbolLoop], LOWER_BAND, bufferLower, numValuesNeeded, CurrentSymbol, "BBANDS");
        
        if(fillSuccessUpper == false  ||  fillSuccessLower == false)
           return("FILL_ERROR");     //No need to log error here. Already done from tlamCopyBuffer() function
        
        double CurrentBBandsUpper = bufferUpper[0];
        double CurrentBBandsLower = bufferLower[0];
        
        double CurrentClose = iClose(CurrentSymbol, Period(), 0);
         
        //SET METRICS FOR BBANDS WHICH GET RETURNED TO CALLING FUNCTION BY REF FOR OUTPUT TO CHART
        StringConcatenate(signalDiagnosticMetrics, "UPPER=", DoubleToString(CurrentBBandsUpper, (int)SymbolInfoInteger(CurrentSymbol, SYMBOL_DIGITS)), "  |  LOWER=", DoubleToString(CurrentBBandsLower, (int)SymbolInfoInteger(CurrentSymbol, SYMBOL_DIGITS)), "  |  CLOSE=" + DoubleToString(CurrentClose, (int)SymbolInfoInteger(CurrentSymbol, SYMBOL_DIGITS)));
        
        
        //INSERT YOUR OWN ENTRY LOGIC HERE
        //e.g.
        //if(CurrentClose > CurrentBBandsUpper)
        //   return("SHORT");
        //else if(CurrentClose < CurrentBBandsLower)
        //   return("LONG");
        //else
             return("NO_TRADE");
      

      }

      string GetBBandsCloseSignalStatus(int SymbolLoop)
      {
      string CurrentSymbol = SymbolArray[SymbolLoop];

        //Need to copy values from indicator buffers to local buffers
        int    numValuesNeeded = 3;
        double bufferUpper[];
        double bufferLower[];
        
        bool fillSuccessUpper = tlamCopyBuffer(handle_BollingerBands[SymbolLoop], UPPER_BAND, bufferUpper, numValuesNeeded, CurrentSymbol, "BBANDS");
        bool fillSuccessLower = tlamCopyBuffer(handle_BollingerBands[SymbolLoop], LOWER_BAND, bufferLower, numValuesNeeded, CurrentSymbol, "BBANDS");
        
        if(fillSuccessUpper == false  ||  fillSuccessLower == false)
           return("FILL_ERROR");     //No need to log error here. Already done from tlamCopyBuffer() function
        
        double CurrentBBandsUpper = bufferUpper[0];
        double CurrentBBandsLower = bufferLower[0];
        
        double CurrentClose = iClose(CurrentSymbol, Period(), 0);
         
        //INSERT YOUR OWN ENTRY LOGIC HERE
        //e.g.
        //if(CurrentClose < CurrentBBandsLower)
        //   return("CLOSE_SHORT");
        //else if(CurrentClose > CurrentBBandsUpper)
        //   return("CLOSE_LONG");
        //else
             return("NO_CLOSE_SIGNAL");
      

      }

      bool tlamCopyBuffer(int ind_handle, // handle of the indicator
      int buffer_num, // for indicators with multiple buffers
      double &localArray[], // local array
      int numBarsRequired, // number of values to copy
      string symbolDescription,
      string indDesc)
      {

        int availableBars;
        bool success = false;
        int failureCount = 0;
        
        //Sometimes a delay in prices coming through can cause failure, so allow 3 attempts
        while(!success)
        {
           availableBars = BarsCalculated(ind_handle);
           
           if(availableBars < numBarsRequired)
           {
              failureCount++;
              
              if(failureCount >= 3)
              {
                 Print("Failed to calculate sufficient bars in tlamCopyBuffer() after ", failureCount, " attempts (", symbolDescription, "/", indDesc, " - Required=", numBarsRequired, " Available=", availableBars, ")");
                 return(false);
              }
              
              Print("Attempt ", failureCount, ": Insufficient bars calculated for ", symbolDescription, "/", indDesc, "(Required=", numBarsRequired, " Available=", availableBars, ")");
              
              //Sleep for 0.1s to allow time for price data to become usable
              Sleep(100);
           }
           else
           {
              success = true;
              
              if(failureCount > 0) //only write success message if previous failures registered
                 Print("Succeeded on attempt ", failureCount+1);
           }
        }
         
        ResetLastError(); 
        
        int numAvailableBars = CopyBuffer(ind_handle, buffer_num, 0, numBarsRequired, localArray);
        
        if(numAvailableBars != numBarsRequired) 
        { 
           Print("Failed to copy data from indicator with error code ", GetLastError(), ". Bars required = ", numBarsRequired, " but bars copied = ", numAvailableBars);
           return(false); 
        } 
        
        //Ensure that elements indexed like in a timeseries (with index 0 being the current, 1 being one bar back in time etc.)
        ArraySetAsSeries(localArray, true);
        
        return(true); 
      

      }

      void ProcessTradeOpen(int SymbolLoop, string TradeDirection)
      {
      string CurrentSymbol = SymbolArray[SymbolLoop];

        //INSERT YOUR PRE-CHECKS HERE
        
        //SETUP MqlTradeRequest orderRequest and MqlTradeResult orderResult HERE 
        //Ensure that CurrentSymbol is used as the symbol 
        
        //bool success = OrderSend(orderRequest, orderResult);
        
        //CHECK FOR ERRORS AND HANDLE EXCEPTIONS HERE
        
        //SET TRADE ARRAY TO PREVENT FUTURE TRADES BEING OPENED UNTIL THIS IS CLOSED
        //OpenTradeOrderTicket[SymbolLoop] = orderResult.order;
      

      }

      void ProcessTradeClose(int SymbolLoop, string CloseDirection)
      {
      string CurrentSymbol = SymbolArray[SymbolLoop];

        //INCLUSE PRE-CLOSURE CHECKS HERE
        
        //SETUP CTrade tradeObject HERE
           
        //bool bCloseCheck = tradeObject.PositionClose(OpenTradeOrderTicket[SymbolLoop], 0); 
        
        //CHECK FOR ERRORS AND HANDLE EXCEPTIONS HERE
        
        //IF SUCCESSFUL SET TRADE ARRAY TO 0 TO ALLOW FUTURE TRADES TO BE OPENED
        //OpenTradeOrderTicket[SymbolLoop] = 0;
      

      }

      void OutputStatusToChart(string additionalMetrics)
      {
      //GET GMT OFFSET OF MT5 SERVER
      double offsetInHours = (TimeCurrent() - TimeGMT()) / 3600.0;

        //SYMBOLS BEING TRADED
        string symbolsText = "SYMBOLS BEING TRADED: ";
        for(int SymbolLoop=0; SymbolLoop < NumberOfTradeableSymbols; SymbolLoop++)
           StringConcatenate(symbolsText, symbolsText, " ", SymbolArray[SymbolLoop]);
        
        Comment("\n\rMT5 SERVER TIME: ", TimeCurrent(), " (OPERATING AT UTC/GMT", StringFormat("%+.1f", offsetInHours), ")\n\r\n\r",
                 Symbol(), " TICKS RECEIVED: ", TicksReceivedCount, "\n\r\n\r",
                 symbolsText,
                 "\n\r\n\r", additionalMetrics);
      

      }

      l'andorrà 1 Reply Last reply Reply Quote 0
      • l'andorrà
        l'andorrà @JamesDaly last edited by

        @jamesdaly Don't get me wrong but, if you have the code why don't you simply paste it into a 'custom mql code' block yourself? 🙂

        (English) I will try to help everyone in these fxDreema forums. But if you want to learn how to use the platform in depth or more quickly, I can help you with my introductory fxDreema course in English at https://www.theandorraninvestor.eu.

        (Català) Miraré d’ajudar tothom en aquests fòrums d’fxDreema. Tanmateix, si vols aprendre a fer servir la plataforma amb més profunditat o més de pressa, t’hi puc ajudar amb el meu curs d’introducció a fxDeema en català a https://www.theandorraninvestor.eu/ca.

        (Español) Intentaré ayudar a todo el mundo en estos foros de fxDreema. Sin embargo, si quieres aprender a usar la plataforma en profundidad o más deprisa, te puedo ayudar con mi curso de introducción a fxDreema en español en https://www.theandorraninvestor.eu/es.

        1 Reply Last reply Reply Quote 0
        • J
          JamesDaly last edited by

          The real reason is im not smart enough to make this code work on all projects.

          If you know how to do this please share the project

          If the code could be added to the foundations ,then muti testing should always work ,benefiting everyone and saving alot of testing time.

          l'andorrà 1 Reply Last reply Reply Quote 0
          • l'andorrà
            l'andorrà @JamesDaly last edited by

            @jamesdaly I wish I could do it, my friend! I'm afraid I'm not a programmer. 😞

            (English) I will try to help everyone in these fxDreema forums. But if you want to learn how to use the platform in depth or more quickly, I can help you with my introductory fxDreema course in English at https://www.theandorraninvestor.eu.

            (Català) Miraré d’ajudar tothom en aquests fòrums d’fxDreema. Tanmateix, si vols aprendre a fer servir la plataforma amb més profunditat o més de pressa, t’hi puc ajudar amb el meu curs d’introducció a fxDeema en català a https://www.theandorraninvestor.eu/ca.

            (Español) Intentaré ayudar a todo el mundo en estos foros de fxDreema. Sin embargo, si quieres aprender a usar la plataforma en profundidad o más deprisa, te puedo ayudar con mi curso de introducción a fxDreema en español en https://www.theandorraninvestor.eu/es.

            1 Reply Last reply Reply Quote 0
            • J
              JamesDaly last edited by

              @FXDREEMA could this be added in a future update. So all memebers can benefit from multi symbol testing?

              1 Reply Last reply Reply Quote 0
              • TipsyWisdom
                TipsyWisdom last edited by

                It can be done with the blocks that are already in Dreema, just a matter of configuration.
                I've used 2 asset classes to generate signals to tell me when to trade a 3rd.

                1 Reply Last reply Reply Quote 0
                • J
                  JamesDaly last edited by

                  Hi
                  from some further reading it seems this would have to be built into fxdreema as even with custom blocks we cannot use the #include function and we need this to enable #include <StdLibErr.mqh>

                  Please consider adding this. Multiple currency back testing is crucial to building portfolio EA's

                  1 Reply Last reply Reply Quote 0
                  • J
                    JamesDaly last edited by

                    @tipsywisdom you know how to backtest multiple symbols at one time please share your project

                    1 Reply Last reply Reply Quote 0
                    • TipsyWisdom
                      TipsyWisdom last edited by

                      you dont need custom anything.

                      I have a tutorial posted recently that includes how I did it.

                      J 1 Reply Last reply Reply Quote 0
                      • J
                        JamesDaly @TipsyWisdom last edited by

                        @tipsywisdom i couldn't find your tutorial on multiple pair back testing. please link it in this chat.

                        i have figured a work around which is to set market for each tick but having some issues with the trade management side not updating each trade with the correct trailing stops and other things. are pulling in from the other pair before updating.

                        TipsyWisdom 1 Reply Last reply Reply Quote 0
                        • TipsyWisdom
                          TipsyWisdom @JamesDaly last edited by

                          @jamesdaly https://fxdreema.com/forum/topic/14971/multi-symbol-high-of-day-low-of-day-tracking

                          1 Reply Last reply Reply Quote 0
                          • 1 / 1
                          • First post
                            Last post

                          Online Users

                          A
                          E

                          10
                          Online

                          146.7k
                          Users

                          22.4k
                          Topics

                          122.6k
                          Posts

                          Powered by NodeBB Forums | Contributors