ADX_BtcUsd does not close positions based on +DI and -DI reversal

 
//+------------------------------------------------------------------+
//|                                                      ADX_BtcUsd.mq4 |
//|                Expert Advisor per Trading con ADX e RSI           |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023"
#property link      ""
#property version   "1.20"
#property strict

// Input dell'utente
input int    MAPeriod             = 8;               // Periodo della Media Mobile (se desiderato per altre analisi)
input double LotSize              = 1.5;             // Dimensione del lotto
input double DI_Perc_Threshold_Open_BUY = 40.0;      // Percentuale di differenza per apertura posizione BUY
input double DI_Perc_Threshold_Open_SELL = 60.0;     // Percentuale di differenza per apertura posizione SELL

int candlesSinceOpen = 0;  // Variabile globale per contare le candele dalla posizione aperta
input double ADX_Threshold = 5;  // Soglia minima dell'ADX per aprire una posizione
double previousPlusDI = 0;  // Memorizza il valore precedente di +DI
double previousMinusDI = 0; // Memorizza il valore precedente di -DI
bool isFirstCandle = true;   // Flag per verificare la prima candela

// Struttura per memorizzare i dati della posizione corrente
struct PositionData
{
   int      ticket;
   datetime openTime;
   double   initialSL;
   double   highestHigh;
   double   lowestLow;
};

PositionData currentPosition;
datetime       lastCandleTime;

//+------------------------------------------------------------------+
//| Funzione di inizializzazione                                     |
//+------------------------------------------------------------------+
int OnInit()
{
   currentPosition.ticket = -1;
   lastCandleTime = 0;
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Funzione di deinizializzazione                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Print("EA disattivato. Motivo: ", reason);
}

//+------------------------------------------------------------------+
//| Funzione chiamata ad ogni tick                                   |
//+------------------------------------------------------------------+
void OnTick()
{
   if(IsNewCandle())  // Verifica se è una nuova candela
   {
      // Ottieni i valori ADX, +DI, -DI e RSI
      double adx = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_MAIN, 1);  // ADX
      double plusDI = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_PLUSDI, 1);  // +DI
      double minusDI = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_MINUSDI, 1); // -DI
      double rsi = iRSI(Symbol(), 0, 14, PRICE_CLOSE, 1);  // RSI

      // Stampa i valori di ADX, +DI, -DI, e RSI
      Print("Nuova candela rilevata. Valori attuali: ADX = ", adx, ", +DI = ", plusDI, ", -DI = ", minusDI, ", RSI = ", rsi);

      // Log dei valori precedenti di +DI e -DI (solo dopo la prima candela)
      if (!isFirstCandle) {
         Print("Candele precedenti: +DI = ", previousPlusDI, ", -DI = ", previousMinusDI);
         
         // Confronto dei valori precedenti e attuali di +DI e -DI
         if (plusDI > previousPlusDI)
            Print("Cambiamento +DI: aumentato");
         else if (plusDI < previousPlusDI)
            Print("Cambiamento +DI: diminuito");
         else
            Print("Cambiamento +DI: invariato");
         
         if (minusDI > previousMinusDI)
            Print("Cambiamento -DI: aumentato");
         else if (minusDI < previousMinusDI)
            Print("Cambiamento -DI: diminuito");
         else
            Print("Cambiamento -DI: invariato");
      }
      
      // Salva i valori attuali di +DI e -DI come precedenti per la prossima candela
      previousPlusDI = plusDI;
      previousMinusDI = minusDI;
      
      // Imposta isFirstCandle a false dopo la prima candela
      isFirstCandle = false;
      
      // Incrementa il contatore delle candele dalla posizione aperta
      if(currentPosition.ticket != -1)
         candlesSinceOpen++;
      
      // Gestione delle posizioni aperte (chiusura in base al pattern opposto)
      ManageOpenPositions();
      
      // Analisi e apertura nuove posizioni (se le condizioni sono soddisfatte)
      AnalyzePatterns();  
   }
}


//+------------------------------------------------------------------+
//| Funzione per verificare se è una nuova candela                   |
//+------------------------------------------------------------------+
bool IsNewCandle()
{
   datetime currentCandleTime = iTime(Symbol(), PERIOD_M1, 0);  // Ottieni il timestamp della candela corrente
   if(currentCandleTime != lastCandleTime)  // Se è cambiato il timestamp, è una nuova candela
   {
      lastCandleTime = currentCandleTime;
      return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//| Funzione per verificare se ci sono posizioni aperte              |
//+------------------------------------------------------------------+
bool IsPositionOpen()
{
    bool positionFound = false;
    for (int i = 0; i < OrdersTotal(); i++)
    {
        if (OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == Symbol() && (OrderType() == OP_BUY || OrderType() == OP_SELL))
        {
            positionFound = true; // Trovata una posizione aperta (manuale o automatica)
            Print("Posizione aperta trovata: ", "Ticket = ", OrderTicket(), ", Tipo = ", (OrderType() == OP_BUY ? "BUY" : "SELL"));
        }
    }
    if (!positionFound) {
        Print("Nessuna posizione aperta per ", Symbol());
    }
    return positionFound; // Restituisce true se una posizione è aperta, altrimenti false
}
//+------------------------------------------------------------------+
//| Funzione per analizzare e aprire le posizioni                    |
//+------------------------------------------------------------------+
void AnalyzePatterns()
{
   // Se c'è già una posizione aperta, non aprire una nuova posizione
   if (IsPositionOpen())  // Verifica se ci sono posizioni aperte
   {
      Print("Non apro posizione BUY o SELL perché è già aperta una posizione.");
      return;  // Esci dalla funzione se c'è una posizione aperta
   }

   // Ottieni i valori di ADX, +DI, -DI e RSI
   double adx = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_MAIN, 1);  // ADX
   double plusDI = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_PLUSDI, 1);  // +DI
   double minusDI = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_MINUSDI, 1); // -DI
   double rsi = iRSI(Symbol(), 0, 14, PRICE_CLOSE, 1);  // RSI

   // Verifica se l'ADX è sopra la soglia
   if (adx <= ADX_Threshold)
   {
      Print("ADX (", adx, ") è inferiore o uguale alla soglia (", ADX_Threshold, "). Valori attuali: +DI = ", plusDI, ", -DI = ", minusDI, ", RSI = ", rsi, ". Nessuna posizione aperta.");
      return;  // Esci dalla funzione se l'ADX non è sopra la soglia
   }

   // Verifica se l'RSI è compreso tra 45 e 55
   if (rsi < 45 || rsi > 55)
   {
      Print("RSI (", rsi, ") non è compreso tra 45 e 55. Valori attuali: +DI = ", plusDI, ", -DI = ", minusDI, ", ADX = ", adx, ". Nessuna posizione aperta.");
      return;  // Esci dalla funzione se l'RSI non è nel range
   }

   // Logica per apertura BUY
   if (plusDI > minusDI * (1 + DI_Perc_Threshold_Open_BUY / 100))
   {
      OpenBuyPosition();
   }
   // Logica per apertura SELL
   else if (minusDI > plusDI * (1 + DI_Perc_Threshold_Open_SELL / 100))
   {
      OpenSellPosition();
   }
}

// Funzione per aprire una posizione BUY
void OpenBuyPosition()
{
   double tickSize = MarketInfo(Symbol(), MODE_POINT);  // Ottieni la dimensione del tick
   
   // Imposta una distanza minima di 38000 ticks dal prezzo di mercato
   double distanceInPoints = 38000 * tickSize;  // Impostiamo la distanza minima di 38000 ticks dal prezzo
   double sl = Ask - distanceInPoints;  // SL sotto il prezzo di mercato
   double tp = Ask + distanceInPoints;  // TP sopra il prezzo di mercato
   
   // Controlla che SL e TP non siano troppo lontani dal prezzo di mercato
   if (sl <= 0 || tp <= 0)
   {
      Print("Errore: SL o TP non validi (<= 0).");
      return; // Esci dalla funzione se SL o TP non sono validi
   }

   // Controlla la quantità del lotto
   double minLot = MarketInfo(Symbol(), MODE_MINLOT);
   double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   
   if (LotSize < minLot || LotSize > maxLot)
   {
      Print("Errore: LotSize non valido. Minimo: ", minLot, " Massimo: ", maxLot, " Step: ", lotStep);
      return; // Esci dalla funzione se LotSize non è valido
   }

   int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp, "Buy Position", 0, 0, clrGreen);
   
   // Debug: stampa il ticket
   if(ticket < 0)
   {
      int errorCode = GetLastError();
      Print("Errore nell'aprire la posizione BUY. Codice errore: ", errorCode);
      
      // Mostra l'errore con maggiori dettagli
      if (errorCode == 130)
      {
         Print("L'errore 130 potrebbe essere causato da SL o TP troppo vicini al prezzo di mercato.");
      }
   }
   else
   {
      currentPosition.ticket = ticket;
      currentPosition.openTime = TimeCurrent();
      currentPosition.initialSL = sl;
      currentPosition.highestHigh = High[0];
      currentPosition.lowestLow = Low[0];
      Print("Posizione BUY aperta con ticket: ", ticket);
   }
}

// Funzione per aprire una posizione SELL
void OpenSellPosition()
{
   double tickSize = MarketInfo(Symbol(), MODE_POINT);  // Ottieni la dimensione del tick
   
   // Imposta una distanza minima di 38000 ticks dal prezzo di mercato
   double distanceInPoints = 38000 * tickSize;  // Impostiamo la distanza minima di 38000 ticks dal prezzo
   double sl = Bid + distanceInPoints;  // SL sopra il prezzo di mercato
   double tp = Bid - distanceInPoints;  // TP sotto il prezzo di mercato
   
   // Controlla che SL e TP non siano troppo lontani dal prezzo di mercato
   if (sl <= 0 || tp <= 0)
   {
      Print("Errore: SL o TP non validi (<= 0).");
      return; // Esci dalla funzione se SL o TP non sono validi
   }

   // Controlla la quantità del lotto
   double minLot = MarketInfo(Symbol(), MODE_MINLOT);
   double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   
   if (LotSize < minLot || LotSize > maxLot)
   {
      Print("Errore: LotSize non valido. Minimo: ", minLot, " Massimo: ", maxLot, " Step: ", lotStep);
      return; // Esci dalla funzione se LotSize non è valido
   }

   int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp, "Sell Position", 0, 0, clrRed);
   
   // Debug: stampa il ticket
   if(ticket < 0)
   {
      int errorCode = GetLastError();
      Print("Errore nell'aprire la posizione SELL. Codice errore: ", errorCode);
   }
   else
   {
      currentPosition.ticket = ticket;
      currentPosition.openTime = TimeCurrent();
      currentPosition.initialSL = sl;
      currentPosition.highestHigh = High[0];
      currentPosition.lowestLow = Low[0];
      Print("Posizione SELL aperta con ticket: ", ticket);
   }
}
//+------------------------------------------------------------------+
// Funzione per gestire le posizioni aperte
//+------------------------------------------------------------------+
void ManageOpenPositions()
{
    // Se c'è una posizione aperta, verifica se deve essere chiusa
    if (currentPosition.ticket != -1)
    {
        // Log prima di tentare di chiudere la posizione
        Print("Tentativo di chiudere la posizione. Ticket: ", currentPosition.ticket);
        
        // Verifica e chiudi la posizione se l'inversione del pattern è rilevata
        ClosePositionIfInverted(); 
    }
}

//+------------------------------------------------------------------+
//| Funzione per gestire la chiusura delle posizioni                 |
//+------------------------------------------------------------------+
void ClosePosition()
{
   // Seleziona l'ordine
   if (OrderSelect(currentPosition.ticket, SELECT_BY_TICKET))  // Seleziona il ticket della posizione aperta
   {
      // Debug: mostra il tipo di ordine selezionato
      Print("Ordine selezionato correttamente. Tipo di ordine: ", OrderType(), ", Ticket: ", OrderTicket());

      // Verifica il tipo di ordine (BUY o SELL)
      if(OrderType() == OP_BUY)
      {
         double closePrice = Bid; // Prezzo di chiusura per BUY
         if(OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrNONE))
         {
            Print("Posizione BUY chiusa. Ticket: ", OrderTicket());
            currentPosition.ticket = -1; // Reset del ticket della posizione
         }
         else
         {
            Print("Errore nella chiusura della posizione BUY. Codice errore: ", GetLastError());
         }
      }
      else if(OrderType() == OP_SELL)
      {
         double closePrice = Ask; // Prezzo di chiusura per SELL
         if(OrderClose(OrderTicket(), OrderLots(), closePrice, 3, clrNONE))
         {
            Print("Posizione SELL chiusa. Ticket: ", OrderTicket());
            currentPosition.ticket = -1; // Reset del ticket della posizione
         }
         else
         {
            Print("Errore nella chiusura della posizione SELL. Codice errore: ", GetLastError());
         }
      }
   }
   else
   {
      Print("Errore: Impossibile selezionare l'ordine. Codice errore: ", GetLastError());
   }
}

//+------------------------------------------------------------------+
// Funzione per gestire la chiusura delle posizioni se viene rilevata un'inversione
//+------------------------------------------------------------------+
void ClosePositionIfInverted()
{
    // Ottieni i valori attuali di +DI e -DI
    double currentPlusDI = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_PLUSDI, 0);  // +DI attuale
    double currentMinusDI = iADX(Symbol(), 0, 14, PRICE_CLOSE, MODE_MINUSDI, 0); // -DI attuale

    // Log per monitorare i valori di +DI e -DI
    Print("Controllo inversione. Valori attuali: +DI = ", currentPlusDI, ", -DI = ", currentMinusDI);
    Print("Valori precedenti: +DI = ", previousPlusDI, ", -DI = ", previousMinusDI);

    // Verifica se una posizione è aperta
    if (currentPosition.ticket != -1) // Se una posizione è aperta
    {
        // Seleziona l'ordine
        if (OrderSelect(currentPosition.ticket, SELECT_BY_TICKET))
        {
            // Verifica se la posizione è una SELL
            if (OrderType() == OP_SELL)
            {
                // Condizione per chiudere la posizione SELL: +DI aumenta e -DI diminuisce
                if (currentPlusDI > previousPlusDI && currentMinusDI < previousMinusDI)
                {
                    Print("Inversione del pattern SELL rilevata. Chiudo la posizione SELL.");
                    Print("Prezzo di chiusura SELL: ", Bid);
                    ClosePosition(); // Chiude la posizione SELL
                }
                else
                {
                    Print("Condizione di inversione SELL non soddisfatta. +DI = ", currentPlusDI, ", -DI = ", currentMinusDI);
                }
            }
            // Verifica se la posizione è una BUY
            else if (OrderType() == OP_BUY)
            {
                // Condizione per chiudere la posizione BUY: +DI diminuisce e -DI aumenta
                if (currentPlusDI < previousPlusDI && currentMinusDI > previousMinusDI)
                {
                    Print("Inversione del pattern BUY rilevata. Chiudo la posizione BUY.");
                    Print("Prezzo di chiusura BUY: ", Ask);
                    ClosePosition(); // Chiude la posizione BUY
                }
                else
                {
                    Print("Condizione di inversione BUY non soddisfatta. +DI = ", currentPlusDI, ", -DI = ", currentMinusDI);
                }
            }
            else
            {
                // Debug: Se non riesce a selezionare l'ordine
                Print("Errore nella selezione dell'ordine. Codice errore: ", GetLastError());
            }
        }
        else
        {
            // Se non riesce a selezionare la posizione
            Print("Errore nella selezione della posizione aperta. Codice errore: ", GetLastError());
        }
    }
    else
    {
        // Debug: Se non c'è una posizione aperta
        Print("Nessuna posizione aperta per eseguire la chiusura.");
    }

    // Salva i valori attuali di +DI e -DI come precedenti per la prossima candela
    previousPlusDI = currentPlusDI;
    previousMinusDI = currentMinusDI;
}
Files:
ADX.mq4  34 kb
 

this code opens positions correctly but does not close them based on:

//+------------------------------------------------------------------+
// Function to manage the closing of positions if a reversal is detected
//+------------------------------------------------------------------+
void ClosePositionIfInverted(). 
From the logs generated on mediatrader 4 the current and previous values ​​of +DI and -DI of the current candle just closed and the previous one are calculated correctly and yet the problem persists and I have not been able to solve it for several days. I am looking for opinions regarding the resolution of this bug in my ea
 

Your code seems to have AI-generated elements, so it cannot be helped (would need considerable human review/corrections before being usable in a live trading environment).

NOTE: this forum primarily operates in English (your commenting in Italian adds another layer of complexity).

 
Oleksandr Medviediev #:

Your code seems to have AI-generated elements, so it cannot be helped (would need considerable human review/corrections before being usable in a live trading environment).

NOTE: this forum primarily operates in English (your commenting in Italian adds another layer of complexity).

ok, I resolved bug by myself