Need Help with MQL5 Robot - Orders Not Triggering Despite Conditions Being Met

 

Hi everyone,

I'm new to programming in MQL5, and I'm trying to create a simple trading robot for the Brazilian market (mini index). My strategy is straightforward, but I’ve been running into issues where the robot doesn't open orders even when the conditions are met. I’d appreciate some guidance!

Here’s the strategy:

  • Buy conditions:

    1. Buy every time the fast moving average (5) crosses the two slow ones (75, 85) from bottom to top and the MACD switches from negative to positive on the current candle or any of the next 3 candles.
    2. Buy every time the MACD switches from negative to positive and the fast moving average crosses the slow ones (75, 85) from bottom to top in the same candle or any of the next 3 candles.
  • Sell conditions:

    1. Sell every time the fast moving average (5) crosses the two slow ones (75, 85) from top to bottom and the MACD switches from positive to negative on the current candle or any of the next 3 candles.
    2. Sell every time the MACD switches from positive to negative and the fast moving average crosses the slow ones (75, 85) from top to bottom in the same candle or any of the next 3 candles.

Extra Rules:

  • No buy or sell orders are executed if any of the last 3 candles is equal to or higher than 150 points.
  • If the MACD switches from positive to negative (or vice versa) during an open order, the order should close immediately.
  • If the moving averages cross in the opposite direction during an open order, the order should close immediately.
  • The robot only works from 10 a.m. to 5 p.m.

Indicator values:

  • Fast Moving Average: 5
  • Slow Moving Averages: 75 and 85
  • MACD: 15.26.1

The Problem:
When I run the robot, no orders are being executed, even though the conditions appear to be met. I’ve double-checked my code and the conditions, but I can’t figure out what’s wrong.

Has anyone encountered a similar issue or have tips on debugging this kind of problem? Could it be an issue with how I’m checking the conditions or something else?

Here is the code (comments are in portuguese lmk if you need translation):

//+------------------------------------------------------------------+
//|                                                Jaraxxus.mq5 |
//|                                       Desenvolvido por Maxxam71 |
//+------------------------------------------------------------------+
#property copyright ""
#property link      ""
#property version   "1.04"
#property strict

// Definir o enumerador para o MACD
enum ENUM_MACD_MODE
{
   MACD_MAIN=0,      // Linha principal do MACD
   MACD_SIGNAL=1,    // Linha de sinal
   MACD_HISTOGRAM=2  // Histograma
};

// Definição dos parâmetros de entrada
input double Lots = 1.0;                   // Tamanho do lote
input int    TakeProfitPoints = 100;       // Take Profit em pontos
input int    StopLossPoints = 100;         // Stop Loss em pontos
input int    MagicNumber = 123456;         // Número mágico para identificar as ordens

// Variáveis globais
double maFast[], maSlow1[], maSlow2[];
double macdMain[];
datetime lastTradeTime;

//+------------------------------------------------------------------+
//| Função de inicialização                                          |
//+------------------------------------------------------------------+
int OnInit()
{
    // Nenhum código necessário aqui para este EA
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Função principal                                                 |
//+------------------------------------------------------------------+
void OnTick()
{
    // Verifica se está dentro do horário de operação
    if(!IsTradeTime())
        return;

    // Verifica se há novos ticks
    static datetime lastTime = 0;
    datetime currentTime = iTime(_Symbol, PERIOD_CURRENT, 0);
    if(lastTime == currentTime)
        return;
    lastTime = currentTime;

    // Calcula os indicadores
    CalculateIndicators();

    // Verifica as condições de entrada
    CheckForOpen();

    // Verifica as condições de saída
    CheckForClose();
}

//+------------------------------------------------------------------+
//| Função para verificar se está no horário de operação             |
//+------------------------------------------------------------------+
bool IsTradeTime()
{
    datetime currentTime = TimeCurrent();
    MqlDateTime tm;
    TimeToStruct(currentTime, tm);
    int hour = tm.hour;

    // Verifica se o horário está entre 11:00 e 17:00
    if(hour >= 11 && hour < 17)
        return true;
    else
        return false;
}

//+------------------------------------------------------------------+
//| Função para calcular os indicadores                              |
//+------------------------------------------------------------------+
void CalculateIndicators()
{
    // Calcula as médias móveis
    ArraySetAsSeries(maFast, true);
    ArraySetAsSeries(maSlow1, true);
    ArraySetAsSeries(maSlow2, true);

    CopyBuffer(iMA(_Symbol, PERIOD_CURRENT, 5, 0, MODE_EMA, PRICE_CLOSE), 0, 0, 10, maFast);
    CopyBuffer(iMA(_Symbol, PERIOD_CURRENT, 75, 0, MODE_EMA, PRICE_CLOSE), 0, 0, 10, maSlow1);
    CopyBuffer(iMA(_Symbol, PERIOD_CURRENT, 85, 0, MODE_EMA, PRICE_CLOSE), 0, 0, 10, maSlow2);

    // Calcula o MACD
    ArraySetAsSeries(macdMain, true);

    CopyBuffer(iMACD(_Symbol, PERIOD_CURRENT, 15, 25, 1, PRICE_CLOSE), MACD_MAIN, 0, 10, macdMain);
}

//+------------------------------------------------------------------+
//| Função para verificar as condições de abertura de posição        |
//+------------------------------------------------------------------+
void CheckForOpen()
{
    // Não abre novas posições se alguma das últimas 3 velas tiver mais de 150 pontos
    if(IsBigCandle())
        return;

    // Verifica se já existe uma posição aberta
    if(PositionSelect(_Symbol))
        return;

    // Verifica condições de compra
    if(BuyCondition())
    {
        OpenPosition(ORDER_TYPE_BUY);
        return;
    }

    // Verifica condições de venda
    if(SellCondition())
    {
        OpenPosition(ORDER_TYPE_SELL);
        return;
    }
}

//+------------------------------------------------------------------+
//| Função para verificar as condições de fechamento de posição      |
//+------------------------------------------------------------------+
void CheckForClose()
{
    if(PositionSelect(_Symbol))
    {
        ulong ticket = PositionGetInteger(POSITION_TICKET);
        ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

        // Fecha a posição se o MACD inverter sinal
        if(MacdSignalChanged(positionType))
        {
            Print("Fechando posição devido à inversão do MACD.");
            ClosePosition(ticket);
            return;
        }

        // Fecha a posição se as médias cruzarem em direção oposta
        if(MaCrossOpposite(positionType))
        {
            Print("Fechando posição devido ao cruzamento das médias em direção oposta.");
            ClosePosition(ticket);
            return;
        }
    }
}

//+------------------------------------------------------------------+
//| Função para verificar condição de compra                         |
//+------------------------------------------------------------------+
bool BuyCondition()
{
    // Verifica o cruzamento das médias
    if(MaCrossUp())
    {
        // Verifica se o MACD mudou de negativo para positivo nas últimas 3 velas
        if(MacdChangedToPositive())
            return true;
    }

    // Verifica se o MACD mudou de negativo para positivo
    if(MacdChangedToPositive())
    {
        // Verifica se as médias cruzaram de baixo para cima nas últimas 3 velas
        if(MaCrossUp())
            return true;
    }

    return false;
}

//+------------------------------------------------------------------+
//| Função para verificar condição de venda                          |
//+------------------------------------------------------------------+
bool SellCondition()
{
    // Verifica o cruzamento das médias
    if(MaCrossDown())
    {
        // Verifica se o MACD mudou de positivo para negativo nas últimas 3 velas
        if(MacdChangedToNegative())
            return true;
    }

    // Verifica se o MACD mudou de positivo para negativo
    if(MacdChangedToNegative())
    {
        // Verifica se as médias cruzaram de cima para baixo nas últimas 3 velas
        if(MaCrossDown())
            return true;
    }

    return false;
}

//+------------------------------------------------------------------+
//| Função para abrir posição                                        |
//+------------------------------------------------------------------+
void OpenPosition(int type)
{
    MqlTradeRequest request;
    MqlTradeResult result;
    ZeroMemory(request);
    ZeroMemory(result);

    request.action = TRADE_ACTION_DEAL;
    request.magic = MagicNumber;
    request.symbol = _Symbol;
    request.volume = Lots;
    request.type = type;
    request.type_filling = ORDER_FILLING_IOC; // Ajuste conforme o broker
    request.deviation = 10;

    // Preço da ordem
    double price = SymbolInfoDouble(_Symbol, (type == ORDER_TYPE_BUY) ? SYMBOL_ASK : SYMBOL_BID);
    request.price = price;

    if(!OrderSend(request, result))
    {
        PrintFormat("Erro ao abrir posição: %d", GetLastError());
    }
    else
    {
        lastTradeTime = TimeCurrent();
        PrintFormat("Posição aberta com sucesso. Ticket: %I64d", result.order);

        // Definir SL e TP após a abertura da posição
        SetPositionSLTP(result.order, type);
    }
}

//+------------------------------------------------------------------+
//| Função para definir SL e TP após a abertura da posição           |
//+------------------------------------------------------------------+
void SetPositionSLTP(ulong positionTicket, int type)
{
    // Obter detalhes da posição
    if(!PositionSelectByTicket(positionTicket))
    {
        PrintFormat("Erro ao selecionar posição: %d", GetLastError());
        return;
    }

    double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
    double sl, tp;

    // Verifique se _Point corresponde ao tamanho de ponto do ativo
    double pointSize = _Point;

    if(type == ORDER_TYPE_BUY)
    {
        sl = openPrice - StopLossPoints * pointSize;
        tp = openPrice + TakeProfitPoints * pointSize;
    }
    else
    {
        sl = openPrice + StopLossPoints * pointSize;
        tp = openPrice - TakeProfitPoints * pointSize;
    }

    sl = NormalizeDouble(sl, _Digits);
    tp = NormalizeDouble(tp, _Digits);

    MqlTradeRequest request;
    MqlTradeResult result;
    ZeroMemory(request);
    ZeroMemory(result);

    request.action = TRADE_ACTION_SLTP;
    request.position = positionTicket;
    request.symbol = _Symbol;
    request.sl = sl;
    request.tp = tp;
    request.magic = MagicNumber;

    if(!OrderSend(request, result))
    {
        PrintFormat("Erro ao modificar posição SL/TP: %d", GetLastError());
    }
    else
    {
        PrintFormat("SL e TP definidos para a posição Ticket: %I64d", positionTicket);
    }
}

//+------------------------------------------------------------------+
//| Função para fechar posição                                       |
//+------------------------------------------------------------------+
void ClosePosition(ulong ticket)
{
    MqlTradeRequest request;
    MqlTradeResult result;
    ZeroMemory(request);
    ZeroMemory(result);

    request.action = TRADE_ACTION_DEAL;
    request.position = ticket;
    request.symbol = _Symbol;
    request.volume = PositionGetDouble(POSITION_VOLUME);
    request.magic = MagicNumber;
    request.deviation = 10;
    request.type_filling = ORDER_FILLING_IOC; // Ajuste conforme o broker

    // Obter o tipo da posição
    ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

    // Determinar o tipo de ordem oposto para fechar a posição
    ENUM_ORDER_TYPE orderType;
    if(positionType == POSITION_TYPE_BUY)
        orderType = ORDER_TYPE_SELL;
    else if(positionType == POSITION_TYPE_SELL)
        orderType = ORDER_TYPE_BUY;
    else
        orderType = ORDER_TYPE_BUY; // Valor padrão

    request.type = orderType;

    // Obter o preço atual
    if(request.type == ORDER_TYPE_BUY)
        request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    else
        request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    if(!OrderSend(request, result))
    {
        PrintFormat("Erro ao fechar posição: %d", GetLastError());
    }
    else
    {
        PrintFormat("Posição fechada com sucesso. Ticket: %I64d", ticket);
    }
}

//+------------------------------------------------------------------+
//| Função para verificar cruzamento de médias de baixo para cima    |
//+------------------------------------------------------------------+
bool MaCrossUp()
{
    // Verifica cruzamento nas últimas 3 velas
    for(int i = 0; i <= 2; i++)
    {
        if(maFast[i+1] < maSlow1[i+1] && maFast[i+1] < maSlow2[i+1] && maFast[i] > maSlow1[i] && maFast[i] > maSlow2[i])
        {
            return true;
        }
    }
    return false;
}

//+------------------------------------------------------------------+
//| Função para verificar cruzamento de médias de cima para baixo    |
//+------------------------------------------------------------------+
bool MaCrossDown()
{
    // Verifica cruzamento nas últimas 3 velas
    for(int i = 0; i <= 2; i++)
    {
        if(maFast[i+1] > maSlow1[i+1] && maFast[i+1] > maSlow2[i+1] && maFast[i] < maSlow1[i] && maFast[i] < maSlow2[i])
        {
            return true;
        }
    }
    return false;
}

//+------------------------------------------------------------------+
//| Função para verificar se o MACD mudou de negativo para positivo  |
//+------------------------------------------------------------------+
bool MacdChangedToPositive()
{
    for(int i = 0; i <= 2; i++)
    {
        if(macdMain[i+1] < 0 && macdMain[i] > 0)
            return true;
    }
    return false;
}

//+------------------------------------------------------------------+
//| Função para verificar se o MACD mudou de positivo para negativo  |
//+------------------------------------------------------------------+
bool MacdChangedToNegative()
{
    for(int i = 0; i <= 2; i++)
    {
        if(macdMain[i+1] > 0 && macdMain[i] < 0)
            return true;
    }
    return false;
}

//+------------------------------------------------------------------+
//| Função para verificar se o MACD inverteu sinal na posição aberta |
//+------------------------------------------------------------------+
bool MacdSignalChanged(ENUM_POSITION_TYPE positionType)
{
    // Se posição é BUY, verifica se MACD mudou para negativo
    if(positionType == POSITION_TYPE_BUY && macdMain[0] < 0)
        return true;

    // Se posição é SELL, verifica se MACD mudou para positivo
    if(positionType == POSITION_TYPE_SELL && macdMain[0] > 0)
        return true;

    return false;
}

//+------------------------------------------------------------------+
//| Função para verificar se as MAs cruzaram em direção oposta       |
//+------------------------------------------------------------------+
bool MaCrossOpposite(ENUM_POSITION_TYPE positionType)
{
    if(positionType == POSITION_TYPE_BUY)
    {
        // Verifica se as MAs cruzaram de cima para baixo
        for(int i = 0; i <= 2; i++)
        {
            if(maFast[i+1] > maSlow1[i+1] && maFast[i+1] > maSlow2[i+1] && maFast[i] < maSlow1[i] && maFast[i] < maSlow2[i])
                return true;
        }
    }
    else if(positionType == POSITION_TYPE_SELL)
    {
        // Verifica se as MAs cruzaram de baixo para cima
        for(int i = 0; i <= 2; i++)
        {
            if(maFast[i+1] < maSlow1[i+1] && maFast[i+1] < maSlow2[i+1] && maFast[i] > maSlow1[i] && maFast[i] > maSlow2[i])
                return true;
        }
    }
    return false;
}

//+------------------------------------------------------------------+
//| Função para verificar se alguma das últimas 3 velas é grande     |
//+------------------------------------------------------------------+
bool IsBigCandle()
{
    for(int i = 1; i <= 3; i++)
    {
        double candleRange = MathAbs(iHigh(_Symbol, PERIOD_CURRENT, i) - iLow(_Symbol, PERIOD_CURRENT, i));
        if(candleRange >= 150 * _Point)
            return true;
    }
    return false;
}
 

I think the problem lies in the openposition function. I changed the parameter type to 

void OpenPosition(ENUM_ORDER_TYPE type)

and then changed your filling to 

    request.type_filling = ORDER_FILLING_FOK;

And then I managed to get some trades off from my tester.

Alternatively, I suggest you utilized the Trade.mqh file that is in the MetaEditor Include file, it saves a lot of work in terms of opening different position types.

You can refer to this discussion https://www.mql5.com/en/forum/338486

How to useTrade.mqh library in mql5?
How to useTrade.mqh library in mql5?
  • 2020.04.24
  • Yule Msee
  • www.mql5.com
#include CTrade trade; I am new to mql. I have seen the code above in *** but there are parts I do not understand...