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 ; \
}