//+------------------------------------------------------------------+ //| 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 #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); } //+------------------------------------------------------------------+