| //+------------------------------------------------------------------+
|
| //| DualEA_MasterIntegration.mqh - Complete P0/P1 Integration |
|
| //| Master include file that initializes all hardened components |
|
| //| Version: 2.0 - Comprehensive EA Hardening & Intelligence Upgrade |
|
| //+------------------------------------------------------------------+
|
| #ifndef DUALEA_MASTERINTEGRATION_MQH
|
| #define DUALEA_MASTERINTEGRATION_MQH
|
|
|
| //+------------------------------------------------------------------+
|
| //| P0 Components - Critical Fixes |
|
| //+------------------------------------------------------------------+
|
| #include "CShadowLogger.mqh" // P0-1: Atomic CSV writes
|
| #include "CGateFeatureCache.mqh" // P0-5: Feature caching
|
|
|
| //+------------------------------------------------------------------+
|
| //| P1 Components - Architecture Upgrades |
|
| //+------------------------------------------------------------------+
|
| #include "CSQLiteKnowledgeBase.mqh" // P1-1: SQLite KB
|
| #include "CInsightGateBridge.mqh" // P1-2: O(1) insights bridge
|
| #include "CRegimeAwareStrategy.mqh" // P1-3: Regime adaptation
|
| #include "CSystemMonitor.mqh" // P1-4: Health circuit breaker
|
| // Replaced Redis with SQLite - zero external dependencies
|
| #include "CSQLiteExplorationCounter.mqh"// P1-5: Redis counters
|
| #include "CPositionManager.mqh" // P1-6: Correlation sizing
|
|
|
| // Include existing components
|
| #include "EnhancedEfficientGateSystem.mqh"
|
| // ONNX support is provided by CMLPolishGateEnhanced and ModelPredictor.
|
|
|
| //+------------------------------------------------------------------+
|
| //| Configuration Structure |
|
| //+------------------------------------------------------------------+
|
| struct SDualEAConfig
|
| {
|
| // P0-1: Shadow logging
|
| bool shadow_logging_enabled;
|
| bool shadow_mode_only;
|
| string shadow_log_directory;
|
|
|
| // P0-4: ONNX monitoring
|
| bool onnx_health_monitor_enabled;
|
| int onnx_max_latency_ms;
|
|
|
| // P0-5: Feature cache
|
| int feature_cache_max_age_seconds;
|
|
|
| // P1-1: SQLite
|
| bool sqlite_enabled;
|
| string sqlite_db_name;
|
|
|
| // P1-2: Insight bridge
|
| int insight_cache_sync_seconds;
|
|
|
| // P1-4: System monitor
|
| bool circuit_breaker_enabled;
|
| double max_tick_latency_ms;
|
| double max_error_rate_per_hour;
|
| int circuit_breaker_cooldown_minutes;
|
|
|
| // P1-5: Redis
|
| bool redis_enabled;
|
| string redis_host;
|
| int redis_port;
|
|
|
| // P1-6: Position management
|
| bool correlation_sizing_enabled;
|
| bool volatility_exits_enabled;
|
| double max_risk_per_trade_pct;
|
| double max_total_risk_pct;
|
| int max_positions;
|
|
|
| void SetDefaults()
|
| {
|
| // P0 defaults
|
| shadow_logging_enabled = true;
|
| shadow_mode_only = false;
|
| shadow_log_directory = "DualEA\\ShadowLogs";
|
|
|
| // P0-4 defaults
|
| onnx_health_monitor_enabled = true;
|
| onnx_max_latency_ms = 100;
|
|
|
| // P0-5 defaults
|
| feature_cache_max_age_seconds = 5;
|
|
|
| // P1-1 defaults
|
| sqlite_enabled = true;
|
| sqlite_db_name = "dualea_kb.db";
|
|
|
| // P1-2 defaults
|
| insight_cache_sync_seconds = 60;
|
|
|
| // P1-4 defaults
|
| circuit_breaker_enabled = true;
|
| max_tick_latency_ms = 50.0;
|
| max_error_rate_per_hour = 50.0;
|
| circuit_breaker_cooldown_minutes = 15;
|
|
|
| // P1-5 defaults
|
| redis_enabled = false; // Disabled by default (requires Redis server)
|
| redis_host = "127.0.0.1";
|
| redis_port = 6379;
|
|
|
| // P1-6 defaults
|
| correlation_sizing_enabled = true;
|
| volatility_exits_enabled = true;
|
| max_risk_per_trade_pct = 1.0;
|
| max_total_risk_pct = 5.0;
|
| max_positions = 10;
|
| }
|
| };
|
|
|
| //+------------------------------------------------------------------+
|
| //| Dual EA Master Controller |
|
| //+------------------------------------------------------------------+
|
| class CDualEAMasterController
|
| {
|
| private:
|
| SDualEAConfig m_config;
|
| bool m_initialized;
|
| datetime m_last_status_log;
|
|
|
| // Component references
|
| CShadowLogger* m_shadow_logger;
|
| CGateFeatureCache* m_feature_cache;
|
| CSQLiteKnowledgeBase* m_sqlite_kb;
|
| CInsightGateBridge* m_insight_bridge;
|
| CRegimeAwareStrategy* m_regime_strategy;
|
| CSystemMonitor* m_system_monitor;
|
| CSQLiteExplorationCounter* m_explore_counter;
|
| CPositionManager* m_position_manager;
|
|
|
| public:
|
| // Constructor
|
| CDualEAMasterController()
|
| {
|
| m_config.SetDefaults();
|
| m_initialized = false;
|
| m_last_status_log = 0;
|
| m_shadow_logger = NULL;
|
| m_feature_cache = NULL;
|
| m_sqlite_kb = NULL;
|
| m_insight_bridge = NULL;
|
| m_regime_strategy = NULL;
|
| m_system_monitor = NULL;
|
| m_explore_counter = NULL;
|
| m_position_manager = NULL;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Initialize all components |
|
| //+------------------------------------------------------------------+
|
| bool Initialize(const SDualEAConfig &config)
|
| {
|
| m_config = config;
|
|
|
| Print("=== DualEA Master Controller v2.0 Initializing ===");
|
|
|
| // P0-5: Initialize feature cache first (others depend on it)
|
| if(!InitializeFeatureCache()) return false;
|
|
|
| // P1-1: Initialize SQLite KB
|
| if(m_config.sqlite_enabled)
|
| {
|
| if(!InitializeSQLiteKB()) return false;
|
| }
|
|
|
| // P1-3: Initialize regime strategy (depends on feature cache)
|
| if(!InitializeRegimeStrategy()) return false;
|
|
|
| // P1-2: Initialize insight bridge (depends on SQLite KB)
|
| if(m_config.sqlite_enabled)
|
| {
|
| if(!InitializeInsightBridge()) return false;
|
| }
|
|
|
| // P1-4: Initialize system monitor
|
| if(m_config.circuit_breaker_enabled)
|
| {
|
| if(!InitializeSystemMonitor()) return false;
|
| }
|
|
|
| // P1-5: Initialize exploration counter (SQLite-based)
|
| if(!InitializeExploreCounter()) return false;
|
|
|
| // P1-6: Initialize position manager (depends on feature cache and regime)
|
| if(!InitializePositionManager()) return false;
|
|
|
| // P0-1: Initialize shadow logger
|
| if(m_config.shadow_logging_enabled)
|
| {
|
| if(!InitializeShadowLogger()) return false;
|
| }
|
|
|
| m_initialized = true;
|
| Print("=== DualEA Master Controller v2.0 Ready ===");
|
|
|
| return true;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Component initializers |
|
| //+------------------------------------------------------------------+
|
| bool InitializeFeatureCache()
|
| {
|
| m_feature_cache = new CGateFeatureCache();
|
| if(!m_feature_cache.Initialize())
|
| {
|
| Print("[MasterController] ERROR: Feature cache initialization failed");
|
| return false;
|
| }
|
|
|
| // Set global reference for gates
|
| g_gate_feature_cache = m_feature_cache;
|
|
|
| Print("[MasterController] P0-5: Feature cache initialized");
|
| return true;
|
| }
|
|
|
| bool InitializeSQLiteKB()
|
| {
|
| m_sqlite_kb = new CSQLiteKnowledgeBase(m_config.sqlite_db_name);
|
| if(!m_sqlite_kb.Initialize())
|
| {
|
| Print("[MasterController] WARNING: SQLite KB init failed, continuing with reduced functionality");
|
| // Don't fail completely - we can work without SQLite
|
| delete m_sqlite_kb;
|
| m_sqlite_kb = NULL;
|
| m_config.sqlite_enabled = false;
|
| return true;
|
| }
|
|
|
| g_sqlite_kb = m_sqlite_kb;
|
| Print("[MasterController] P1-1: SQLite KB initialized");
|
| return true;
|
| }
|
|
|
| bool InitializeInsightBridge()
|
| {
|
| m_insight_bridge = new CInsightGateBridge(m_sqlite_kb);
|
| if(!m_insight_bridge.Initialize(m_sqlite_kb))
|
| {
|
| Print("[MasterController] WARNING: Insight bridge init failed");
|
| delete m_insight_bridge;
|
| m_insight_bridge = NULL;
|
| return true; // Don't fail completely
|
| }
|
|
|
| // CRITICAL: Preload historical data to populate bridge stats immediately
|
| m_insight_bridge.PreloadHotStrategies();
|
|
|
| g_insight_gate_bridge = m_insight_bridge;
|
| Print("[MasterController] P1-2: Insight-Gate bridge initialized with historical data");
|
| return true;
|
| }
|
|
|
| bool InitializeRegimeStrategy()
|
| {
|
| m_regime_strategy = new CRegimeAwareStrategy(m_feature_cache);
|
|
|
| g_regime_strategy = m_regime_strategy;
|
| Print("[MasterController] P1-3: Regime-aware strategy initialized");
|
| return true;
|
| }
|
|
|
| bool InitializeSystemMonitor()
|
| {
|
| m_system_monitor = new CSystemMonitor();
|
|
|
| // Thresholds are configured internally via SHealthThresholds.SetDefaults()
|
| // m_system_monitor.SetThresholds() is not available - using default thresholds
|
|
|
| g_system_monitor = m_system_monitor;
|
| Print("[MasterController] P1-4: System monitor with circuit breaker initialized");
|
| return true;
|
| }
|
|
|
| bool InitializeExploreCounter()
|
| {
|
| m_explore_counter = new CSQLiteExplorationCounter();
|
| if(!m_explore_counter.Initialize())
|
| {
|
| Print("[MasterController] WARNING: Exploration counter init failed, using fallback");
|
| delete m_explore_counter;
|
| m_explore_counter = NULL;
|
| return true; // Don't fail - fallback is built-in
|
| }
|
|
|
| g_sqliteCounter = m_explore_counter;
|
| Print("[MasterController] P1-5: SQLite exploration counter initialized");
|
| return true;
|
| }
|
|
|
| bool InitializePositionManager()
|
| {
|
| m_position_manager = new CPositionManager(m_feature_cache, m_regime_strategy);
|
|
|
| // Configure
|
| m_position_manager.SetMaxPositions(m_config.max_positions);
|
| m_position_manager.SetMaxRiskPerTrade(m_config.max_risk_per_trade_pct);
|
| m_position_manager.SetMaxTotalRisk(m_config.max_total_risk_pct);
|
|
|
| SVolatilityExitConfig vol_config;
|
| vol_config.SetDefaults();
|
| m_position_manager.SetVolatilityExitConfig(vol_config);
|
|
|
| g_position_manager = m_position_manager;
|
| Print("[MasterController] P1-6: Position manager with correlation sizing initialized");
|
| return true;
|
| }
|
|
|
| bool InitializeShadowLogger()
|
| {
|
| m_shadow_logger = new CShadowLogger();
|
|
|
| if(!m_shadow_logger.Initialize(m_config.shadow_mode_only, m_config.shadow_log_directory))
|
| {
|
| Print("[MasterController] WARNING: Shadow logger init failed");
|
| delete m_shadow_logger;
|
| m_shadow_logger = NULL;
|
| return true; // Don't fail
|
| }
|
|
|
| Print("[MasterController] P0-1: Shadow logger with atomic CSV initialized");
|
| return true;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| OnTick processing - call from EA's OnTick() |
|
| //+------------------------------------------------------------------+
|
| void OnTick()
|
| {
|
| if(!m_initialized) return;
|
|
|
| // P0-5: Update feature cache
|
| if(m_feature_cache != NULL)
|
| m_feature_cache.Update();
|
|
|
| // P1-3: Update regime detection
|
| if(m_regime_strategy != NULL)
|
| m_regime_strategy.Update();
|
|
|
| // P1-4: Update system monitor
|
| if(m_system_monitor != NULL)
|
| m_system_monitor.OnTickUpdate();
|
|
|
| // P1-6: Check volatility exits
|
| if(m_position_manager != NULL && !m_config.shadow_mode_only)
|
| m_position_manager.CheckVolatilityExits();
|
|
|
| // P1-2: Sync insight bridge periodically
|
| if(m_insight_bridge != NULL && m_system_monitor != NULL)
|
| {
|
| static int tick_counter = 0;
|
| tick_counter++;
|
| if(tick_counter % 600 == 0) // Every ~10 seconds (assuming 60 ticks/sec)
|
| {
|
| m_insight_bridge.OnTickSync();
|
| }
|
| }
|
|
|
| // Log status periodically
|
| if(TimeCurrent() - m_last_status_log > 300) // Every 5 minutes
|
| {
|
| LogSystemStatus();
|
| m_last_status_log = TimeCurrent();
|
| }
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Check if trading is allowed (circuit breaker) |
|
| //+------------------------------------------------------------------+
|
| bool IsTradingAllowed(string &reason)
|
| {
|
| reason = "";
|
|
|
| // P1-4: Check system monitor circuit breaker
|
| if(m_system_monitor != NULL && m_system_monitor.IsCircuitBreakerActive())
|
| {
|
| reason = "Circuit breaker: " + m_system_monitor.GetCircuitBreakerReason();
|
| return false;
|
| }
|
|
|
| // P1-3: Check regime allows trading
|
| if(m_regime_strategy != NULL)
|
| {
|
| if(!m_regime_strategy.IsTradingAllowed(reason))
|
| {
|
| return false;
|
| }
|
| }
|
|
|
| return true;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Process trade signal through all gates |
|
| //+------------------------------------------------------------------+
|
| bool ProcessTradeSignal(TradingSignal &signal,
|
| CEfficientGateManagerEnhanced &gate_manager,
|
| string &block_reason)
|
| {
|
| // P1-3: Apply regime-adjusted parameters
|
| if(m_regime_strategy != NULL)
|
| {
|
| double min_confidence = m_regime_strategy.GetMinConfidenceThreshold();
|
| // Could adjust gate thresholds here
|
| }
|
|
|
| // P1-2: Fast gate decision using insights
|
| if(m_insight_bridge != NULL)
|
| {
|
| double signal_confidence = m_insight_bridge.GetSignalConfidence(
|
| signal.strategy, signal.symbol);
|
|
|
| if(signal_confidence < 0.4)
|
| {
|
| // Adjust-only mode: do not block, but penalize confidence and annotate reason
|
| signal.confidence = MathMax(0.05, MathMin(1.0, signal.confidence * signal_confidence));
|
| block_reason = "Low insight confidence (soft): " + DoubleToString(signal_confidence, 2);
|
| }
|
| }
|
|
|
| // P1-6: Check position limits
|
| if(m_position_manager != NULL)
|
| {
|
| double risk_amount = 0; // Calculate based on signal
|
| if(!m_position_manager.CanOpenPosition(signal.symbol, signal.type,
|
| risk_amount, block_reason))
|
| {
|
| return false;
|
| }
|
| }
|
|
|
| // Process through gate cascade
|
| CSignalDecision decision;
|
| return gate_manager.ProcessSignalEnhanced(signal, decision, block_reason);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Log gate decision to shadow log |
|
| //+------------------------------------------------------------------+
|
| void LogGateDecision(const string &gate_name, const TradingSignal &signal,
|
| bool passed, double confidence, double threshold)
|
| {
|
| if(m_shadow_logger != NULL)
|
| {
|
| SShadowLogEntry entry;
|
| entry.Init(signal.symbol, signal.direction == 0 ? "BUY" : "SELL",
|
| signal.price, signal.volume, signal.strategy);
|
|
|
| // Convert gate_name to gate number for entry
|
| int gate_num = 0;
|
| if(gate_name == "G1") gate_num = 0;
|
| else if(gate_name == "G2") gate_num = 1;
|
| else if(gate_name == "G3") gate_num = 2;
|
| else if(gate_name == "G4") gate_num = 3;
|
| else if(gate_name == "G5") gate_num = 4;
|
| else if(gate_name == "G6") gate_num = 5;
|
| else if(gate_name == "G7") gate_num = 6;
|
| else if(gate_name == "G8") gate_num = 7;
|
|
|
| entry.gate_passed[gate_num] = passed;
|
| entry.gate_confidence[gate_num] = confidence;
|
| entry.gate_threshold[gate_num] = threshold;
|
| entry.gate_block_reason[gate_num] = passed ? "" : "Below threshold";
|
|
|
| m_shadow_logger.LogGateDecision(entry);
|
| }
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Record completed trade |
|
| //+------------------------------------------------------------------+
|
| void RecordTrade(const STradeRecord &trade)
|
| {
|
| // P1-1: Log to SQLite
|
| if(m_sqlite_kb != NULL)
|
| {
|
| m_sqlite_kb.LogTrade(trade);
|
| }
|
|
|
| // P1-2: Update insight bridge
|
| if(m_insight_bridge != NULL)
|
| {
|
| m_insight_bridge.OnTradeCompleted(trade.strategy, trade.symbol,
|
| trade.pnl, trade.r_multiple);
|
| }
|
|
|
| // P1-4: Update system monitor
|
| if(m_system_monitor != NULL)
|
| {
|
| m_system_monitor.RecordTrade();
|
| }
|
|
|
| // P1-6: Remove from position tracking
|
| if(m_position_manager != NULL && trade.id > 0)
|
| {
|
| // m_position_manager->RemovePosition((ulong)trade.id);
|
| }
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Get position size with all adjustments |
|
| //+------------------------------------------------------------------+
|
| double CalculatePositionSize(const TradingSignal &signal, double risk_pct)
|
| {
|
| if(m_position_manager == NULL) return 0;
|
|
|
| double account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
|
| return m_position_manager.CalculatePositionSize(
|
| signal.symbol,
|
| signal.type,
|
| signal.price,
|
| signal.sl,
|
| risk_pct,
|
| account_balance
|
| );
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Log system status |
|
| //+------------------------------------------------------------------+
|
| void LogSystemStatus()
|
| {
|
| string status = "=== DualEA System Status ===\n";
|
|
|
| // P1-4: System monitor status
|
| if(m_system_monitor != NULL)
|
| {
|
| status += "Health: " + m_system_monitor.GetHealthReport() + "\n";
|
| }
|
|
|
| // P1-3: Regime status
|
| if(m_regime_strategy != NULL)
|
| {
|
| status += "Regime: " + m_regime_strategy.RegimeToString(
|
| m_regime_strategy.GetCurrentRegime()) + "\n";
|
| }
|
|
|
| // P1-6: Position status
|
| if(m_position_manager != NULL)
|
| {
|
| status += "Positions: " + m_position_manager.GetRiskReport() + "\n";
|
| }
|
|
|
| // P1-2: Bridge status
|
| if(m_insight_bridge != NULL)
|
| {
|
| double hit_rate, avg_lookup;
|
| int cache_size;
|
| m_insight_bridge.GetStats(hit_rate, avg_lookup, cache_size);
|
| status += StringFormat("Insights: HitRate=%.1f%% Latency=%.2fus Cache=%d\n",
|
| hit_rate * 100, avg_lookup, cache_size);
|
| }
|
|
|
| Print(status);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Shutdown all components |
|
| //+------------------------------------------------------------------+
|
| void Shutdown()
|
| {
|
| Print("=== DualEA Master Controller v2.0 Shutting Down ===");
|
|
|
| // Save all data
|
| if(m_sqlite_kb != NULL) m_sqlite_kb.Close();
|
|
|
| // Cleanup
|
| if(m_explore_counter != NULL) { if(g_sqliteCounter == m_explore_counter) g_sqliteCounter = NULL; delete m_explore_counter; m_explore_counter = NULL; }
|
| if(m_shadow_logger != NULL) { delete m_shadow_logger; m_shadow_logger = NULL; }
|
| if(m_position_manager != NULL) { if(g_position_manager == m_position_manager) g_position_manager = NULL; delete m_position_manager; m_position_manager = NULL; }
|
| if(m_system_monitor != NULL) { if(g_system_monitor == m_system_monitor) g_system_monitor = NULL; delete m_system_monitor; m_system_monitor = NULL; }
|
| if(m_insight_bridge != NULL) { if(g_insight_gate_bridge == m_insight_bridge) g_insight_gate_bridge = NULL; delete m_insight_bridge; m_insight_bridge = NULL; }
|
| if(m_regime_strategy != NULL) { if(g_regime_strategy == m_regime_strategy) g_regime_strategy = NULL; delete m_regime_strategy; m_regime_strategy = NULL; }
|
| if(m_sqlite_kb != NULL) { if(g_sqlite_kb == m_sqlite_kb) g_sqlite_kb = NULL; delete m_sqlite_kb; m_sqlite_kb = NULL; }
|
| if(m_feature_cache != NULL) { if(g_gate_feature_cache == m_feature_cache) g_gate_feature_cache = NULL; delete m_feature_cache; m_feature_cache = NULL; }
|
|
|
| m_initialized = false;
|
| Print("=== DualEA Master Controller v2.0 Shutdown Complete ===");
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Getters |
|
| //+------------------------------------------------------------------+
|
| CRegimeAwareStrategy* GetRegimeStrategy() { return m_regime_strategy; }
|
| CPositionManager* GetPositionManager() { return m_position_manager; }
|
| CSystemMonitor* GetSystemMonitor() { return m_system_monitor; }
|
| CInsightGateBridge* GetInsightBridge() { return m_insight_bridge; }
|
| CSQLiteKnowledgeBase* GetSQLiteKB() { return m_sqlite_kb; }
|
| bool IsInitialized() { return m_initialized; }
|
| };
|
|
|
| // Global master controller instance
|
| CDualEAMasterController* g_master_controller = NULL;
|
|
|
| //+------------------------------------------------------------------+
|
| //| Initialize DualEA Master Controller |
|
| //+------------------------------------------------------------------+
|
| bool InitializeDualEAMasterController(const SDualEAConfig &config)
|
| {
|
| if(g_master_controller != NULL)
|
| {
|
| g_master_controller.Shutdown();
|
| delete g_master_controller;
|
| }
|
|
|
| g_master_controller = new CDualEAMasterController();
|
| return g_master_controller.Initialize(config);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Shutdown DualEA Master Controller |
|
| //+------------------------------------------------------------------+
|
| void ShutdownDualEAMasterController()
|
| {
|
| if(g_master_controller != NULL)
|
| {
|
| g_master_controller.Shutdown();
|
| delete g_master_controller;
|
| g_master_controller = NULL;
|
| }
|
| }
|
|
|
| #endif // DUALEA_MASTERINTEGRATION_MQH
|