// include guard for MQL5 #ifndef __GATINGPIPELINE_MQH__ #define __GATINGPIPELINE_MQH__ #include // Warning: these macros expect the including translation unit to provide // the following symbols: // bool CircuitBreakerAllowed(string&) // bool CircuitCooldownAllowed(string&) // bool NewsAllowed(string&) // bool PromotionAllowed(string&) // bool RegimeAllowed(string&) // void LogGate(const string gate, const bool allow, const string phase, const ulong started) // bool UseSessionManager // bool UseCorrelationManager // bool UsePositionManager // bool TelemetryEnabled // bool NoConstraintsMode // CSessionManager *g_session_manager // CCorrelationManager *g_correlation_manager // CPositionManager *g_position_manager // CTelemetryStandard *g_tel_standard // int PMMaxOpenPositions // Provide lightweight fallbacks to avoid undefined symbol errors when a host EA // does not supply optional managers. Host code can override by defining before include. #ifndef GP_HAS_SESSION_MANAGER #define GP_HAS_SESSION_MANAGER 1 #endif #ifndef GP_HAS_CORRELATION_MANAGER #define GP_HAS_CORRELATION_MANAGER 1 #endif #ifndef GP_HAS_POSITION_MANAGER #define GP_HAS_POSITION_MANAGER 1 #endif #ifndef GP_HAS_TELEMETRY #define GP_HAS_TELEMETRY 1 #endif #ifndef GP_HAS_NO_CONSTRAINTS_FLAG #define GP_HAS_NO_CONSTRAINTS_FLAG 1 #endif #ifndef GP_STATIC_BOOL #define GP_STATIC_BOOL(name, value) static bool name = (value) #endif // Note: Host EA must declare these variables as input or global before including this file: // - bool UseSessionManager // - bool UseCorrelationManager // - bool UsePositionManager // - bool TelemetryEnabled // - bool NoConstraintsMode // - int PMMaxOpenPositions // - void LogGate(const string gate, const bool allow, const string phase, const ulong start_time) // - ulong NowMs() // // If not declared by host, macros will use fallback inline implementations below. #ifndef LogGate #define LogGate(gate, allow, phase, start_time) /* no-op */ #endif #ifndef NowMs #define NowMs() ((ulong)GetTickCount64()) #endif //+------------------------------------------------------------------+ //| GatingPipeline.mqh | //| Purpose: Centralize gate orchestration (macro-based) | //| Status: Used by EAs via macros; preserves existing behavior | //+------------------------------------------------------------------+ // These macros expand inline inside the EA translation unit and call the // EA-local functions/variables (e.g., NewsAllowed, LogGate, g_session_manager). // This avoids forward-declaration issues and preserves existing telemetry tags. // Helper: compute dynamic PM cap if PositionManager is available; otherwise use static input int GP_GetPMCap() { // PMMaxOpenPositions semantics: 0 = disabled/unlimited int cap = PMMaxOpenPositions; // When a PositionManager is present, allow it to adjust the cap adaptively if(UsePositionManager && CheckPointer(g_position_manager)!=POINTER_INVALID) { // ComputeDynamicMaxOpenPositions() returns a possibly adjusted cap; values <=0 mean 'unlimited' int dyn = (*g_position_manager).ComputeDynamicMaxOpenPositions(cap); // Only adopt positive values; otherwise keep existing semantics if(dyn!=cap) cap = dyn; } return cap; } #define GP_EARLY_GATES_BLOCK \ { \ string __gp_reason; ulong __gp_t0; \ __gp_t0=NowMs(); \ bool __cb_ok = CircuitBreakerAllowed(__gp_reason); LogGate("cb", __cb_ok, "early", __gp_t0); if(!__cb_ok) return false; \ __gp_t0=NowMs(); \ bool __news_ok = NewsAllowed(__gp_reason); LogGate("news", __news_ok, "early", __gp_t0); if(!__news_ok) return false; \ __gp_t0=NowMs(); \ bool __promo_ok= PromotionAllowed(__gp_reason); LogGate("promotion", __promo_ok, "early", __gp_t0); if(!__promo_ok) return false; \ __gp_t0=NowMs(); \ bool __reg_ok = RegimeAllowed(__gp_reason); LogGate("regime", __reg_ok, "early", __gp_t0); if(!__reg_ok) return false; \ bool __circ_ok = CircuitCooldownAllowed(__gp_reason); LogGate("circuit_cooldown", __circ_ok, "early", __gp_t0); if(!__circ_ok) return false; \ /* FR-02 Session gate */ \ if(UseSessionManager && CheckPointer(g_session_manager)!=POINTER_INVALID) \ { \ __gp_t0=NowMs(); \ bool __sess_ok = g_session_manager.IsSessionAllowed(__gp_reason); LogGate("session", __sess_ok, "early", __gp_t0); if(!__sess_ok) return false; \ } \ /* FR-05 Correlation gate */ \ if(UseCorrelationManager && CheckPointer(g_correlation_manager)!=POINTER_INVALID) \ { \ double __max_corr; \ __gp_t0=NowMs(); \ bool __corr_ok = g_correlation_manager.CheckCorrelationLimits(__gp_reason, __max_corr); LogGate("corr", __corr_ok, "early", __gp_t0); if(!__corr_ok) return false; \ } \ return true; \ } // include guard end is at file bottom #define GP_RISK4_GATES_BLOCK \ { \ string __gp_reason; ulong __gp_t0; \ __gp_t0=NowMs(); \ bool __cb_ok = CircuitBreakerAllowed(__gp_reason); LogGate("risk4_cb", __cb_ok, "risk4", __gp_t0); if(!__cb_ok) return false; \ __gp_t0=NowMs(); \ bool __news_ok = NewsAllowed(__gp_reason); LogGate("news", __news_ok, "risk4", __gp_t0); if(!__news_ok) return false; \ __gp_t0=NowMs(); \ bool __promo_ok= PromotionAllowed(__gp_reason);LogGate("promotion", __promo_ok,"risk4", __gp_t0); if(!__promo_ok) return false; \ __gp_t0=NowMs(); \ bool __reg_ok = RegimeAllowed(__gp_reason); LogGate("regime", __reg_ok, "risk4", __gp_t0); if(!__reg_ok) return false; \ __gp_t0=NowMs(); \ bool __circ_ok = CircuitCooldownAllowed(__gp_reason); LogGate("circuit_cooldown", __circ_ok, "risk4", __gp_t0); if(!__circ_ok) return false; \ /* FR-02 Session gate */ \ if(UseSessionManager && CheckPointer(g_session_manager)!=POINTER_INVALID) \ { \ __gp_t0=NowMs(); \ bool __sess_ok = g_session_manager.IsSessionAllowed(__gp_reason); LogGate("session", __sess_ok, "risk4", __gp_t0); if(!__sess_ok) return false; \ } \ /* FR-05 Correlation gate */ \ if(UseCorrelationManager && CheckPointer(g_correlation_manager)!=POINTER_INVALID) \ { \ double __max_corr; \ __gp_t0=NowMs(); \ bool __corr_ok = g_correlation_manager.CheckCorrelationLimits(__gp_reason, __max_corr); LogGate("corr", __corr_ok, "risk4", __gp_t0); if(!__corr_ok) return false; \ } \ /* FR-04 Position Manager gate */ \ if(UsePositionManager && CheckPointer(g_position_manager)!=POINTER_INVALID) \ { \ int __open_positions = PositionsTotal(); \ int __pm_cap = GP_GetPMCap(); \ /* Telemetry for PM gate params */ \ if(TelemetryEnabled && CheckPointer(g_tel_standard)!=POINTER_INVALID) \ { \ string __pm_det = StringFormat("open=%d cap=%d", __open_positions, __pm_cap); \ (*g_tel_standard).LogGateParams(_Symbol, (int)_Period, "pm", __pm_det); \ } \ bool __pm_ok = (__pm_cap<=0 ? true : (__open_positions < __pm_cap)); \ __gp_t0=NowMs(); LogGate("pm", __pm_ok, "risk4", __gp_t0); if(!__pm_ok) return false; \ } \ return true; \ } #endif // __GATINGPIPELINE_MQH__ // Variants for LiveEA semantics (no CB in early; early uses NoConstraintsMode to shadow-bypass blocks) #define GP_EARLY_GATES_BLOCK_NO_CB_SHADOW \ { \ string __gp_reason; ulong __gp_t0; \ __gp_t0=NowMs(); \ bool __news_ok = NewsAllowed(__gp_reason); LogGate("news", __news_ok, "early", __gp_t0); if(!__news_ok && !NoConstraintsMode) return false; \ __gp_t0=NowMs(); \ bool __promo_ok= PromotionAllowed(__gp_reason);LogGate("promotion", __promo_ok,"early", __gp_t0); if(!__promo_ok && !NoConstraintsMode) return false; \ __gp_t0=NowMs(); \ bool __reg_ok = RegimeAllowed(__gp_reason); LogGate("regime", __reg_ok, "early", __gp_t0); if(!__reg_ok && !NoConstraintsMode) return false; \ __gp_t0=NowMs(); \ bool __circ_ok = CircuitCooldownAllowed(__gp_reason); LogGate("circuit_cooldown", __circ_ok, "early", __gp_t0); /* early only logs circ in Live; honor NoConstraints */ if(!__circ_ok && !NoConstraintsMode) return false; \ /* FR-02 Session gate (diagnostic unless constraints enabled) */ \ if(UseSessionManager && CheckPointer(g_session_manager)!=POINTER_INVALID) \ { \ __gp_t0=NowMs(); \ bool __sess_ok = g_session_manager.IsSessionAllowed(__gp_reason); LogGate("session", __sess_ok, "early", __gp_t0); if(!__sess_ok && !NoConstraintsMode) return false; \ } \ /* FR-05 Correlation gate */ \ if(UseCorrelationManager && CheckPointer(g_correlation_manager)!=POINTER_INVALID) \ { \ double __max_corr; \ __gp_t0=NowMs(); \ bool __corr_ok = g_correlation_manager.CheckCorrelationLimits(__gp_reason, __max_corr); LogGate("corr", __corr_ok, "early", __gp_t0); if(!__corr_ok && !NoConstraintsMode) return false; \ } \ return true; \ } // Variant for LiveEA risk4 (no CB; strict fail-closed) #define GP_RISK4_GATES_BLOCK_NO_CB \ { \ string __gp_reason; ulong __gp_t0; \ __gp_t0=NowMs(); \ bool __news_ok = NewsAllowed(__gp_reason); LogGate("news", __news_ok, "risk4", __gp_t0); if(!__news_ok) return false; \ __gp_t0=NowMs(); \ bool __promo_ok= PromotionAllowed(__gp_reason);LogGate("promotion", __promo_ok,"risk4", __gp_t0); if(!__promo_ok) return false; \ __gp_t0=NowMs(); \ bool __reg_ok = RegimeAllowed(__gp_reason); LogGate("regime", __reg_ok, "risk4", __gp_t0); if(!__reg_ok) return false; \ __gp_t0=NowMs(); \ bool __circ_ok = CircuitCooldownAllowed(__gp_reason); LogGate("circuit_cooldown", __circ_ok, "risk4", __gp_t0); if(!__circ_ok) return false; \ if(UseSessionManager && CheckPointer(g_session_manager)!=POINTER_INVALID) \ { \ __gp_t0=NowMs(); \ bool __sess_ok = g_session_manager.IsSessionAllowed(__gp_reason); LogGate("session", __sess_ok, "risk4", __gp_t0); if(!__sess_ok) return false; \ } \ if(UseCorrelationManager && CheckPointer(g_correlation_manager)!=POINTER_INVALID) \ { \ double __max_corr; \ __gp_t0=NowMs(); \ bool __corr_ok = g_correlation_manager.CheckCorrelationLimits(__gp_reason, __max_corr); LogGate("corr", __corr_ok, "risk4", __gp_t0); if(!__corr_ok) return false; \ } \ if(UsePositionManager && CheckPointer(g_position_manager)!=POINTER_INVALID) \ { \ int __open_positions = PositionsTotal(); \ int __pm_cap = GP_GetPMCap(); \ bool __pm_ok = (__pm_cap<=0 ? true : (__open_positions < __pm_cap)); \ __gp_t0=NowMs(); LogGate("pm", __pm_ok, "risk4", __gp_t0); if(!__pm_ok) return false; \ } \ return true; \ }