Ulcer Expert not work! Can anyone help me?

 

I have been working on this simple expert for days, but it does not open any pending orders when you reach the preset levels BestLongPrice or BestShortPrice. Yet the logic is very simple. these values are set, you set whether the direction is long or short and set the entry and exit levels. the end. Is anyone kind enough to help me?

//+------------------------------------------------------------------+

//|                                                  Ulcer-Index.mq4 |

//|                                  Copyright 2024, Michele Guidoni |

//|                                  https://www.opinioniprodotto.it |

//+------------------------------------------------------------------+

#property strict



//+------------------------------------------------------------------+

//| Expert initialization function                                   |

//+------------------------------------------------------------------+



// Definizioni Variabili

input bool IsLong = true; // Direzione: true per Long, false per Short

input double BestLongPrice; // Livello prezzo migliore per Long

input double LongEntryLevel; // Livello di ingresso Long

input double LongTarget; // Target Long

input double BestShortPrice; // Livello prezzo migliore per Short

input double ShortEntryLevel; // Livello di ingresso Short

input double ShortTarget; // Target Short

input int CloseAllOrdersHour = 19; // Ora chiusura tutti gli ordini

input int CancelAllOrdersHour = 19; // Ora cancellazione ordini non aperti

input double CapitalManagementPercentage = 5.0; // Gestione capitale in percentuale

input int AdjustTPHour = 19; // Ora del giorno per regolare il TP

input double ProfitAdjustmentPercentage = 10.0; // Percentuale di profitto aggiuntivo da aggiungere al pareggio

input int MagicNumber = 12345; // Numero magico

input int Slippage = 2;

bool longConditionMetAfterEight = false;

bool shortConditionMetAfterEight = false;

int lastDayChecked = 0;

int LongLineHandle, ShortLineHandle;

double currentAskPrice;

double currentBidPrice;

bool bestLongPriceTouched = false;

bool bestShortPriceTouched = false;











int OnInit() {

    // Qui va il codice per l'inizializzazione dell'EA

    LongLineHandle = -1;

    ShortLineHandle = -1;

    Print("Ulcer Index è pronto per farti fare un monte di soldi! Tieniti forte!");

    return(INIT_SUCCEEDED);

}







void OnDeinit(const int reason) {

    ObjectsDeleteAll(0, OBJ_HLINE);

    ObjectsDeleteAll(0, OBJ_TEXT);

    ObjectsDeleteAll(0, OBJ_ARROW_UP);

    ObjectsDeleteAll(0, OBJ_ARROW_DOWN);

}







void OnTick() {

    datetime now = TimeCurrent();

    int currentHour = TimeHour(now);



    MqlDateTime str;

    TimeToStruct(now, str);

    if (str.day != lastDayChecked) {

        longConditionMetAfterEight = false;

        shortConditionMetAfterEight = false;

        lastDayChecked = str.day;

    }



    if (currentHour < 8) return;



    CheckMarketConditions();



    if(AreThereOpenOrPendingOrders(_Symbol, IsLong)) {

        return;

    }



   if (IsLong && longConditionMetAfterEight) {

    PlaceLongOrder(CalculateLotSize(), LongEntryLevel); // Aggiungi LongEntryLevel come prezzo limite

    longConditionMetAfterEight = false;

  } else if (!IsLong && shortConditionMetAfterEight) {

    PlaceShortOrder(CalculateLotSize(), ShortEntryLevel); // Aggiungi ShortEntryLevel come prezzo limite

    shortConditionMetAfterEight = false;

  }



    if(currentHour == AdjustTPHour) {

        AdjustTakeProfitToBreakEvenPlus();

    }



    if(currentHour == CancelAllOrdersHour) {

        CancelPendingOrders();

    }



    if(currentHour == CloseAllOrdersHour) {

        CloseMarketOrders();

    }

}







void CheckMarketConditions() {



    CheckHistoricalPriceTouch(); // Verifica se i livelli sono stati toccati dopo le 8 di mattina

    

    // Aggiornamento delle variabili globali per riflettere i prezzi correnti di ask e bid

    currentBidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); // Aggiornato: Prezzo di offerta per operazioni Short

    currentAskPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Aggiornato: Prezzo di domanda per operazioni Long

  



    datetime now = TimeCurrent();

    MqlDateTime str;

    TimeToStruct(now, str);

    if (str.day != lastDayChecked) {

        // Se è un nuovo giorno, resettiamo le condizioni e verifichiamo se i livelli sono stati toccati

        longConditionMetAfterEight = false;

        shortConditionMetAfterEight = false;

        lastDayChecked = str.day;

        // Reset dei controlli sui livelli di prezzo raggiunti durante la giornata

        bestLongPriceTouched = false;

        bestShortPriceTouched = false;

    }



    int currentHour = TimeHour(now);

    if (currentHour >= 8) {

        // Aggiorna i flag se i livelli di prezzo sono stati toccati dopo le 8

        if (!bestLongPriceTouched && currentAskPrice <= BestLongPrice) {

            bestLongPriceTouched = true;

            Print("BestLongPrice toccato alle ore ", TimeToString(now, TIME_MINUTES));

            Alert("BestLongPrice toccato alle ore ", TimeToString(now, TIME_MINUTES));

        }

        if (!bestShortPriceTouched && currentBidPrice >= BestShortPrice) {

            bestShortPriceTouched = true;

            Print("BestShortPrice toccato alle ore ", TimeToString(now, TIME_MINUTES));

            Alert("BestShortPrice toccato alle ore ", TimeToString(now, TIME_MINUTES));

        }

    } else {

        // Se l'ora corrente è prima delle 8, non eseguiamo alcuna azione relativa ai prezzi

        return;

    }

      

    // Verifica delle condizioni di mercato senza piazzare ordini direttamente qui

    if (!AreThereOpenOrPendingOrders(_Symbol, IsLong)) {

        if (IsLong && currentAskPrice <= BestLongPrice && currentAskPrice >= LongEntryLevel) {

            // Se le condizioni per un ordine Long sono soddisfatte

            longConditionMetAfterEight = true;

        } else if (!IsLong && currentBidPrice >= BestShortPrice && currentBidPrice <= ShortEntryLevel) {

            // Se le condizioni per un ordine Short sono soddisfatte

            shortConditionMetAfterEight = true;

        }

    }



    // Azione basata sulle condizioni verificate in precedenza

    if (longConditionMetAfterEight) {

        // Se è stata soddisfatta la condizione per un ordine Long dopo le 8

        PlaceLongOrder(CalculateLotSize(), LongEntryLevel);

        longConditionMetAfterEight = false; // Reset della condizione

    } else if (shortConditionMetAfterEight) {

        // Se è stata soddisfatta la condizione per un ordine Short dopo le 8

        PlaceShortOrder(CalculateLotSize(), ShortEntryLevel);

        shortConditionMetAfterEight = false; // Reset della condizione

    }



    // Operazioni di routine eseguite a orari specifici

    if (currentHour == AdjustTPHour) {

        AdjustTakeProfitToBreakEvenPlus();

    }

    if (currentHour == CancelAllOrdersHour) {

        CancelPendingOrders();

    }

    if (currentHour == CloseAllOrdersHour) {

        CloseMarketOrders();

    }

}















void CheckHistoricalPriceTouch() {

    MqlDateTime str;

    TimeToStruct(TimeCurrent(), str);



    // Assicurati che la verifica venga eseguita solo una volta al giorno

    if(lastDayChecked == str.day) return; // Se abbiamo già controllato oggi, non eseguire nuovamente

    lastDayChecked = str.day; // Aggiorna l'ultimo giorno controllato



    datetime todayStart = D'1970.01.01 00:00' + (TimeCurrent() - TimeDay(TimeCurrent())); // Mezzanotte del giorno corrente

    datetime eightAMToday = todayStart + 8 * 3600; // Calcola le 8 di mattina del giorno corrente



    // Ottieni l'indice del primo tick dopo le 8 di mattina

    int startBar = iBarShift(_Symbol, PERIOD_M1, eightAMToday, true);



    // Controlla se il livello BestLongPrice è stato toccato dopo le 8 di mattina

    for(int i = startBar; i >= 0; i--) {

        double highPrice = iHigh(_Symbol, PERIOD_M1, i);

        if(highPrice >= BestLongPrice) {

            bestLongPriceTouched = true;

            Print("BestLongPrice è stato toccato dopo le 8 di mattina.");

            Alert("BestLongPrice è stato toccato dopo le 8 di mattina.");

            break; // Interrompi il ciclo una volta trovato

        }

    }



    // Controlla se il livello BestShortPrice è stato toccato dopo le 8 di mattina

    for(int i = startBar; i >= 0; i--) {

        double lowPrice = iLow(_Symbol, PERIOD_M1, i);

        if(lowPrice <= BestShortPrice) {

            bestShortPriceTouched = true;

            Print("BestShortPrice è stato toccato dopo le 8 di mattina.");

            Alert("BestShortPrice è stato toccato dopo le 8 di mattina.");

            break; // Interrompi il ciclo una volta trovato

        }

    }

}







bool AreThereOpenOrPendingOrders(string symbol, bool isLong) {

    for(int i = 0; i < OrdersTotal(); i++) {

        if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == symbol && OrderMagicNumber() == MagicNumber) {

            // Verifica per gli ordini pendenti

            if(isLong && (OrderType() == OP_BUYLIMIT || OrderType() == OP_BUYSTOP)) return true;

            if(!isLong && (OrderType() == OP_SELLLIMIT || OrderType() == OP_SELLSTOP)) return true;



            // Aggiunto: Verifica per gli ordini a mercato aperti

            if(isLong && OrderType() == OP_BUY) return true;

            if(!isLong && OrderType() == OP_SELL) return true;

        }

    }

    return false; // Nessun ordine che corrisponde ai criteri trovato

}









void PlaceLongOrder(double lotSize, double price) {

    // Eliminiamo il controllo della direzione qui, poiché è già stato verificato prima di chiamare questa funzione

    // Prepariamo il palcoscenico per l'ordine Long

    double stopLoss = BestLongPrice - (2 * _Point); // Calcoliamo lo stop loss

    double takeProfit = LongTarget; // Definiamo il take profit



    // Invio dell'ordine BUYLIMIT con le coordinate precise

    int ticket = OrderSend(_Symbol, OP_BUYLIMIT, lotSize, price, Slippage, stopLoss, takeProfit, "Long Order", MagicNumber, 0, clrGreen);

    if (ticket < 0) {

        Print("Errore nell'invio ordine Long: ", GetLastError());

    } else {

        Print("Ordine Long pendente piazzato con successo.");

    }

}









void PlaceShortOrder(double lotSize, double price) {

    // Anche qui, il controllo di direzione viene rimosso, assumendo che la decisione sia già stata presa

    // Luci sulla scena per l'ordine Short

    double stopLoss = BestShortPrice + (2 * _Point); // Calcolo dello stop loss

    double takeProfit = ShortTarget; // Impostazione del take profit



    // Invio dell'ordine SELLLIMIT con precisione millimetrica

    int ticket = OrderSend(_Symbol, OP_SELLLIMIT, lotSize, price, Slippage, stopLoss, takeProfit, "Short Order", MagicNumber, 0, clrRed);

    if (ticket < 0) {

        Print("Errore nell'invio ordine Short: ", GetLastError());

    } else {

        Print("Ordine Short pendente piazzato con successo.");

    }

}











double CalculateLotSize() {

    double accountBalance = AccountBalance(); // Il saldo attuale del conto

    double riskPerTrade = accountBalance * (CapitalManagementPercentage / 100.0); // Il rischio per trade in termini monetari



    // Determiniamo la distanza dello stop loss in pips per un calcolo accurato del rischio

    double stopLossDistance;

    if (IsLong) {

        stopLossDistance = MathAbs(LongEntryLevel - (BestLongPrice - (2 * _Point))); // Per Long

    } else {

        stopLossDistance = MathAbs((BestShortPrice + (2 * _Point)) - ShortEntryLevel); // Per Short

    }



    // Calcoliamo il valore del pip per lotti standard per questo simbolo

    double pipValuePerLot = MarketInfo(_Symbol, MODE_TICKVALUE) / MarketInfo(_Symbol, MODE_TICKSIZE);



    // Ora, determiniamo la dimensione del lotto basata sul rischio fisso per trade e sulla distanza dello stop loss

    double lotSize = riskPerTrade / (stopLossDistance * pipValuePerLot);



    // Assicuriamoci che la dimensione del lotto sia nei limiti consentiti dal broker

    double minLot = MarketInfo(_Symbol, MODE_MINLOT);

    double maxLot = MarketInfo(_Symbol, MODE_MAXLOT);

    double lotStep = MarketInfo(_Symbol, MODE_LOTSTEP);

    lotSize = MathMax(minLot, MathMin(lotSize, maxLot)); // Confiniamo la dimensione del lotto entro i limiti

    lotSize = MathRound(lotSize / lotStep) * lotStep; // Arrotondiamo alla dimensione del lotto permessa più vicina



    return lotSize; // E così, con un grido di sfida, il nostro lotto prende forma

}







void AdjustTakeProfitToBreakEvenPlus() {

    datetime now = TimeCurrent();

    if(TimeHour(now) != AdjustTPHour) return; // Esegue solo all'ora specificata



    for(int i = OrdersTotal()-1; i >= 0; i--) {

        if(OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol()) {

            if(OrderType() == OP_BUY || OrderType() == OP_SELL) {

                double currentProfit = OrderProfit();

                double breakEvenPrice = OrderOpenPrice();

                double adjustedTP = 0.0;



                // Calcolo del nuovo Take Profit basato sulla direzione dell'ordine

                if(currentProfit > 0) { // Se l'ordine è in profitto

                    if(OrderType() == OP_BUY) {

                        adjustedTP = breakEvenPrice + (Point * SymbolInfoInteger(Symbol(), SYMBOL_DIGITS) * ProfitAdjustmentPercentage / 100);

                    } else if(OrderType() == OP_SELL) {

                        adjustedTP = breakEvenPrice - (Point * SymbolInfoInteger(Symbol(), SYMBOL_DIGITS) * ProfitAdjustmentPercentage / 100);

                    }



                    // Aggiorna il Take Profit solo se il nuovo TP è migliore di quello esistente

                    if((OrderType() == OP_BUY && adjustedTP > OrderTakeProfit()) || (OrderType() == OP_SELL && adjustedTP < OrderTakeProfit())) {

                        bool result = OrderModify(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), adjustedTP, 0, clrNONE);

                        if(!result) {

                            Print("Errore nella modifica dell'ordine ", OrderTicket(), ": ", GetLastError());

                        } else {

                            Print("Take Profit aggiustato per l'ordine ", OrderTicket(), " al prezzo ", adjustedTP);

                        }

                    }

                }

            }

        }

    }

}





// funzione che cancella tutti gli oridini pendenti ad una precisa ora del giorno, se non siamo entrati a mercato

void CancelPendingOrders() {

    // Ciclo attraverso tutti gli ordini

    for(int i = OrdersTotal() - 1; i >= 0; i--) {

        if(OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == MagicNumber) {

            // Verifichiamo che l'ordine sia pendente e corrisponda al nostro numero magico

            if(OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLLIMIT) {

                // Cancella l'ordine pendente

                bool result = OrderDelete(OrderTicket(), clrRed);

                if(!result) {

                    Print("Errore nella cancellazione dell'ordine pendente ", OrderTicket(), ": ", GetLastError());

                } else {

                    Print("Ordine pendente ", OrderTicket(), " cancellato con successo.");

                }

            }

        }

    }

}







// funzione che cancella tutti gli oridini a mercato e pendenti ad una precisa ora del giorno, se siamo entrati a mercato

void CloseMarketOrders() {

    // Ciclo attraverso tutti gli ordini aperti

    for(int i = OrdersTotal() - 1; i >= 0; i--) {

        if(OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == MagicNumber) {

            // Controlla se l'ordine appartiene al nostro EA tramite il Magic Number

            if(OrderType() <= OP_SELL) { // Se l'ordine è a mercato (BUY o SELL)

                bool closeResult = false; // Variabile per controllare il risultato dell'azione di chiusura

                // Prova a chiudere l'ordine a mercato

                if(OrderType() == OP_BUY) {

                    closeResult = OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed);

                } else if(OrderType() == OP_SELL) {

                    closeResult = OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrRed);

                }

                // Controlla il risultato della chiusura e agisci di conseguenza

                if(!closeResult) {

                    Print("Errore nella chiusura dell'ordine ", OrderTicket(), ": ", GetLastError());

                }

            } else { // Se l'ordine è pendente (BUY LIMIT, SELL LIMIT, BUY STOP, SELL STOP)

                // Cancella l'ordine pendente e controlla il risultato

                bool deleteResult = OrderDelete(OrderTicket());

                if(!deleteResult) {

                    Print("Errore nella cancellazione dell'ordine pendente ", OrderTicket(), ": ", GetLastError());

                }

            }

        }

    }

}









// Verifica se ci sono ordini aperti per la direzione specificata

bool ExistOpenOrders(string symbol, bool isLong) {

    for(int i = 0; i < OrdersTotal(); i++) {

        if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == symbol && OrderMagicNumber() == MagicNumber) {

            if((isLong && OrderType() == OP_BUY) || (!isLong && OrderType() == OP_SELL)) {

                return true; // Trovato un ordine aperto che corrisponde ai criteri

            }

        }

    }

    return false; // Nessun ordine aperto che corrisponde ai criteri trovato

}







bool ExistPendingOrders(string symbol, bool isLong) {

    for(int i = 0; i < OrdersTotal(); i++) {

        if(OrderSelect(i, SELECT_BY_POS) && OrderSymbol() == symbol && OrderMagicNumber() == MagicNumber) {

            if(isLong && (OrderType() == OP_BUYLIMIT || OrderType() == OP_BUYSTOP)) return true;

            if(!isLong && (OrderType() == OP_SELLLIMIT || OrderType() == OP_SELLSTOP)) return true;

        }

    }

    return false; // Nessun ordine pendente che corrisponde ai criteri trovato

}