RM1/Experts/Advisors/DR LOLI cent 142.mq5
90011485 3102651d81
2025-10-15 10:42:34 +02:00

425 lines
41 KiB
MQL5

//+------------------------------------------------------------------+
//| 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 <Trade\Trade.mqh>
#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.");
}
}
}
}
}
//+------------------------------------------------------------------+