Why this code doesn't work in backtesting?

 
This is a Moving Average Crossover EA made by Tom Whitbread. I have tried so many times to backtest This EA but it doesn't work. I could not find what is the actual problem in this code.

Where is the problem anyone can find it?

//+------------------------------------------------------------------+ 
//| Double Sma.mq4 | 
//| Copyright 2017, Tom Whitbread. | 
//| http://www.gript.co.uk | 
//+------------------------------------------------------------------+ 
#property copyright "2017, Tom Whitbread." 
#property link "http://www.gript.co.uk" 
#property description "Smoothed Moving Average sample expert advisor" 
#define MAGICNUM 20131111 
// Define our Parameters 
input double Lots          = 0.01;
input int PeriodOne        = 9; // The period for the first SMA 
input int PeriodTwo        = 21; // The period for the second SMA 
input int TakeProfit       = 150; // The take profit level (0 disable) 
input int StopLoss         = 50; // The default stop loss (0 disable) 
//+------------------------------------------------------------------+ 
//| expert initialization functions | 
//+------------------------------------------------------------------+ 
int init()
{
  return(0);
}
int deinit()
{
  return(0);
}
//+------------------------------------------------------------------+ 
//| Check for cross over of SMA | 
//+------------------------------------------------------------------+ 
int CheckForCross(double input1, double input2)
{
  static int previous_direction = 0;
  static int current_direction  = 0;
  // Up Direction = 1 
  if(input1 > input2){
    current_direction = 1;
  }
  // Down Direction = 2 
  if(input1 < input2){
    current_direction = 2;
  }
  // Detect a direction change 
  if(current_direction != previous_direction){
    previous_direction = current_direction;
    return (previous_direction);
  } else {
    return (0);
  }
}
//+------------------------------------------------------------------+ 
//| Calculate optimal lot size | 
//+------------------------------------------------------------------+ 
double LotsOptimized()
  {
   double lot = Lots;
   // Calculate Lot size as a fifth of available free equity. 
   lot = NormalizeDouble((AccountFreeMargin()/5)/1000.0,1);
   if(lot<0.1) lot=0.1; //Ensure the minimal amount is 0.1 lots 
   return(lot);
  }
//+------------------------------------------------------------------+ 
//+ Break Even | 
//+------------------------------------------------------------------+ 
bool BreakEven(int MN){
  int Ticket;
  for(int i = OrdersTotal() - 1; i >= 0; i--) {
    OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MN){
      Ticket = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, Green);
      if(Ticket < 0) Print("Error in Break Even : ", GetLastError());
        break;
      }
    }
  return(Ticket);
}
//+------------------------------------------------------------------+ 
//+ Run the algorithm | 
//+------------------------------------------------------------------+ 
int start()
{
  int cnt, ticket, total;
  double shortSma, longSma, ShortSL, ShortTP, LongSL, LongTP;
  // Parameter Sanity checking 
  if(PeriodTwo < PeriodOne){
    Print("Please check settings, Period Two is lesser then the first period");
    return(0);
  }
  if(Bars < PeriodTwo){
    Print("Please check settings, less then the second period bars available for the long SMA");
    return(0);
  }
  // Calculate the SMAs from the iMA indicator in MODE_SMMA using the close price 
  shortSma = iMA(NULL, 0, PeriodOne, 0, MODE_SMMA, PRICE_CLOSE, 0);
  longSma = iMA(NULL, 0, PeriodTwo, 0, MODE_SMMA, PRICE_CLOSE, 0);
  // Check if there has been a cross on this tick from the two SMAs 
  int isCrossed = CheckForCross(shortSma, longSma);
  // Get the current total orders 
  total = OrdersTotal();
  // Calculate Stop Loss and Take profit 
  if(StopLoss > 0){
    ShortSL = Bid+(StopLoss*Point);
    LongSL = Ask-(StopLoss*Point);
  }
  if(TakeProfit > 0){
    ShortTP = Bid-(TakeProfit*Point);
    LongTP = Ask+(TakeProfit*Point);
  }
// Only open one trade at a time.. 
if(total < 1){
  // Buy - Long position 
  if(isCrossed == 1){
    ticket = OrderSend(Symbol(), OP_BUY, LotsOptimized(),Ask,5, LongSL, LongTP, "Double SMA Crossover",MAGICNUM,0,Blue);
    if(ticket > 0){
      if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
        Print("BUY Order Opened: ", OrderOpenPrice(), " SL:", LongSL, " TP: ", LongTP);
    }
    else
      Print("Error Opening BUY Order: ", GetLastError());
    return(0);
  }
  // Sell - Short position 
  if(isCrossed == 2){
    ticket = OrderSend(Symbol(), OP_SELL, LotsOptimized(),Bid,5, ShortSL, ShortTP, "Double SMA Crossover",MAGICNUM,0,Red);
    if(ticket > 0){
      if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
        Print("SELL Order Opened: ", OrderOpenPrice(), " SL:", ShortSL, " TP: ", ShortTP);
    }
    else
      Print("Error Opening SELL Order: ", GetLastError());
    return(0);
  }
}

// Manage open orders for exit criteria 
for(cnt = 0; cnt < total; cnt++){
  OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
  if(OrderType() <= OP_SELL && OrderSymbol() == Symbol()){
    // Look for long positions 
    if(OrderType() == OP_BUY){
      // Check for Exit criteria on buy - change of direction 
      if(isCrossed == 2){
        OrderClose(OrderTicket(), OrderLots(), Bid, 3, Violet); // Close the position 
        return(0);
      }
    }
    else //Look for short positions - inverse of prior conditions 
    {
      // Check for Exit criteria on sell - change of direction 
      if(isCrossed == 1){
        OrderClose(OrderTicket(), OrderLots(), Ask, 3, Violet); // Close the position 
        return(0);
      }
    }
    // If we are in a loss - Try to BreakEven 
    Print("Current Unrealized Profit on Order: ", OrderProfit());
    if(OrderProfit() < 0){
      BreakEven(MAGICNUM);
    }
  }
}

  return(0);
}
 

Please don't create topics randomly in any section. It has been moved to the section: MQL4 e MetaTrader 4

Please EDIT your post and use the CODE button (Alt-S) when inserting code.

Code button in editor

 
  1. i don't know: but it doesn't work. I could not find what is the actual problem in this code.

    “Doesn't work” is meaningless — just like saying the car doesn't work. Doesn't start, won't go in gear, no electrical, missing the key, flat tires — meaningless.
         How To Ask Questions The Smart Way. (2004)
              When asking about code
              Be precise and informative about your problem

  2.       Ticket = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, Green);

    OrderModify does not return a ticket.

  3.   if(StopLoss > 0){
        ShortSL = Bid+(StopLoss*Point);
        LongSL = Ask-(StopLoss*Point);
      }
      if(TakeProfit > 0){
        ShortTP = Bid-(TakeProfit*Point);
        LongTP = Ask+(TakeProfit*Point);

    You buy at the Ask and sell at the Bid. Pending Buy Stop orders become market orders when hit by the Ask.

    1. Your buy order's TP/SL (or Sell Stop's/Sell Limit's entry) are triggered when the Bid / OrderClosePrice reaches it. Using Ask±n, makes your SL shorter and your TP longer, by the spread. Don't you want the specified amount used in either direction?

    2. Your sell order's TP/SL (or Buy Stop's/Buy Limit's entry) will be triggered when the Ask / OrderClosePrice reaches it. To trigger close at a specific Bid price, add the average spread.
                MODE_SPREAD (Paul) - MQL4 programming forum - Page 3 #25

    3. The charts show Bid prices only. Turn on the Ask line to see how big the spread is (Tools → Options (control+O) → charts → Show ask line.)

      Most brokers with variable spreads widen considerably at end of day (5 PM ET) ± 30 minutes.
      My GBPJPY shows average spread = 26 points, average maximum spread = 134.
      My EURCHF shows average spread = 18 points, average maximum spread = 106.
      (your broker will be similar).
                Is it reasonable to have such a huge spreads (20 PIP spreads) in EURCHF? - General - MQL5 programming forum (2022)

  4. // Manage open orders for exit criteria 
    for(cnt = 0; cnt < total; cnt++){
      OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);

    In the presence of multiple orders (one EA multiple charts, multiple EAs, manual trading), while you are waiting for the current operation (closing, deleting, modifying) to complete, any number of other operations on other orders could have concurrently happened and changed the position indexing and order count:

    1. For non-FIFO (non-US brokers), (or the EA only opens one order per symbol), you can simply count down, in an index loop, and you won't miss orders. Get in the habit of always counting down.
                Loops and Closing or Deleting Orders - MQL4 programming forum

    2. For In First Out (FIFO rules — US brokers), and you (potentially) process multiple orders per symbol, you must find the earliest order (count up), close it, and on a successful operation, reprocess all positions (from zero).
                CloseOrders by FIFO Rules - Strategy Tester - MQL4 programming forum - Page 2 #16
                MetaTrader 5 platform beta build 2155: MQL5 scope, global Strategy Tester and built-in Virtual Hosting updates - Best Expert Advisors - General - MQL5 programming forum #1.11

    and check OrderSelect in case other positions were deleted.
              What are Function return values ? How do I use them ? - MQL4 programming forum
              Common Errors in MQL4 Programs and How to Avoid Them - MQL4 Articles

    and if you (potentially) process multiple orders, must call RefreshRates() after server calls if you want to use, on the next order / server call, the Predefined Variables (Bid/Ask.) Or instead, be direction independent and just use OrderClosePrice().

  5. i don't know: Where is the problem anyone can find it?

    Use the debugger or print out your variables, including _LastError and prices and find out why. Do you really expect us to debug your code for you?
              Code debugging - Developing programs - MetaEditor Help
              Error Handling and Logging in MQL5 - MQL5 Articles (2015)
              Tracing, Debugging and Structural Analysis of Source Code - MQL5 Articles (2011)
              Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator - MQL5 Articles (2010)

 
i don't know:
This is a Moving Average Crossover EA made by Tom Whitbread. I have tried so many times to backtest This EA but it doesn't work. I could not find what is the actual problem in this code.

Where is the problem anyone can find it?

Hi! I'm new, but hope this updated code helps. Just backtested it in MT4 on EURUSD with M30 and April 1st 2023 - May 25th 2023 timeframe. Default Expert properties and Optimization disabled.
Looks like it actually makes a decent profit!

Regards


//+------------------------------------------------------------------+
//| Double Sma.mq4                                                   |
//| Copyright 2017, Tom Whitbread.                                   |
//| http://www.gript.co.uk                                            |
//+------------------------------------------------------------------+
#property copyright "2017, Tom Whitbread."
#property link "http://www.gript.co.uk"
#property description "Smoothed Moving Average sample expert advisor"
#define MAGICNUM 20131111

// Define our Parameters
input double Lots = 0.01;
input int PeriodOne = 9;            // The period for the first SMA
input int PeriodTwo = 21;           // The period for the second SMA
input int TakeProfit = 150;         // The take profit level (0 disable)
input int StopLoss = 50;            // The default stop loss (0 disable)

//+------------------------------------------------------------------+
//| expert initialization functions                                   |
//+------------------------------------------------------------------+
int init()
{
    return (0);
}

int deinit()
{
    return (0);
}

//+------------------------------------------------------------------+
//| Check for cross over of SMA                                      |
//+------------------------------------------------------------------+
int CheckForCross(double input1, double input2)
{
    static int previous_direction = 0;
    static int current_direction = 0;

    // Up Direction = 1
    if (input1 > input2)
    {
        current_direction = 1;
    }
    // Down Direction = 2
    if (input1 < input2)
    {
        current_direction = 2;
    }

    // Detect a direction change
    if (current_direction != previous_direction)
    {
        previous_direction = current_direction;
        return (previous_direction);
    }
    else
    {
        return (0);
    }
}

//+------------------------------------------------------------------+
//| Calculate optimal lot size                                        |
//+------------------------------------------------------------------+
double LotsOptimized()
{
    double lot = Lots;

    // Calculate Lot size as a fifth of available free equity.
    lot = NormalizeDouble((AccountFreeMargin() / 5) / 1000.0, 1);
    if (lot < 0.1)
        lot = 0.1; //Ensure the minimal amount is 0.1 lots

    return (lot);
}

//+------------------------------------------------------------------+
//+ Break Even                                                       |
//+------------------------------------------------------------------+
bool BreakEven(int MN)
{
    int Ticket;
    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if (OrderSymbol() == Symbol() && OrderMagicNumber() == MN)
            {
                Ticket = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, Green);
                if (Ticket < 0)
                {
                    Print("Error in Break Even : ", GetLastError());
                }
                break;
            }
        }
    }
    return (Ticket > 0);
}

//+------------------------------------------------------------------+
//+ Run the algorithm                                                |
//+------------------------------------------------------------------+
int start()
{
    int cnt, ticket, total;
    double shortSma, longSma, ShortSL, ShortTP, LongSL, LongTP;

    // Parameter Sanity checking
    if (PeriodTwo < PeriodOne)
    {
        Print("Please check settings, Period Two is lesser than the first period");
        return (0);
    }

    if (Bars < PeriodTwo)
    {
        Print("Please check settings, less than the second period bars available for the long SMA");
        return (0);
    }

    // Calculate the SMAs from the iMA indicator in MODE_SMMA using the close price
    shortSma = iMA(NULL, 0, PeriodOne, 0, MODE_SMMA, PRICE_CLOSE, 0);
    longSma = iMA(NULL, 0, PeriodTwo, 0, MODE_SMMA, PRICE_CLOSE, 0);

    // Check if there has been a cross on this tick from the two SMAs
    int isCrossed = CheckForCross(shortSma, longSma);

    // Get the current total orders
    total = OrdersTotal();

    // Calculate Stop Loss and Take profit
    if (StopLoss > 0)
    {
        ShortSL = Bid + (StopLoss * Point);
        LongSL = Ask - (StopLoss * Point);
    }

    if (TakeProfit > 0)
    {
        ShortTP = Bid - (TakeProfit * Point);
        LongTP = Ask + (TakeProfit * Point);
    }

    // Only open one trade at a time..
    if (total < 1)
    {
        // Buy - Long position
        if (isCrossed == 1)
        {
            ticket = OrderSend(Symbol(), OP_BUY, LotsOptimized(), Ask, 5, LongSL, LongTP, "Double SMA Crossover", MAGICNUM, 0, Blue);
            if (ticket > 0)
            {
                if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
                {
                    Print("BUY Order Opened: ", OrderOpenPrice(), " SL:", LongSL, " TP: ", LongTP);
                }
                else
                {
                    Print("Error Opening BUY Order: ", GetLastError());
                }
            }
            else
            {
                Print("Error Opening BUY Order: ", GetLastError());
            }
            return (0);
        }

        // Sell - Short position
        if (isCrossed == 2)
        {
            ticket = OrderSend(Symbol(), OP_SELL, LotsOptimized(), Bid, 5, ShortSL, ShortTP, "Double SMA Crossover", MAGICNUM, 0, Red);
            if (ticket > 0)
            {
                if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
                {
                    Print("SELL Order Opened: ", OrderOpenPrice(), " SL:", ShortSL, " TP: ", ShortTP);
                }
                else
                {
                    Print("Error Opening SELL Order: ", GetLastError());
                }
            }
            else
            {
                Print("Error Opening SELL Order: ", GetLastError());
            }
            return (0);
        }
    }

    // Manage open orders for exit criteria
    for (cnt = 0; cnt < total; cnt++)
    {
        if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES))
        {
            if (OrderType() <= OP_SELL && OrderSymbol() == Symbol())
            {
                // Look for long positions
                if (OrderType() == OP_BUY)
                {
                    // Check for Exit criteria on buy - change of direction
                    if (isCrossed == 2)
                    {
                        bool closeResult = OrderClose(OrderTicket(), OrderLots(), Bid, 3, Violet); // Close the position
                        if (closeResult)
                        {
                            Print("Closed BUY Order: ", OrderTicket(), " at Bid: ", Bid);
                        }
                        else
                        {
                            Print("Error Closing BUY Order: ", GetLastError());
                        }
                        return (0);
                    }
                }
                else // Look for short positions - inverse of prior conditions
                {
                    // Check for Exit criteria on sell - change of direction
                    if (isCrossed == 1)
                    {
                        bool closeResult2 = OrderClose(OrderTicket(), OrderLots(), Ask, 3, Violet); // Close the position
                        if (closeResult2)
                        {
                            Print("Closed SELL Order: ", OrderTicket(), " at Ask: ", Ask);
                        }
                        else
                        {
                            Print("Error Closing SELL Order: ", GetLastError());
                        }
                        return (0);
                    }
                }

                // If we are in a loss - Try to BreakEven
                double currentProfit = OrderProfit();
                Print("Current Unrealized Profit on Order ", OrderTicket(), ": ", currentProfit);
                if (currentProfit < 0)
                {
                    BreakEven(MAGICNUM);
                }
            }
        }
    }

    return (0);
}
 
  1. persector #: this updated code helps. Just backtested it in MT4 on EURUSD with M30 and April 1st 2023 - May 25th 2023 timeframe. Default Expert properties and Optimization disabled.

    Looks like it actually makes a decent profit!

                    Ticket = OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, Green);

    Again, #2.2

  2. Again, #2.3

  3. There is not such thing as "Optimization disabled." You either run an optimization run or your don't.

  4. int start()
    {
        ⋮
        if (PeriodTwo < PeriodOne)
        {
            Print("Please check settings, Period Two is lesser than the first period");
            return (0);
        }
    
        if (Bars < PeriodTwo)
        {
            Print("Please check settings, less than the second period bars available for the long SMA");
            return (0);
        }

    Check your input variables in OnInit, and reject there.

  5.     total = OrdersTotal();

    Magic number only allows an EA to identify its trades from all others. Using OrdersTotal/OrdersHistoryTotal (MT4) or PositionsTotal (MT5), directly and/or no Magic number/symbol filtering on your OrderSelect / Position select loop means your code is incompatible with every EA (including itself on other charts and manual trading.)
              Symbol Doesn't equal Ordersymbol when another currency is added to another seperate chart . - MQL4 programming forum (2013)
              PositionClose is not working - MQL5 programming forum (2020)
              MagicNumber: "Magic" Identifier of the Order - MQL4 Articles (2006)
              Orders, Positions and Deals in MetaTrader 5 - MQL5 Articles (2011)
              Limit one open buy/sell position at a time - General - MQL5 programming forum (2022)

    You need one Magic Number for each symbol/timeframe/strategy.
         Trade current timeframe, one strategy, and filter by symbol requires one MN.
         If trading multiple timeframes, and filter by symbol requires use a range of MN (base plus timeframe).
              Why are MT5 ENUM_TIMEFRAMES strange? - General - MQL5 programming forum - Page 2 #11 (2020)

  6.     for (cnt = 0; cnt < total; cnt++)

    Total was before you opened orders.

    In the presence of multiple orders (one EA multiple charts, multiple EAs, manual trading), while you are waiting for the current operation (closing, deleting, modifying) to complete, any number of other operations on other orders could have concurrently happened and changed the position indexing and order count:

    1. For non-FIFO (non-US brokers), (or the EA only opens one order per symbol), you can simply count down, in an index loop, and you won't miss orders. Get in the habit of always counting down.
                Loops and Closing or Deleting Orders - MQL4 programming forum

    2. For In First Out (FIFO rules — US brokers), and you (potentially) process multiple orders per symbol, you must find the earliest order (count up), close it, and on a successful operation, reprocess all positions (from zero).
                CloseOrders by FIFO Rules - Strategy Tester - MQL4 programming forum - Page 2 #16
                MetaTrader 5 platform beta build 2155: MQL5 scope, global Strategy Tester and built-in Virtual Hosting updates - Best Expert Advisors - General - MQL5 programming forum #1.11

    and check OrderSelect in case other positions were deleted.
              What are Function return values ? How do I use them ? - MQL4 programming forum
              Common Errors in MQL4 Programs and How to Avoid Them - MQL4 Articles

    and if you (potentially) process multiple orders, must call RefreshRates() after server calls if you want to use, on the next order / server call, the Predefined Variables (Bid/Ask.) Or instead, be direction independent and just use OrderClosePrice().