NinjaTrader 8 vs Metatrader 5 EA Backtesting Results

 

I have been trying to replicate the following strategy which was published by ATSon January 14, 2021. The trategy uses the MACD Indicator (MACD), Average Directional Index (ADX) and Average Directional Index Rating (ADXR).

Buy

  • When MACD (MACD plot) is greater than MACD (Avg plot)
  • When ADX crosses above ADXR

Sell

  • When MACD (MACD plot) is less than MACD (Avg plot)
  • When ADX crosses below ADXR

The parameters for this strategy are as follows:

  • Futures Contract: NQ
  • ADXR bottom: 14
  • ADXRtop: 10
  • ADXtop: 14
  • MACD1: 12
  • MACD2: 26
  • MACD3: 9
  • Data Series: Range
  • Data Series Value: 23

I've tried to replicate the NinjaTrader EA but I'm nowhere near the backtesting results published when run in NinjaTrader. I suspect my ADXR indicator could be incorrectly coded, but there could be other issues.


//+------------------------------------------------------------------+
//| EA: NinjaTraderEA.mq5
//|
//| Uses:
//|    MACD Indicator (MACD)
//|    Average Directional Index (ADX)
//|    Average Directional Index Rating (ADXR)
//| 
//| Strategy:
//|    Long
//|       MACD (MACD) >= MACD (Signal)
//|       ADX crosses above ADXR
//|    Short
//|       MACD (MACD) <= MACD (Signal)
//|       ADX crosses below ADXR
//|
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Properties                            
//+------------------------------------------------------------------+
#property      copyright     ""
#property      link          ""
#property      version       "1.00"
#property      description   "NinjaTrader EA"

//+------------------------------------------------------------------+
//| Includes                            
//+------------------------------------------------------------------+
#include       <Trade\Trade.mqh>
#include       <Trade\PositionInfo.mqh>

CTrade         Trade;                                                // object of CTrade class 
CPositionInfo  Position;                                             // object of CPositionInfo class

//+------------------------------------------------------------------+
//| Input Parameters
//+------------------------------------------------------------------+
input group                "[GENERAL]"
input string               Inp_EAComment     = "NinajaTraderEA";     //EA Comment
input int                  Inp_MagicNum      = 123321;               //Magic number

input group                "[MONEY MANAGEMENT]"
input double               Inp_Lot           = 0.1;                  //Lot Value

//Indicator Parameters
input group                "[PARAMETERS]"
input int                  Inp_ADX_Period    = 14;                   //ADX Period
input int                  Inp_ADXR_Interval = 10;                   //ARXR Interval
input int                  Inp_ADXR_Period   = 14;                   //ADXR Period
input int                  Inp_MACD_Fast     = 12;                   //MACD Fast
input int                  Inp_MACD_Slow     = 26;                   //MACD Slow
input int                  Inp_MACD_Period   = 9;                    //MACD Period

input group                "[DEBUGGING]"
input bool                 Inp_Debug         = false;                //Debugging Mode                  

//Indicator handles and Arrays
int      Indicator_ADXHandle, Indicator_ADXRHandle, Indicator_MACDHandle;
double   ADX[],ADXR[],MACD[],MACDSignal[],Close[]; 

//+------------------------------------------------------------------+
//| Initialization Function
//+------------------------------------------------------------------+
int OnInit()
  {
   //Checking connection to a trade server
   if(!TerminalInfoInteger(TERMINAL_CONNECTED))
     {
      Print(Inp_EAComment,": No Connection!");
      return(INIT_FAILED);
     }
   
   //Checking if automated trading is enabled
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      Print(Inp_EAComment,": Trade is not allowed!");
      return(INIT_FAILED);
     }
     
   //Set magic number
   Trade.SetExpertMagicNumber(Inp_MagicNum);
   
   //Debug
   if(Inp_Debug) Print("MagicNumber: "+IntegerToString(Inp_MagicNum));
   
   if ((Indicator_ADXHandle = iADX(Symbol(), PERIOD_CURRENT, Inp_ADX_Period)) == INVALID_HANDLE)
      return(INIT_PARAMETERS_INCORRECT);
      
   if ((Indicator_ADXRHandle = iADX(Symbol(), PERIOD_CURRENT, Inp_ADXR_Period)) == INVALID_HANDLE)
      return(INIT_PARAMETERS_INCORRECT);

   if ((Indicator_MACDHandle = iMACD(Symbol(), PERIOD_CURRENT, Inp_MACD_Fast, Inp_MACD_Slow, Inp_MACD_Period, PRICE_CLOSE)) == INVALID_HANDLE)
      return(INIT_PARAMETERS_INCORRECT);

   if (!InitialiseArrays())
     {
      Print(Inp_EAComment,": Failed to initialise arrays");
      Print("Error = ",GetLastError());
      return(INIT_FAILED);
     }
   
   return(INIT_SUCCEEDED);
  }
  
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
bool InitialiseArrays()
  {
   //Initialies arrays
   ArrayInitialize(ADX, true);
   ArrayInitialize(ADXR, true);    
   ArrayInitialize(MACD, true);
   ArrayInitialize(MACDSignal, true);
   ArrayInitialize(Close, true);

   //Setup arrays
   ArraySetAsSeries(ADX, 0.0);
   ArraySetAsSeries(ADXR, 0.0);    
   ArraySetAsSeries(MACD, 0.0);
   ArraySetAsSeries(MACDSignal, 0.0);
   ArraySetAsSeries(Close, 0.0);  
  
   return(true);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(Indicator_ADXHandle);                            //deletes the indicator handle and deallocates the memory space it occupies
   IndicatorRelease(Indicator_ADXRHandle);                           //deletes the indicator handle and deallocates the memory space it occupies
   IndicatorRelease(Indicator_MACDHandle);                            //deletes the indicator handle and deallocates the memory space it occupies
  
   ArrayFree(ADX);
   ArrayFree(ADXR);    
   ArrayFree(MACD);
   ArrayFree(MACDSignal);
   ArrayFree(Close);   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //Have we started a new bar?
   if(!IsNewBar(Symbol(), PERIOD_CURRENT)) return;
   
   //Getting data for calculations
   if(!GetIndValue())
     {
      if(Inp_Debug) Print("Failed to get indicator values");
      return;
     }
        
   ADXR[0] = (ADXR[0] + ADXR[Inp_ADXR_Interval])/2;
   ADXR[1] = (ADXR[1] + ADXR[Inp_ADXR_Interval+1])/2;     

   bool Buy = BuySignal();
   bool Sell = SellSignal();
   
   //Close all open orders
   if (Buy || Sell) 
     {
      if(Buy && Inp_Debug) Print("Buy Signal -> Close short trades.");
      if(Sell && Inp_Debug) Print("Sell Signal -> Close long trades.");

      if(Inp_Debug) Print("Time: "  +TimeToString(Close[1])+
                     ", MACD: "     +DoubleToString(MACD[1], 8)+
                     ", MACDSig: "  +DoubleToString(MACDSignal[1], 8)+
                     ", ADX: "      +DoubleToString(ADX[1], 4)+
                     ", ADXR: "     +DoubleToString(ADXR[1], 4)); 
                     
      if(Inp_Debug) Print("Time: "  +TimeToString(Close[0])+
                     ", MACD: "     +DoubleToString(MACD[0], 8)+
                     ", MACDSig: "  +DoubleToString(MACDSignal[0], 8)+
                     ", ADX: "      +DoubleToString(ADX[0], 4)+
                     ", ADXR: "     +DoubleToString(ADXR[0], 4)); 
      
      if(Buy)
        {
         //Ony open a long trade if we're not already in a long trade        
         if(!IsOpenedByType(POSITION_TYPE_BUY, Inp_MagicNum))
           {
            Trade.PositionClose(Symbol());
            Trade.Buy(Inp_Lot, Symbol(), 0, 0, 0, Inp_EAComment);
           }
        }
      if(Sell)   
        {
         //Ony open a short trade if we're not already in a short trade
         if(!IsOpenedByType(POSITION_TYPE_SELL, Inp_MagicNum))
           {
            Trade.PositionClose(Symbol());                
            Trade.Sell(Inp_Lot, Symbol(), 0, 0, 0, Inp_EAComment);
           } 
        }
     }
  }
  
//+------------------------------------------------------------------+
// Buy conditions
//+------------------------------------------------------------------+
bool BuySignal()
  {
   return(
      ((MACD[0] >= MACDSignal[0]) && ((ADX[1] < ADXR[1]) && (ADX[0] > ADXR[0])))
   )?true:false;
  }
//+------------------------------------------------------------------+
// Sell conditions
//+------------------------------------------------------------------+
bool SellSignal()
  {
   return(
      ((MACD[0] <= MACDSignal[0]) && ((ADX[1] > ADXR[1]) && (ADX[0] < ADXR[0])))
   )?true:false;
  }
//+------------------------------------------------------------------+
//| Getting the current indicator values                             |
//+------------------------------------------------------------------+
bool GetIndValue()
  {
   return(
      //ADX_handle
      (CopyBuffer(Indicator_ADXHandle, MAIN_LINE, 0, 2, ADX) <= 0) ||
      //ADXR_handle
      (CopyBuffer(Indicator_ADXRHandle, MAIN_LINE, 0, Inp_ADXR_Interval+2, ADXR) <= 0) ||
      //MACD_handle (Copy MACD)
      (CopyBuffer(Indicator_MACDHandle, MAIN_LINE, 0, 2, MACD) <= 0) ||
      //MACD_handle (Copy MACDSignal)
      (CopyBuffer(Indicator_MACDHandle, SIGNAL_LINE, 0, 2, MACDSignal) <= 0) ||
      //Period
      (CopyClose(Symbol(), PERIOD_CURRENT, 1, 2, Close) <= 0)
   )?false:true;
  }

//+------------------------------------------------------------------+
// Checking open position types with the magic number
// Credit: "https://www.mql5.com/ru/users/alex2356"
//+------------------------------------------------------------------+ 
bool IsOpenedByType(ENUM_POSITION_TYPE PosType, int MagicNumber)
  {
   int pos=0;
   uint total=PositionsTotal();
//---
   for(uint i=0; i<total; i++)
     {
      if(Position.SelectByIndex(i))
         if(PositionGetInteger(POSITION_TYPE)==PosType && PositionGetInteger(POSITION_MAGIC)==MagicNumber)
            pos++;
     }
   return((pos>0)?true:false);
  }

//+------------------------------------------------------------------+
// Is New Bar
// Credit: https://www.mql5.com/en/users/tonegarot
//+------------------------------------------------------------------+ 
 bool IsNewBar(const string symbol, const ENUM_TIMEFRAMES period)
  {
   bool isNewBar = false;
   static datetime priorBarOpenTime = NULL;
   
   // New Bar event handler -> per https://www.mql5.com/en/articles/159
   // SERIES_LASTBAR_DATE == Open time of the last bar of the symbol-period
   const datetime currentBarOpenTime = (datetime) SeriesInfoInteger(symbol,period,SERIES_LASTBAR_DATE);
   
   if(priorBarOpenTime != currentBarOpenTime)
   {
      // Don't want new bar just because EA started
      if (priorBarOpenTime == NULL)
         isNewBar = false;
      else
         isNewBar = true;
      
      // Regardless of new bar, update the held bar time
      priorBarOpenTime = currentBarOpenTime;
   }
   
   return isNewBar;
  }
//+------------------------------------------------------------------+

I'd really appreciate any assistance with the review of my attached EA.

Thanks

MACD - Oscillators - Technical Indicators - Price Charts, Technical and Fundamental Analysis - MetaTrader 5 Help
MACD - Oscillators - Technical Indicators - Price Charts, Technical and Fundamental Analysis - MetaTrader 5 Help
  • www.metatrader5.com
Moving Average Convergence/Divergence (MACD) is a trend-following dynamic indicator. It indicates the correlation between two Moving Averages of a...