1
0
Fork 0
EA_SMC_Mql5_review/Experts/EA SMC.mq5
2025-11-28 15:30:59 +03:00

361 lines
No EOL
36 KiB
MQL5

//+------------------------------------------------------------------+
//| EA SMC.mq5 |
//| v23.2 - OPTIMIZED: OnTick/OnNewBar Split |
//+------------------------------------------------------------------+
#property copyright "Your Name"
#property link "https://github.com"
#property version "23.2"
#property description "SMC Expert Advisor - Optimizado para rendimiento"
// --- Standard & Custom Library Includes ---
#include <Trade/Trade.mqh>
#include "..\\Include\\Main.mqh"
input group "--- Estrategia Principal de Salida ---";
input ENUM_EXIT_MODE InpExitMode = EXIT_MODE_TRAILING_STOP;
input double InpRiskToRewardRatio = 0.8;
input int InpFixedTPPoints = 1400;
input group "--- Configuración de Trading y Riesgo ---";
input long InpMagicNumber = 0;
input string InpEaComment = "EA_SMC_v23.2";
input int InpMaxOpenTrades = 2;
input int InpStopLossBufferPoints = 50;
input ulong InpSlippagePoints = 10;
input int InpMinStopLossPoints = 100; // +++ CHANGED: Valor más razonable
input int InpMaxStopLossPoints = 300; // +++ CHANGED: Valor más razonable
input group "--- Modo de Gestión Monetaria ---";
input ENUM_MONEY_MANAGEMENT_MODE InpMoneyManagementMode = MM_MODE_RISK_PERCENT;
input group "--- Configuración para: Lote Fijo ---";
input double InpFixedLotSize = 0.01;
input group "--- Configuración para: Riesgo por Porcentaje por Trade ---";
input double InpRiskPercentPerTrade = 1.0; // +++ CHANGED: 1% es más razonable que 4%
input group "--- Configuración para: Escalado de Lotes por Balance ---";
input double InpBaseLotForScaling = 0.01;
input double InpBalanceStepForScaling = 1000.0;
input group "--- Activadores de Estrategia de Entrada ---";
input int InpMaxTradesPerZone = 1;
input bool InpUseContinuationRetest = false;
input bool InpUseReversalRetest = false;
input bool InpUseBreakoutEntry = true;
input bool InpUseScaleInOnBreakout = true;
input int InpBreakout_RetestNumber = 1;
input bool InpUseFakeoutEntry = false;
input bool InpUseMajorSwingMomentumEntry = false;
input bool InpUseSfpEntry = false;
input bool InpUseSweepToPoiEntry = false;
input bool InpUseFreshFvgRetestEntry = true;
input group "--- Activadores de Patrones de Confirmación ---";
input bool InpUseStoForEntryConfirmation = true;
input bool InpUseSimpleReclaimPattern = true;
input bool InpUse2BarConfirmation = true;
input bool InpUse3BarConfirmation = true;
input group "--- Configuración de Retest de FVG (Avanzado) ---";
input ENUM_RETEST_CONFIRMATION_MODE InpRetest_ConfirmationMode = CONF_MODE_DISP_AND_STRUCT;
input double InpRetest_MinAtrMoveAway = 1.0;
input group "--- Configuración de Análisis de Estructura ---";
input int InpSwingLength = 14;
input double InpAtrNoiseFilter = 0.25;
input int InpMaxBarsForBOS = 15;
input ENUM_BOS_TYPE InpBosConfirmationType = BOS_BY_CLOSE;
input int InpPdArrayLookbackSwings = 15;
input double InpMinFvgAtrMult = 0.3;
input ENUM_ZONE_QUALITY_LEVEL InpMinZoneQuality = ZQ_STANDARD;
input group "--- Gestión Avanzada de Trades ---";
input bool InpUsePartialTP = false;
input double InpPartialTP_RR = 0.8;
input double InpPartialClosePercent = 50.0;
input double InpPsarStep = 0.02;
input double InpPsarMax = 0.2;
input group "--- Configuración de Trailing Stop Dinámico ---";
input double InpTrail_Tier1_RR = 1.0;
input int InpTrail_Tier1_Points = 50; // +++ CHANGED: Valores más razonables
input double InpTrail_Tier2_RR = 2.0;
input int InpTrail_Tier2_Points = 30;
input double InpTrail_Tier3_RR = 3.0;
input int InpTrail_Tier3_Points = 10;
input group "--- Filtros de Indicadores (Avanzado) ---";
input bool InpFilterSwingsBySweep = true;
input bool InpFilterSwingsByFVG = true;
input bool InpUseVolumeFilter = false;
input bool InpUseRsiFilter = true;
input int InpRsiPeriod = 14;
input int InpRsiOverbought = 70;
input int InpRsiOversold = 30;
input bool InpUseStochasticFilter = true;
input int InpSto_K_Period = 14;
input int InpSto_D_Period = 3;
input int InpSto_Slowing = 3;
input int InpSto_Overbought = 80;
input int InpSto_Oversold = 20;
input group "--- Configuración de Filtro de Tiempo ---";
input bool InpUseTimeFilter = false;
input int InpSession1_StartHour = 14;
input int InpSession1_EndHour = 22;
input bool InpUseFridayExit = false;
input int InpFridayExit_Hour = 22;
input int InpFridayExit_Minute = 0;
// --- Punteros Globales a Todos los Módulos ---
CZoneManager* g_zoneManager_ptr = NULL;
CChartDrawer* g_drawer_ptr = NULL;
CRiskManager* g_riskManager_ptr = NULL;
CSetupScanner* g_setupScanner_ptr = NULL;
CStructureAnalyzer* g_analyzer_ptr = NULL;
CEntryExecutor* g_entryExecutor_ptr = NULL;
CTimeFilter* g_timeFilter_ptr = NULL;
CTradeManager* g_tradeManager_ptr = NULL;
// --- Handles Globales de Indicadores ---
int g_atr_handle = INVALID_HANDLE;
int g_rsi_handle = INVALID_HANDLE;
int g_volume_handle = INVALID_HANDLE;
int g_sto_handle = INVALID_HANDLE;
// --- Variables Globales de Timer ---
static bool is_initial_scan_done = false;
static datetime last_sl_tp_check_time = 0;
static datetime last_processed_bar_time = 0;
const int SL_TP_CHECK_INTERVAL = 10;
// +++ NEW: Global context to avoid recreating on every tick +++
CDataContext* g_context_ptr = NULL;
//+------------------------------------------------------------------+
int OnInit()
{
Print("EA v23.2 (OPTIMIZED) Initializing...");
MathSrand(GetTickCount());
// --- Crear instancias de módulos ---
g_zoneManager_ptr = new CZoneManager();
g_drawer_ptr = new CChartDrawer(ChartID(), InpMagicNumber);
g_riskManager_ptr = new CRiskManager(InpMoneyManagementMode, InpFixedLotSize, InpRiskPercentPerTrade, InpBaseLotForScaling, InpBalanceStepForScaling);
g_setupScanner_ptr = new CSetupScanner(g_zoneManager_ptr, InpSwingLength, InpMagicNumber, InpMinFvgAtrMult,
InpUseStochasticFilter, InpSto_Overbought, InpSto_Oversold);
g_analyzer_ptr = new CStructureAnalyzer(g_zoneManager_ptr, InpAtrNoiseFilter, InpMaxBarsForBOS,
InpBosConfirmationType, InpPdArrayLookbackSwings,
InpUseRsiFilter, InpRsiPeriod,InpRsiOverbought, InpRsiOversold, InpFilterSwingsByFVG, InpFilterSwingsBySweep,InpRetest_MinAtrMoveAway,InpMinZoneQuality);
g_entryExecutor_ptr = new CEntryExecutor(g_zoneManager_ptr, g_analyzer_ptr, InpMaxTradesPerZone,
InpUseContinuationRetest, InpUseReversalRetest,InpUseBreakoutEntry, InpUseFakeoutEntry,
InpUseMajorSwingMomentumEntry, InpUseSfpEntry, InpUseSweepToPoiEntry,
InpUseScaleInOnBreakout, InpBreakout_RetestNumber, InpUseFreshFvgRetestEntry,
InpUseSimpleReclaimPattern, InpUse2BarConfirmation, InpUse3BarConfirmation,
InpUseStoForEntryConfirmation, InpSto_Overbought, InpSto_Oversold,
InpRetest_ConfirmationMode, InpRetest_MinAtrMoveAway);
g_timeFilter_ptr = new CTimeFilter(InpUseTimeFilter, InpSession1_StartHour, InpSession1_EndHour, 0, 0, 0, 0, false, 0, 0, 0, 0, InpUseFridayExit, InpFridayExit_Hour, InpFridayExit_Minute, ChartID(), InpMagicNumber);
g_tradeManager_ptr = new CTradeManager(g_riskManager_ptr, InpMagicNumber, InpEaComment, InpSlippagePoints,
InpStopLossBufferPoints, InpMinStopLossPoints, InpMaxStopLossPoints,
InpExitMode, InpRiskToRewardRatio, InpFixedTPPoints,
InpTrail_Tier1_RR, InpTrail_Tier1_Points, InpTrail_Tier2_RR, InpTrail_Tier2_Points, InpTrail_Tier3_RR, InpTrail_Tier3_Points, InpPsarStep, InpPsarMax,
InpUsePartialTP, InpPartialTP_RR, InpPartialClosePercent);
// --- Validación de punteros ---
if(CheckPointer(g_zoneManager_ptr)==POINTER_INVALID || CheckPointer(g_drawer_ptr)==POINTER_INVALID || CheckPointer(g_riskManager_ptr)==POINTER_INVALID ||
CheckPointer(g_setupScanner_ptr)==POINTER_INVALID || CheckPointer(g_analyzer_ptr)==POINTER_INVALID || CheckPointer(g_entryExecutor_ptr)==POINTER_INVALID ||
CheckPointer(g_timeFilter_ptr)==POINTER_INVALID || CheckPointer(g_tradeManager_ptr)==POINTER_INVALID)
{
Print("FATAL: Un módulo central falló al inicializar.");
return(INIT_FAILED);
}
// --- Crear Handles de Indicadores ---
g_atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
if(g_atr_handle == INVALID_HANDLE) { Print("¡Falló la creación del Handle ATR!"); return(INIT_FAILED); }
if(InpUseRsiFilter) {
g_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, InpRsiPeriod, PRICE_CLOSE);
if(g_rsi_handle == INVALID_HANDLE) { Print("¡Falló la creación del Handle RSI!"); return(INIT_FAILED); }
}
if(InpUseVolumeFilter) {
g_volume_handle = iVolume(_Symbol, PERIOD_CURRENT, VOLUME_TICK);
if(g_volume_handle == INVALID_HANDLE) { Print("¡Falló la creación del Handle de Volumen!"); return(INIT_FAILED); }
}
if(InpUseStochasticFilter) {
g_sto_handle = iStochastic(_Symbol, PERIOD_CURRENT, InpSto_K_Period, InpSto_D_Period, InpSto_Slowing, MODE_SMA, STO_LOWHIGH);
if(g_sto_handle == INVALID_HANDLE) { Print("¡Falló la creación del Handle Estocástico!"); return(INIT_FAILED); }
}
// +++ NEW: Crear contexto global +++
g_context_ptr = new CDataContext(500);
Print("--- Inicialización Completa. Esperando el primer tick para realizar análisis histórico... ---");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(CheckPointer(g_tradeManager_ptr)) delete g_tradeManager_ptr;
if(CheckPointer(g_timeFilter_ptr)) delete g_timeFilter_ptr;
if(CheckPointer(g_entryExecutor_ptr)) delete g_entryExecutor_ptr;
if(CheckPointer(g_analyzer_ptr)) delete g_analyzer_ptr;
if(CheckPointer(g_setupScanner_ptr)) delete g_setupScanner_ptr;
if(CheckPointer(g_riskManager_ptr)) delete g_riskManager_ptr;
if(CheckPointer(g_drawer_ptr)) delete g_drawer_ptr;
if(CheckPointer(g_zoneManager_ptr)) delete g_zoneManager_ptr;
if(CheckPointer(g_context_ptr)) delete g_context_ptr; // +++ NEW
if(g_atr_handle != INVALID_HANDLE) IndicatorRelease(g_atr_handle);
if(g_rsi_handle != INVALID_HANDLE) IndicatorRelease(g_rsi_handle);
if(g_volume_handle != INVALID_HANDLE) IndicatorRelease(g_volume_handle);
if(g_sto_handle != INVALID_HANDLE) IndicatorRelease(g_sto_handle);
Comment("");
}
//+------------------------------------------------------------------+
//| OPTIMIZED: Tareas que se ejecutan en cada NUEVO BAR |
//+------------------------------------------------------------------+
void OnNewBar(CDataContext &context, int new_bars_count)
{
// --- 1. Escaneo y Análisis (PESADO - solo en nueva barra) ---
if(CheckPointer(g_setupScanner_ptr))
g_setupScanner_ptr.ScanIncremental(context, new_bars_count);
if(CheckPointer(g_analyzer_ptr))
g_analyzer_ptr.Analyze(context);
// --- 2. Salidas Estructurales (si está habilitado) ---
if(CheckPointer(g_tradeManager_ptr) && InpExitMode == EXIT_MODE_STRUCTURAL) {
g_tradeManager_ptr.ManageStructuralExits(g_zoneManager_ptr.GetAllSwings());
}
// --- 3. Búsqueda de Señales de Entrada ---
if(CheckPointer(g_entryExecutor_ptr) && (int)PositionsTotal() < InpMaxOpenTrades) {
CSignalZone* trade_signal = g_entryExecutor_ptr.FindTradeSignal(context, InpMagicNumber);
if(trade_signal != NULL) {
if(g_tradeManager_ptr.OpenTradeFromSignal(trade_signal)) {
if(trade_signal.trigger_level_time > 0)
g_zoneManager_ptr.IncrementTradeCountForLevel(trade_signal.trigger_level_time);
}
if(trade_signal.zone_id == 0)
delete trade_signal;
}
}
// --- 4. Dibujo (PESADO - solo en nueva barra) ---
if(CheckPointer(g_drawer_ptr) && CheckPointer(g_zoneManager_ptr)) {
CArrayObj* all_zones = g_zoneManager_ptr.GetZoneList();
CArrayObj* all_swings = g_zoneManager_ptr.GetAllSwings();
g_drawer_ptr.SynchronizeDrawings(all_zones, all_swings);
if(all_zones != NULL) {
for(int i = 0; i < all_zones.Total(); i++)
g_drawer_ptr.DrawZone(all_zones.At(i), context);
}
if(all_swings != NULL) {
for(int i = 0; i < all_swings.Total(); i++)
g_drawer_ptr.DrawSwing(all_swings.At(i), all_swings, context);
}
}
ChartRedraw();
}
//+------------------------------------------------------------------+
//| Expert tick function - OPTIMIZADO |
//+------------------------------------------------------------------+
void OnTick()
{
// ==================================================================
// FASE 1: Análisis histórico inicial (solo una vez)
// ==================================================================
if(!is_initial_scan_done) {
int history_bars = 500;
if(Bars(_Symbol, PERIOD_CURRENT) < history_bars + 200) return;
// --- Preparación de Indicadores ---
bool all_indicators_ready = false;
Print("--- Preparando Datos de Indicadores... ---");
for(int i = 0; i < 300; i++) {
int atr_calc = BarsCalculated(g_atr_handle);
int rsi_calc = !InpUseRsiFilter ? history_bars : BarsCalculated(g_rsi_handle);
int vol_calc = !InpUseVolumeFilter ? history_bars : BarsCalculated(g_volume_handle);
int sto_calc = !InpUseStochasticFilter ? history_bars : BarsCalculated(g_sto_handle);
if(atr_calc >= history_bars && rsi_calc >= history_bars && vol_calc >= history_bars && sto_calc >= history_bars) {
all_indicators_ready = true;
Print("--- Todos los datos de indicadores están listos. ---");
break;
}
Sleep(100);
}
if(!all_indicators_ready) {
Print("FATAL: Falló la preparación de datos en 30 segundos.");
ExpertRemove();
return;
}
// --- Análisis Inicial ---
Print("--- Realizando Análisis Histórico Inicial... ---");
if(CopyRates(_Symbol, PERIOD_CURRENT, 0, history_bars, g_context_ptr.rates) < history_bars) return;
if(CopyBuffer(g_atr_handle, 0, 0, history_bars, g_context_ptr.atr_buffer) < history_bars) return;
if(InpUseRsiFilter && CopyBuffer(g_rsi_handle, 0, 0, history_bars, g_context_ptr.rsi_buffer) < history_bars) return;
if(InpUseVolumeFilter && CopyBuffer(g_volume_handle, 0, 0, history_bars, g_context_ptr.volume_buffer) < history_bars) return;
if(InpUseStochasticFilter) {
if(CopyBuffer(g_sto_handle, 0, 0, history_bars, g_context_ptr.sto_main_buffer) < history_bars ||
CopyBuffer(g_sto_handle, 1, 0, history_bars, g_context_ptr.sto_signal_buffer) < history_bars) return;
}
g_setupScanner_ptr.ScanHistory(g_context_ptr);
g_analyzer_ptr.Analyze(g_context_ptr);
is_initial_scan_done = true;
last_processed_bar_time = g_context_ptr.rates[0].time;
Print("--- Análisis Inicial Completo. El EA está ahora en vivo. ---");
ChartRedraw();
return;
}
// ==================================================================
// FASE 2: Operación normal - OPTIMIZADO
// ==================================================================
// --- Tarea 1: Trailing Stop (LIGERO - cada tick) ---
if(CheckPointer(g_tradeManager_ptr)) {
g_tradeManager_ptr.ManageActiveTrailing();
}
// --- Tarea 2: SL/TP Management (MEDIO - cada 10 segundos) ---
if(TimeCurrent() - last_sl_tp_check_time >= SL_TP_CHECK_INTERVAL) {
if(CheckPointer(g_tradeManager_ptr))
g_tradeManager_ptr.ManageUnsetSLTP();
last_sl_tp_check_time = TimeCurrent();
}
// --- Tarea 3: Detectar Nueva Barra ---
datetime current_bar_time = (datetime)SeriesInfoInteger(_Symbol, PERIOD_CURRENT, SERIES_LASTBAR_DATE);
if(current_bar_time == last_processed_bar_time) return; // No es nueva barra, salir
int new_bars_count = (int)((current_bar_time - last_processed_bar_time) / PeriodSeconds(PERIOD_CURRENT));
last_processed_bar_time = current_bar_time;
if(new_bars_count <= 0) return;
// --- Tarea 4: Actualizar Context (reutilizar memoria) ---
if(CopyRates(_Symbol, PERIOD_CURRENT, 0, g_context_ptr.bars_to_load, g_context_ptr.rates) < g_context_ptr.bars_to_load) return;
if(CopyBuffer(g_atr_handle, 0, 0, g_context_ptr.bars_to_load, g_context_ptr.atr_buffer) < g_context_ptr.bars_to_load) return;
if(InpUseRsiFilter && CopyBuffer(g_rsi_handle, 0, 0, g_context_ptr.bars_to_load, g_context_ptr.rsi_buffer) < g_context_ptr.bars_to_load) return;
if(InpUseVolumeFilter && CopyBuffer(g_volume_handle, 0, 0, g_context_ptr.bars_to_load, g_context_ptr.volume_buffer) < g_context_ptr.bars_to_load) return;
if(InpUseStochasticFilter && g_sto_handle != INVALID_HANDLE) {
if(CopyBuffer(g_sto_handle, 0, 0, g_context_ptr.bars_to_load, g_context_ptr.sto_main_buffer) < g_context_ptr.bars_to_load ||
CopyBuffer(g_sto_handle, 1, 0, g_context_ptr.bars_to_load, g_context_ptr.sto_signal_buffer) < g_context_ptr.bars_to_load) return;
}
// --- Tarea 5: Ejecutar todas las operaciones pesadas en OnNewBar ---
OnNewBar(g_context_ptr, new_bars_count);
}
//+------------------------------------------------------------------+