forked from syncoolz/EA_SMC_Mql5
361 lines
No EOL
36 KiB
MQL5
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);
|
|
}
|
|
//+------------------------------------------------------------------+ |