2025-09-20 02:27:35 -04:00 | | | // include guard for MQL5
|
| | | #ifndef __GATINGPIPELINE_MQH__
|
| | | #define __GATINGPIPELINE_MQH__
|
| | |
|
2025-10-16 18:03:12 -04:00 | | | #include <Trade/Trade.mqh>
|
| | |
|
| | | // 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
|
| | |
|
2025-09-20 02:27:35 -04:00 | | | //+------------------------------------------------------------------+
|
| | | //| 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; \
|
| | | }
|