OnTick critical error - backtest

 

Hi all,


I try to (partly) code my manuel trading strategy to be automated, but

1) it doesnt open any trades

2) with the backtest it opens two charts H1 and H4, but for the stragey it only needs to check the value of the indicator on a H4 chart

3) during the backtest I get the Errorcode "OnTick critical error"

Does anyone have an idea why do I have these problems with my EA?

I really appreciate your help!

#include <Trade\Trade.mqh>

// exported variables
input bool Monday = true;
input bool Tuesday = true;
input bool Wednesday = true;
input bool Thursday = true;
input bool Friday = true;
input bool Saturday = false;
input bool Sunday = false;
input int HoursFrom = 1;
input int HoursTo = 23;
input int MaxSpread = 50;
input double Lots = 1;
input int Deviation = 20;



// local variables
double PipValue=1;    // this variable is here to support 5-digit brokers
bool Terminated = false;
string LF = "\n";  // use this in custom or utility blocks where you need line feeds
int NDigits = 4;   // used mostly for NormalizeDouble in Flex type blocks
int ObjCount = 0;  // count of all objects created on the chart, allows creation of objects with unique names
int current = 0;

int handle1 = 0;
int handle2 = 0;



//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    //---
    NDigits = Digits();
    if (NDigits == 3 || NDigits == 5) PipValue = 10;
    
    if (AccountInfoInteger(ACCOUNT_TRADE_EXPERT) == false)
    {
        Print("Check terminal options because EA trade option is set to not allowed.");
        Comment("Check terminal options because EA trade option is set to not allowed.");
    }
    
    if (false) ObjectsDeleteAll(0);      // clear the chart
    
    handle1 = iCustom(NULL, PERIOD_H4, "Kalman velocity (mtf)");
    handle2 = iCustom(NULL, PERIOD_CURRENT, "Kalman velocity (mtf)");
    
    
    Comment("");    // clear the chart
    //---
    return(0);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    //---
    if (false) ObjectsDeleteAll(0);
    
    IndicatorRelease(handle1);
    IndicatorRelease(handle2);
 
    
    return;
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    //---
    if (Terminated == true)
    {
        Comment("EA Terminated.");
    }
    
    OnEveryTick();
    return ;
}

//+------------------------------------------------------------------+
//| Get Low for specified bar index                                  |
//+------------------------------------------------------------------+
double Low(int index)
{
    double arr[];
    double low = 0;
    ArraySetAsSeries(arr, true);
    int copied = CopyLow(Symbol(), PERIOD_CURRENT, 0, Bars(Symbol(), PERIOD_CURRENT), arr);
    if (copied>0 && index<copied) low = arr[index];
    return (low);
}
//+------------------------------------------------------------------+
//| Get the High for specified bar index                             |
//+------------------------------------------------------------------+
double High(int index)
{
    double arr[];
    double high = 0;
    ArraySetAsSeries(arr, true);
    int copied = CopyHigh(Symbol(), PERIOD_CURRENT, 0, Bars(Symbol(), PERIOD_CURRENT), arr);
    if (copied>0 && index<copied) high=arr[index];
    return(high);
}
//+------------------------------------------------------------------+
//| Get Close for specified bar index                                |
//+------------------------------------------------------------------+
double Close(int index)
{
    double arr[];
    double close = 0;
    ArraySetAsSeries(arr, true);
    int copied = CopyClose(Symbol(), PERIOD_CURRENT, 0, Bars(Symbol(), PERIOD_CURRENT), arr);
    if (copied>0 && index<copied) close = arr[index];
    return (close);
}
//+------------------------------------------------------------------+
//| Get Open for specified bar index                                 |
//+------------------------------------------------------------------+
double Open(int index)
{
    double arr[];
    double open = 0;
    ArraySetAsSeries(arr, true);
    int copied = CopyOpen(Symbol(), PERIOD_CURRENT, 0, Bars(Symbol(), PERIOD_CURRENT), arr);
    if (copied>0 && index<copied) open = arr[index];
    return (open);
}
//+------------------------------------------------------------------+
//| Get current bid value                                            |
//+------------------------------------------------------------------+
double Bid()
{
    return (SymbolInfoDouble(Symbol(), SYMBOL_BID));
}

//+------------------------------------------------------------------+
//| Get current ask value                                            |
//+------------------------------------------------------------------+
double Ask()
{
    return (SymbolInfoDouble(Symbol(), SYMBOL_ASK));
}

//+------------------------------------------------------------------+
//| Is there an error                                                |
//+------------------------------------------------------------------+
bool IsError(MqlTradeResult& result, string function)
{
    if (result.retcode != 0 && result.retcode != TRADE_RETCODE_DONE && result.retcode != TRADE_RETCODE_PLACED)
    {
        Print("Function: ", function, " Error: ", result.retcode, " ", result.comment);
        return (true);
    }
    else
    Print("> Executed: [", function, "]");
    return (false);
}

bool IsError(CTrade& trade, string function)
{
    if (trade.ResultRetcode() != 0 && trade.ResultRetcode() != TRADE_RETCODE_DONE && trade.ResultRetcode() != TRADE_RETCODE_PLACED)
    {
        Print("Function: ", function, " Error: ", trade.ResultRetcode(), " ", trade.ResultRetcodeDescription());
        return (true);
    }
    else
    Print("> Executed: [", function, "]");
    return (false);
}

//+------------------------------------------------------------------+
//| Get indicator value back                                         |
//+------------------------------------------------------------------+
double GetIndicator(int handle, int buffer_num, int index)
{
    //--- array for the indicator values
    double arr[];    
    //--- obtain the indicator value in the last two bars
    if (CopyBuffer(handle, buffer_num, 0, index+1, arr) <= 0)
    {        
        Sleep(200);
        for(int i=0; i<100; i++)
        {
            if (BarsCalculated(handle) > 0)
            break;
            Sleep(50);
        }
        int copied = CopyBuffer(handle, buffer_num, 0, index+1, arr);
        if (copied <= 0)
        {
            Print("CopyBuffer failed. Maybe history has not download yet? Error = ", GetLastError());
            return -1;
        }
        else
        return (arr[index]);
    }
    else
    {
        return (arr[index]);
    }
    
    return 0;
}

//+------------------------------------------------------------------+
//| Building blocks                                                  |
//+------------------------------------------------------------------+
void OnEveryTick()
{
    
    if (NDigits == 3 || NDigits == 5) PipValue = 10;
    
    WeekdayFilter();
    
}

void WeekdayFilter()
{
    
    MqlDateTime currTime;
    TimeLocal(currTime);
    int weekday = currTime.day_of_week;
    if ((Monday && weekday == 1) || (Tuesday && weekday == 2) || (Wednesday && weekday == 3) ||
    (Thursday && weekday == 4) || (Friday && weekday == 5) || (Saturday && weekday == 6) || (Sunday && weekday == 0))
    {
        HoursFilter();
        
    }
}

void HoursFilter()
{
    
    MqlDateTime currTime;
    TimeLocal(currTime);
    int hour0 = currTime.hour;
    if ((HoursFrom < HoursTo && hour0 >= HoursFrom && hour0 < HoursTo) ||
    (HoursFrom > HoursTo && (hour0 < HoursTo || hour0 >= HoursFrom)))
    {
        SpreadFilter();
        
    }
}

void SpreadFilter()
{
    if (SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/PipValue < MaxSpread)
    {
        TechnicalAnalysis();
      
        
    }
}

void TechnicalAnalysis()
{
    
    if (GetIndicator(handle1,1,current) > 0)
    {
        TechnicalAnalysis();
        
    }
}

void TechnicalAnalysis2()
{
    
    if ((GetIndicator(handle2,1,current) > 0) && (GetIndicator(handle2,1,current+1) < 0))
    {
        IfPositionDoesNotExist();
        
    }
}

void IfPositionDoesNotExist()
{
    
    bool exists = false;
    
    // go through all positions
    for (int i=PositionsTotal()-1;i>=0;i--)
    {
        if (PositionSelect(Symbol()))
        // position with appropriate ORDER_MAGIC, symbol and order type
        if (PositionGetInteger(POSITION_MAGIC) == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
        exists = true;
    }
    
    if (exists == false)
    {
        BuyOrderFlex();
        
    }
}

void BuyOrderFlex()
{
    
    //--- prepare a request
    MqlTradeRequest request={0};
    MqlTradeResult  result={0};
    request.action = TRADE_ACTION_DEAL;          // setting a deal order
    request.magic = 1;                   // ORDER_MAGIC
    request.symbol = Symbol();                   // symbol
    request.volume= Lots;                      // volume in lots
    request.price = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
    request.sl = Low(current+1);                     // Stop Loss specified
    request.tp = 250;                   // Take Profit specified
    request.deviation= Deviation;             // deviation in 5 points
    request.type = ORDER_TYPE_BUY;
    request.comment = "Order";
    
    
    if(!OrderSend(request,result))
      PrintFormat("OrderSend error %d",GetLastError());     // if unable to send the request, output the error code
}

void TechnicalAnalysis3()
{
    
    if (GetIndicator(handle1,1,current) < 0)
    {
        TechnicalAnalysis2();
        
    }
}

void TechnicalAnalysis4()
{
    
    if ((GetIndicator(handle2,1,current) < 0) && (GetIndicator(handle2,1,current+1) > 0))
    {
        IfPositionDoesNotExist2();
        
    }
}

void IfPositionDoesNotExist2()
{
    
    bool exists = false;
    
    // go through all positions
    for (int i=PositionsTotal()-1;i>=0;i--)
    {
        if (PositionSelect(Symbol()))
        // position with appropriate ORDER_MAGIC, symbol and order type
        if (PositionGetInteger(POSITION_MAGIC) == 1 && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
        exists = true;
    }
    
    if (exists == false)
    {
        SellOrderFlex();
        
    }
}

void SellOrderFlex()
{
    
    //--- prepare a request
    MqlTradeRequest request={0};
    MqlTradeResult  result={0};
    request.action = TRADE_ACTION_DEAL;          // setting a deal order
    request.magic = 1;                   // ORDER_MAGIC
    request.symbol = Symbol();                   // symbol
    request.volume= Lots;                      // volume in lots
    request.price = SymbolInfoDouble(Symbol(),SYMBOL_BID);
    request.sl = High(current+1);                     // Stop Loss specified
    request.tp = 250;                   // Take Profit specified
    request.deviation= Deviation;             // deviation in 5 points
    request.type = ORDER_TYPE_SELL;
    request.comment = "Order";
    
   
    // check the result
  if(!OrderSend(request,result))
      PrintFormat("OrderSend error %d",GetLastError()); 
}


 
void TechnicalAnalysis()
{
    
    if (GetIndicator(handle1,1,current) > 0)
    {
        TechnicalAnalysis();  // <--- Shouldn't here be TechnicalAnalysis2()
        
    }
}
Above function calls itself.
 
Drazen Penic:
Above function calls itself.
Hi Drazen,

thanks for your quick reply. Yes thats solve the error problem!

Do u have any idea why it doenst open any trades? Based on the indicator seetings it should?! Its a simple logic -> check H4 if H4 is positive and H1 gives a buy signal = buy (vice verca)

Thansk in advance,
Max
 

I have no idea why it doesn't work. 

You should check if you read correct values from the indicators, and if you do, check if your decision making logic is correct.

Add series of Print() statements in your code and print out values from the indicator and decision making code and/or run it through debugger using history data.

 

The best way is to watch Journal.

I had Critical Error ... it makes me crazy

but Journal exactly indicate for you what is the error source.

 
Drazen Penic:

I have no idea why it doesn't work. 

You should check if you read correct values from the indicators, and if you do, check if your decision making logic is correct.

Add series of Print() statements in your code and print out values from the indicator and decision making code and/or run it through debugger using history data.

I think you were right with the indicator values. I didnt use the iCustom function in a correct way, but now I have a CopyBuffer error, becasue I changed the iCustom function to:
handle1 = iCustom(NULL, PERIOD_H4, "Kalman velocity (mtf)","Current time frame",1,PRICE_CLOSE,"Interpolate data when in multi time frame");
    handle2 = iCustom(NULL, PERIOD_CURRENT, "Kalman velocity (mtf)","Current time frame",1,PRICE_CLOSE,"Interpolate data when in multi time frame");
The CopyBuffer error comes from this part of the code, but the history is there:

double GetIndicator(int handle, int buffer_num, int index)
{
    //--- array for the indicator values
    double arr[];    
    //--- obtain the indicator value in the last two bars
    if (CopyBuffer(handle, buffer_num, 0, index+1, arr) <= 0)
    {        
        Sleep(200);
        for(int i=0; i<100; i++)
        {
            if (BarsCalculated(handle) > 0)
            break;
            Sleep(50);
        }
        int copied = CopyBuffer(handle, buffer_num, 0, index+1, arr);
        if (copied <= 0)
        {
            Print("CopyBuffer failed. Maybe history has not download yet? Error = ", GetLastError());
            return -1;
        }
        else
        return (arr[index]);
    }
    else
    {
        return (arr[index]);
    }
    
    return 0;
}


 I could not find a possible solution so far. Any tips how to solve/adjust it?


Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
  • www.mql5.com
//| Expert initialization function                                   | //| Expert deinitialization function                                 | //| Expert tick function                                             | //| test1                                                            |...
 
Maximilian Goldbecker:
I think you were right with the indicator values. I didnt use the iCustom function in a correct way, but now I have a CopyBuffer error, becasue I changed the iCustom function to: The CopyBuffer error comes from this part of the code:


 I could not find a possible solution so far. Any tips how to solve/adjust it?



What error? 

 
Drazen Penic:


What error? 

2020.05.20 17:24:58.000    Core 1    2019.04.18 18:14:52   CopyBuffer failed. Maybe history has not download yet? Error = 4807
 
Maximilian Goldbecker:
2020.05.20 17:24:58.000    Core 1    2019.04.18 18:14:52   CopyBuffer failed. Maybe history has not download yet? Error = 4807

From the documentation:

ERR_INDICATOR_WRONG_HANDLE

4807

Wrong indicator handle


You probably have an error in iCustom() call.

Check if handle is INVALID_HANDLE. Read documentation on iCustom()

Documentation on MQL5: Technical Indicators / iCustom
Documentation on MQL5: Technical Indicators / iCustom
  • www.mql5.com
[in]  The name of the custom indicator, with path relative to the root directory of indicators (MQL5/Indicators/). If an indicator is located in a subdirectory, for example, in MQL5/Indicators/ [in] input-parameters of a custom indicator, separated by commas. Type and order of parameters must match. If there is no parameters specified, then...
 
Drazen Penic:

From the documentation:

ERR_INDICATOR_WRONG_HANDLE

4807

Wrong indicator handle


You probably have an error in iCustom() call.

Check if handle is INVALID_HANDLE. Read documentation on iCustom()

I solved the iCustom call I think, but I have another idea why there is no trade at all:

double GetIndicator(int handle, int buffer_num, int index)
{
    //--- array for the indicator values
    double arr[];    
    //--- obtain the indicator value in the last two bars
    if (CopyBuffer(handle, buffer_num, 0, index+1, arr) <= 0)
    {        
        Sleep(200);
        for(int i=0; i<100; i++)
        {
            if (BarsCalculated(handle) > 0)
            break;
            Sleep(50);
        }
        int copied = CopyBuffer(handle, buffer_num, 0, index+1, arr);
        if (copied <= 0)
        {
            Print("CopyBuffer failed. Maybe history has not download yet? Error = ", GetLastError());
            return -1;
        }
        else
        return (arr[index]);
    }
    else
    {
        return (arr[index]);
    }
    
    return 0;
}

Maybe because it calls only handle and not a specific one, because I have 2 handles (H1 and H4).

Could that be the reason?

 

You created handles for the H4 and current (presumably not H4) timeframe.

  • your code calls GetIndicator() with value of the index variable set to "current" and "current+1"
  • variable current is set to 0 and I didn't find any place where it is modified
  • that means that you read current value on H4 timeframe and value of the previous bar on the current timeframe
  • Is that what you want?

  • For debugging purposes, print value of the arr[index] before you return it and check if you got the value you expected
  • Check that you read all values from the same end - check that you consistently use xxxAsSeries() functions
If you don't plan to modify variable "current", define local variables in functions where you use it. Or define global constant. Anyway, don't use global variable for something that can be defined locally.
Reason: