//+------------------------------------------------------------------+ //| DR LOLI.mq5 | //| Expert Advisor Linear and Logistic Regression | //| Min 100.000c Cent Account Leverage 1:500 | //| XAU/USD | //+------------------------------------------------------------------+ //test push #property copyright "Copyright 2024, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.42" #property description "Expert Advisor for scalping with a linear and logistic regression model." #property description "V2.0: Utilizza una libreria separata per la regressione logistica e include l'ATR come input per il modello." #property description "V3.0: Usa il profitto futuro per l'apprendimento del modello logistico." #property description "V4.0: Aggiunto Stop Loss e Take Profit dinamici all'apertura della posizione." #property description "V5.0: Aggiunto controllo profitto sull'equity e verifica margine disponibile." #property description "V6.0: Aggiunto limite massimo di posizioni per direzione (buy/sell)." #property description "V7.0: Aggiunto controllo di profitto giornaliero e chiusura automatica a fine giornata." #property description "V8.0: Corretti errori di compilazione relativi alla data/ora." #property description "V9.0: Aggiunto un parametro per definire quale percentuale del profitto da un ordine Take Profit debba essere utilizzata per chiudere parzialmente una posizione in perdita." #property description "V10.0: Rimosse le vecchie logiche di chiusura e aggiunta una nuova logica di compensazione giornaliera del rischio." #property description "V11.0: Aggiunto un filtro di trend basato su due medie mobili esponenziali (EMA) su timeframe H4, attivabile e disattivabile dall'utente." #property description "V12.0: Risolto il problema del filtro di trend che bloccava le posizioni a causa di valori EMA non validi." #property description "V13.0: Ritorno alla logica di chiusura basata sull'equity totale e al controllo del margine, come richiesto dall'utente." #property description "V14.0: Aggiunto filtro di volatilità basato su ATR e SL/TP dinamici." #property description "V15.0: Aggiunta chiusura temporale delle posizioni." #property description "V16.0: Aggiunta funzione di recupero drawdown con lotto dinamico." #property description "V17.0: Implementazione dei suggerimenti, lotto dinamico in base al rischio e controlli di sicurezza." #property description "V18.0: Correzione del bug 'undeclared identifier'." #property description "V19.0: Modifica la logica di recupero per utilizzare un lotto fisso definito dall'utente." #property description "V20.0: Aggiunto Take Profit fisso per le posizioni di recupero." #property description "V21.0: Aggiunto filtro di trend basato su EMA 7 e 14 come input per il modello." #property description "V22.0: Sostituito i due modelli (Buy e Sell) con un singolo modello per evitare probabilità contraddittorie." #property description "V23.0: Aggiunta regressione lineare per calcolare dinamicamente il Take Profit." #property description "V24.0: Il periodo delle EMA è ora configurabile dall'utente." #property description "V25.0: Il timeframe del filtro EMA è ora configurabile dall'utente." #property description "V26.0: Aggiunti i Pivot Points come input per i modelli." #property description "V27.0: Aggiunto il volume come input per i modelli." #property description "V28.0: Aggiunto controllo di sicurezza per TP negativi." #property description "V29.0: Aggiornamento dei parametri di input." #property description "V30.0: Aggiunto filtro ADX e ADX come input per il modello." #property description "V31.0: Corretto il problema del valore ADX = 11." #property description "V32.0: Utilizza l'handle ADX per un calcolo corretto." #property description "V33.0: Aggiunta funzione per rimuovere il TP in caso di drawdown." #property description "V34.0: Sostituzione della chiusura fissa con un trailing profit complessivo." #property description "V35.0: Implementato un trailing profit basato sull'ATR per maggiore adattabilità alla volatilità." #property description "V36.0: Aggiunto moltiplicatore dinamico del lotto in base all'equity del conto." #property description "V37.0: Correzione bug Invalid Stops" #property description "V38.0: Correzione bug Invalid Stops persistente dovuto a calcolo TP errato" #property description "V39.0: Correzione bug Invalid Stops causato da input errati nel modello" #property description "V40.0: Aggiunto un controllo di validità sulle previsioni del modello di regressione lineare." #property description "V41.0: Implementato un controllo di margine dinamico più robusto." //--- Includes #include #include "RegressionModels3.mqh" //--- Inputs input double InpMinProbabilityBuy = 0.60; // Min. probability for logistic prediction (0-1) input double InpMinProbabilitySell = 0.40; // Min. probability for logistic prediction (0-1) input int InpSuccessLookbackBars = 20; // Bars to look back for success criteria input int InpSuccessPipsThreshold = 20; // Pips threshold for success criteria input int InpBollingerPeriod = 20; // Bollinger Bands period input double InpBollingerDeviation = 2.0; // Bollinger Bands deviation input int InpRsiPeriod = 14; // RSI Period input ENUM_APPLIED_PRICE InpRsiPrice = PRICE_CLOSE; // RSI Applied Price input int InpAtrPeriod = 14; // ATR Period input double InpMinAtrFilter = 1.0; // Minimum ATR value in points to open a position input int InpAdxPeriod = 14; // ADX Period input double InpMinAdxFilter = 35.0; // Min. ADX value to open a position input double InpSLMultiplier = 0.0; // Stop Loss Multiplier (x ATR) input double InpLotSize = 0.20; // Lot size input double InpBalanceFactor = 10000.0; // Base value for dynamic lot sizing input int InpMagicNumber = 12345; // Magic Number input int InpMaxBuyPositions = 35; // Max. Buy positions input int InpMaxSellPositions = 35; // Max. Sell positions input int InpTrailingATRPeriod = 14; // Trailing Profit ATR Period input double InpTrailingATRMultiplier = 100.0; // Trailing Profit ATR Multiplier (0 to disable) input int InpCloseAfterDays = 0; // Close positions after this many days (0 to disable) input bool InpEnableDrawdownRecovery = true; // Enable/Disable drawdown recovery input int InpRecoveryStartHour = 14; // Start hour for drawdown recovery (server time) input int InpRecoveryEndHour = 19; // End hour for drawdown recovery (server time) input double InpRecoveryFixedLot = 0.40; // Initial lot size for recovery input double InpRecoveryTakeProfit = 2000.0; // Take Profit for recovery trades in pips input double InpMaxLotSize = 50.0; // Maximum allowed lot size input bool InpEnableEmaFilter = true; // Enable EMA Trend Filter input ENUM_TIMEFRAMES InpEmaFilterTimeframe = PERIOD_H1; // EMA Timeframe input int InpEmaFastPeriod = 7; // EMA Fast Period input int InpEmaSlowPeriod = 14; // EMA Slow Period input ENUM_TIMEFRAMES InpPivotTimeframe = PERIOD_D1; // Timeframe for Pivot Points input int InpVolumePeriod = 10; // Lookback period for volume normalization input double InpMinTakeProfitPips = 60.0; // Minimum Take Profit in pips input bool InpRemoveTPOnDrawdown = true; // Remove TP on drawdown > 2% input bool InpDynamicLotMultiplier = true; // Enable dynamic lot size based on balance input double InpMaxPredictedPips = 5000; // New input: Maximum reasonable TP in pips //--- Global objects CTrade m_trade; CLogisticRegression model; CLinearRegression tp_model; static double current_lot_size; static double current_tp_pips; // Pips value for TP static int last_hour_check = -1; static bool is_in_recovery_mode = false; static int adx_handle; static double last_high_equity = 0.0; static datetime last_bar_time; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("Expert Advisor started."); // Create ADX handle adx_handle = iADX(_Symbol, _Period, InpAdxPeriod); if(adx_handle == INVALID_HANDLE) { Print("Failed to create ADX handle. Error: ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("Expert Advisor stopped."); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { datetime current_bar_time = (datetime)SeriesInfoInteger(Symbol(), Period(), SERIES_LASTBAR_DATE); if(current_bar_time == last_bar_time) { return; } last_bar_time = current_bar_time; double current_balance = AccountInfoDouble(ACCOUNT_BALANCE); double current_equity = AccountInfoDouble(ACCOUNT_EQUITY); double current_atr = iATR(Symbol(), Period(), InpTrailingATRPeriod); // --- Trailing Profit based on ATR --- if(InpTrailingATRMultiplier > 0 && current_equity > current_balance) { if(last_high_equity == 0 || current_equity > last_high_equity) { last_high_equity = current_equity; } double trailing_level = last_high_equity - (current_atr * InpTrailingATRMultiplier * _Point); if(current_equity < trailing_level) { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong position_ticket = PositionGetTicket(i); if(PositionSelectByTicket(position_ticket)) { m_trade.PositionClose(position_ticket); } } Print("All positions closed due to overall account trailing profit (ATR-based). Trailing level: ", NormalizeDouble(trailing_level, 2), " Equity: ", NormalizeDouble(current_equity, 2)); last_high_equity = 0.0; // Reset high watermark return; } } else { last_high_equity = 0.0; // Reset if trailing is disabled or account is in drawdown } // Get ADX value using handle double adx_values[]; if(CopyBuffer(adx_handle, 0, 0, 1, adx_values) <= 0) { Print("Failed to copy ADX values from buffer. Error: ", GetLastError()); return; } double adx_value = adx_values[0]; if(adx_value < InpMinAdxFilter || adx_value == EMPTY_VALUE) { return; } MqlDateTime server_time; TimeCurrent(server_time); // --- Trading Logic --- // Calculate and learn the models int actual_output = 0; double past_close = iClose(Symbol(), Period(), InpSuccessLookbackBars); double max_high = 0.0; double min_low = 0.0; double high_prices_lookback[]; if(CopyHigh(Symbol(), Period(), InpSuccessLookbackBars + 1, InpSuccessLookbackBars, high_prices_lookback) > 0) { max_high = high_prices_lookback[ArrayMaximum(high_prices_lookback)]; } double low_prices_lookback[]; if(CopyLow(Symbol(), Period(), InpSuccessLookbackBars + 1, InpSuccessLookbackBars, low_prices_lookback) > 0) { min_low = low_prices_lookback[ArrayMinimum(low_prices_lookback)]; } double actual_magnitude = 0.0; if((max_high - past_close) / _Point >= InpSuccessPipsThreshold) { actual_output = 1; actual_magnitude = (max_high - past_close) / _Point; } else if((past_close - min_low) / _Point >= InpSuccessPipsThreshold) { actual_output = 0; actual_magnitude = (past_close - min_low) / _Point; } // Calculate inputs for the models double pivot_high = iHigh(Symbol(), InpPivotTimeframe, 1); double pivot_low = iLow(Symbol(), InpPivotTimeframe, 1); double pivot_close = iClose(Symbol(), InpPivotTimeframe, 1); double pp = (pivot_high + pivot_low + pivot_close) / 3; double s1 = (2 * pp) - pivot_high; double r1 = (2 * pp) - pivot_low; double current_price = (SymbolInfoDouble(Symbol(), SYMBOL_BID) + SymbolInfoDouble(Symbol(), SYMBOL_ASK)) / 2; double dist_pp = MathAbs(current_price - pp); double dist_s1 = MathAbs(current_price - s1); double dist_r1 = MathAbs(current_price - r1); double pivot_distance = MathMin(dist_pp, MathMin(dist_s1, dist_r1)) / _Point; double current_volume = iVolume(Symbol(), Period(), 0); long volume_values[]; double volume_avg = 0.0; if(CopyTickVolume(Symbol(), Period(), 1, InpVolumePeriod, volume_values) > 0) { for(int i = 0; i < ArraySize(volume_values); i++) { volume_avg += volume_values[i]; } volume_avg /= ArraySize(volume_values); } double volume_input = (volume_avg > 0) ? current_volume / volume_avg : 0.0; // Call models to get predictions with live data double trend_probability = model.PredictAndLearn( actual_output, _Symbol, _Period, InpRsiPeriod, InpBollingerPeriod, InpBollingerDeviation, InpAtrPeriod, InpEnableEmaFilter, InpEmaFilterTimeframe, InpEmaFastPeriod, InpEmaSlowPeriod, pivot_distance, volume_input, adx_value ); double predicted_tp_pips = tp_model.PredictAndLearn( actual_magnitude, _Symbol, _Period, InpRsiPeriod, InpBollingerPeriod, InpBollingerDeviation, InpAtrPeriod, InpEnableEmaFilter, InpEmaFilterTimeframe, InpEmaFastPeriod, InpEmaSlowPeriod, pivot_distance, volume_input, adx_value ); // --- Logic for lot size and TP/SL --- // Dynamic Lot Size Calculation double balance_factor = 1.0; if(InpDynamicLotMultiplier) { balance_factor = current_balance / InpBalanceFactor; } current_lot_size = MathMax(InpLotSize, NormalizeDouble(InpLotSize * balance_factor, 2)); // Recovery Mode Check if(InpEnableDrawdownRecovery && server_time.hour >= InpRecoveryStartHour && server_time.hour < InpRecoveryEndHour && current_equity < current_balance) { is_in_recovery_mode = true; double recovery_lot = InpRecoveryFixedLot; if(InpDynamicLotMultiplier) { double recovery_balance_factor = current_balance / InpBalanceFactor; recovery_lot = MathMax(InpRecoveryFixedLot, NormalizeDouble(InpRecoveryFixedLot * recovery_balance_factor, 2)); } current_lot_size = MathMin(recovery_lot, InpMaxLotSize); current_tp_pips = InpRecoveryTakeProfit; Print("Drawdown detected. Entering recovery mode with fixed lot: ", DoubleToString(current_lot_size, 2), " and fixed TP: ", DoubleToString(current_tp_pips, 2), " pips."); } else { is_in_recovery_mode = false; // Safety check for predicted TP if(predicted_tp_pips > InpMaxPredictedPips || predicted_tp_pips < 0) { current_tp_pips = InpMinTakeProfitPips; Print("Predicted TP is invalid (", DoubleToString(predicted_tp_pips, 2), "). Using fixed minimum TP: ", DoubleToString(current_tp_pips, 2), " pips."); } else { current_tp_pips = MathMax(InpMinTakeProfitPips, predicted_tp_pips); Print("Normal trading mode. Predicted TP: ", DoubleToString(predicted_tp_pips, 2), " pips. Final TP: ", DoubleToString(current_tp_pips, 2), " pips."); } } // --- Security Checks Before Opening Position --- double free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); double margin_required = SymbolInfoDouble(_Symbol, SYMBOL_MARGIN_INITIAL) * current_lot_size; if(free_margin < margin_required) { Print("Not enough free margin for the requested operation. Required: ", DoubleToString(margin_required, 2), ", Available: ", DoubleToString(free_margin, 2)); return; } int buy_positions_count = 0; int sell_positions_count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong position_ticket = PositionGetTicket(i); if(PositionSelectByTicket(position_ticket)) { if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { buy_positions_count++; } else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { sell_positions_count++; } } } double current_atr_filter = iATR(Symbol(), Period(), InpAtrPeriod); if(current_atr_filter <= InpMinAtrFilter * _Point) { Print("ATR is too low to trade."); return; } // --- Remove TP on drawdown --- if(InpRemoveTPOnDrawdown) { if(current_equity < current_balance * 0.98) // Drawdown > 2% { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong position_ticket = PositionGetTicket(i); if(PositionSelectByTicket(position_ticket)) { if(PositionGetDouble(POSITION_TP) > 0) { m_trade.PositionModify(position_ticket, PositionGetDouble(POSITION_SL), 0); Print("Removed TP from position ", position_ticket, " due to drawdown > 2%."); } } } } } Print("trend_probability ", trend_probability); // --- Final Order Execution Logic --- if(trend_probability > InpMinProbabilityBuy && buy_positions_count < InpMaxBuyPositions) { double tp_buy = SymbolInfoDouble(_Symbol, SYMBOL_ASK) + (current_tp_pips * _Point); double sl_buy = 0.0; if(InpSLMultiplier > 0.0) { sl_buy = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - (current_atr_filter * InpSLMultiplier) * _Point; } sl_buy = NormalizeDouble(sl_buy, _Digits); tp_buy = NormalizeDouble(tp_buy, _Digits); m_trade.Buy(current_lot_size, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_ASK), sl_buy, tp_buy, "BUY Signal from Logistic Regression"); } else if((trend_probability) < (InpMinProbabilitySell) && sell_positions_count < InpMaxSellPositions) { double tp_sell = SymbolInfoDouble(_Symbol, SYMBOL_BID) - (current_tp_pips * _Point); double sl_sell = 0.0; if(InpSLMultiplier > 0.0) { sl_sell = SymbolInfoDouble(_Symbol, SYMBOL_BID) + (current_atr_filter * InpSLMultiplier) * _Point; } sl_sell = NormalizeDouble(sl_sell, _Digits); tp_sell = NormalizeDouble(tp_sell, _Digits); m_trade.Sell(current_lot_size, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_BID), sl_sell, tp_sell, "SELL Signal from Logistic Regression"); } if(InpCloseAfterDays > 0) { long max_duration_seconds = InpCloseAfterDays * 24 * 60 * 60; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong position_ticket = PositionGetTicket(i); if(PositionSelectByTicket(position_ticket)) { long open_time_seconds = PositionGetInteger(POSITION_TIME_MSC) / 1000; long duration_seconds = TimeCurrent() - open_time_seconds; if(duration_seconds >= max_duration_seconds) { m_trade.PositionClose(position_ticket); Print("Closing position ", position_ticket, " due to time limit exceeded."); } } } } } //+------------------------------------------------------------------+