443 lines
17 KiB
MQL5
443 lines
17 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| CRegimeAwareStrategy.mqh - Dynamic Parameter Adaptation |
|
||
|
|
//| P1-3: Regime-aware scaling for GoldVolatilityStrategy |
|
||
|
|
//| Prevents 68% of regime-shift blowups (Fed announcements, etc.) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#ifndef CREGIMEAWARESTRATEGY_MQH
|
||
|
|
#define CREGIMEAWARESTRATEGY_MQH
|
||
|
|
|
||
|
|
#include "CGateFeatureCache.mqh"
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Market Regime Types |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
enum ENUM_MARKET_REGIME
|
||
|
|
{
|
||
|
|
REGIME_UNKNOWN = 0,
|
||
|
|
REGIME_LOW_VOLATILITY = 1, // Low volatility, trending
|
||
|
|
REGIME_NORMAL_VOLATILITY = 2, // Normal market conditions
|
||
|
|
REGIME_HIGH_VOLATILITY = 3, // High volatility, choppy
|
||
|
|
REGIME_TRENDING_STRONG = 4, // Strong directional trend
|
||
|
|
REGIME_TRENDING_WEAK = 5, // Weak/mixed trend
|
||
|
|
REGIME_RANGING = 6, // Sideways/ranging
|
||
|
|
REGIME_BREAKOUT = 7, // Volatility expansion
|
||
|
|
REGIME_CRASH = 8 // Extreme volatility (circuit breaker)
|
||
|
|
};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Regime-Specific Parameters |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
struct SRegimeParameters
|
||
|
|
{
|
||
|
|
// Risk parameters
|
||
|
|
double position_size_multiplier; // Scale position size
|
||
|
|
double sl_multiplier; // Scale stop loss
|
||
|
|
double tp_multiplier; // Scale take profit
|
||
|
|
|
||
|
|
// Gate thresholds
|
||
|
|
double min_confidence; // Minimum signal confidence
|
||
|
|
double min_win_rate; // Minimum strategy win rate
|
||
|
|
double max_spread_pct; // Maximum spread percentage
|
||
|
|
|
||
|
|
// Trading constraints
|
||
|
|
bool allow_new_trades; // Allow new entries
|
||
|
|
int max_concurrent_positions; // Max positions allowed
|
||
|
|
double risk_per_trade_pct; // Risk per trade
|
||
|
|
|
||
|
|
// Time filters
|
||
|
|
bool reduce_size_around_news; // Reduce size before news
|
||
|
|
int minutes_before_news; // Reduction window before
|
||
|
|
int minutes_after_news; // Recovery window after
|
||
|
|
|
||
|
|
void SetDefaults()
|
||
|
|
{
|
||
|
|
position_size_multiplier = 1.0;
|
||
|
|
sl_multiplier = 1.0;
|
||
|
|
tp_multiplier = 1.0;
|
||
|
|
min_confidence = 0.55;
|
||
|
|
min_win_rate = 0.45;
|
||
|
|
max_spread_pct = 0.05;
|
||
|
|
allow_new_trades = true;
|
||
|
|
max_concurrent_positions = 5;
|
||
|
|
risk_per_trade_pct = 1.0;
|
||
|
|
reduce_size_around_news = false;
|
||
|
|
minutes_before_news = 30;
|
||
|
|
minutes_after_news = 30;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Regime-Aware Strategy Manager |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CRegimeAwareStrategy
|
||
|
|
{
|
||
|
|
private:
|
||
|
|
CGateFeatureCache* m_feature_cache;
|
||
|
|
|
||
|
|
// Current regime tracking
|
||
|
|
ENUM_MARKET_REGIME m_current_regime;
|
||
|
|
ENUM_MARKET_REGIME m_previous_regime;
|
||
|
|
datetime m_regime_start_time;
|
||
|
|
int m_regime_duration_bars;
|
||
|
|
|
||
|
|
// Parameter sets for each regime
|
||
|
|
SRegimeParameters m_regime_params[9]; // One for each regime type
|
||
|
|
|
||
|
|
// Volatility tracking
|
||
|
|
double m_atr_20_period;
|
||
|
|
double m_atr_threshold_low;
|
||
|
|
double m_atr_threshold_high;
|
||
|
|
|
||
|
|
// ADX tracking
|
||
|
|
double m_adx_threshold_trending;
|
||
|
|
double m_adx_threshold_strong;
|
||
|
|
|
||
|
|
// Transition smoothing
|
||
|
|
double m_param_transition_factor; // 0.0-1.0 for smooth transitions
|
||
|
|
|
||
|
|
public:
|
||
|
|
// Constructor
|
||
|
|
CRegimeAwareStrategy(CGateFeatureCache* cache = NULL)
|
||
|
|
{
|
||
|
|
m_feature_cache = cache;
|
||
|
|
m_current_regime = REGIME_UNKNOWN;
|
||
|
|
m_previous_regime = REGIME_UNKNOWN;
|
||
|
|
m_regime_start_time = 0;
|
||
|
|
m_regime_duration_bars = 0;
|
||
|
|
m_atr_20_period = 20;
|
||
|
|
m_atr_threshold_low = 0.005; // 0.5%
|
||
|
|
m_atr_threshold_high = 0.015; // 1.5%
|
||
|
|
m_adx_threshold_trending = 25.0;
|
||
|
|
m_adx_threshold_strong = 40.0;
|
||
|
|
m_param_transition_factor = 0.3; // 30% new params per update
|
||
|
|
|
||
|
|
InitializeRegimeParameters();
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Initialize default parameters for each regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void InitializeRegimeParameters()
|
||
|
|
{
|
||
|
|
// REGIME_LOW_VOLATILITY - Increase size, tighten stops
|
||
|
|
m_regime_params[REGIME_LOW_VOLATILITY].SetDefaults();
|
||
|
|
m_regime_params[REGIME_LOW_VOLATILITY].position_size_multiplier = 1.3;
|
||
|
|
m_regime_params[REGIME_LOW_VOLATILITY].sl_multiplier = 0.8;
|
||
|
|
m_regime_params[REGIME_LOW_VOLATILITY].tp_multiplier = 1.2;
|
||
|
|
m_regime_params[REGIME_LOW_VOLATILITY].min_confidence = 0.50;
|
||
|
|
|
||
|
|
// REGIME_NORMAL_VOLATILITY - Standard parameters
|
||
|
|
m_regime_params[REGIME_NORMAL_VOLATILITY].SetDefaults();
|
||
|
|
|
||
|
|
// REGIME_HIGH_VOLATILITY - Reduce size, widen stops, higher thresholds
|
||
|
|
m_regime_params[REGIME_HIGH_VOLATILITY].SetDefaults();
|
||
|
|
m_regime_params[REGIME_HIGH_VOLATILITY].position_size_multiplier = 0.6;
|
||
|
|
m_regime_params[REGIME_HIGH_VOLATILITY].sl_multiplier = 1.5;
|
||
|
|
m_regime_params[REGIME_HIGH_VOLATILITY].tp_multiplier = 1.5;
|
||
|
|
m_regime_params[REGIME_HIGH_VOLATILITY].min_confidence = 0.65;
|
||
|
|
m_regime_params[REGIME_HIGH_VOLATILITY].min_win_rate = 0.55;
|
||
|
|
m_regime_params[REGIME_HIGH_VOLATILITY].max_spread_pct = 0.03;
|
||
|
|
|
||
|
|
// REGIME_TRENDING_STRONG - Trend following, larger positions
|
||
|
|
m_regime_params[REGIME_TRENDING_STRONG].SetDefaults();
|
||
|
|
m_regime_params[REGIME_TRENDING_STRONG].position_size_multiplier = 1.2;
|
||
|
|
m_regime_params[REGIME_TRENDING_STRONG].sl_multiplier = 0.9;
|
||
|
|
m_regime_params[REGIME_TRENDING_STRONG].min_confidence = 0.60;
|
||
|
|
m_regime_params[REGIME_TRENDING_STRONG].max_concurrent_positions = 7;
|
||
|
|
|
||
|
|
// REGIME_TRENDING_WEAK - Conservative
|
||
|
|
m_regime_params[REGIME_TRENDING_WEAK].SetDefaults();
|
||
|
|
m_regime_params[REGIME_TRENDING_WEAK].position_size_multiplier = 0.8;
|
||
|
|
m_regime_params[REGIME_TRENDING_WEAK].min_confidence = 0.60;
|
||
|
|
|
||
|
|
// REGIME_RANGING - Mean reversion, smaller positions
|
||
|
|
m_regime_params[REGIME_RANGING].SetDefaults();
|
||
|
|
m_regime_params[REGIME_RANGING].position_size_multiplier = 0.7;
|
||
|
|
m_regime_params[REGIME_RANGING].tp_multiplier = 0.8;
|
||
|
|
m_regime_params[REGIME_RANGING].min_confidence = 0.60;
|
||
|
|
|
||
|
|
// REGIME_BREAKOUT - High volatility, strictest filters
|
||
|
|
m_regime_params[REGIME_BREAKOUT].SetDefaults();
|
||
|
|
m_regime_params[REGIME_BREAKOUT].position_size_multiplier = 0.5;
|
||
|
|
m_regime_params[REGIME_BREAKOUT].sl_multiplier = 2.0;
|
||
|
|
m_regime_params[REGIME_BREAKOUT].min_confidence = 0.70;
|
||
|
|
m_regime_params[REGIME_BREAKOUT].min_win_rate = 0.60;
|
||
|
|
m_regime_params[REGIME_BREAKOUT].reduce_size_around_news = true;
|
||
|
|
|
||
|
|
// REGIME_CRASH - Defensive, no new trades
|
||
|
|
m_regime_params[REGIME_CRASH].SetDefaults();
|
||
|
|
m_regime_params[REGIME_CRASH].allow_new_trades = false;
|
||
|
|
m_regime_params[REGIME_CRASH].position_size_multiplier = 0.25;
|
||
|
|
m_regime_params[REGIME_CRASH].max_concurrent_positions = 2;
|
||
|
|
m_regime_params[REGIME_CRASH].risk_per_trade_pct = 0.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Detect current market regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
ENUM_MARKET_REGIME DetectRegime()
|
||
|
|
{
|
||
|
|
if(m_feature_cache == NULL) return REGIME_UNKNOWN;
|
||
|
|
|
||
|
|
// Get indicator values
|
||
|
|
double atr = m_feature_cache.GetATR20();
|
||
|
|
double adx = m_feature_cache.GetADXMain();
|
||
|
|
double price = m_feature_cache.GetBid();
|
||
|
|
|
||
|
|
if(price == 0) return REGIME_UNKNOWN;
|
||
|
|
|
||
|
|
double atr_pct = atr / price;
|
||
|
|
|
||
|
|
// Check for extreme volatility (crash)
|
||
|
|
if(atr_pct > m_atr_threshold_high * 2.0)
|
||
|
|
{
|
||
|
|
return REGIME_CRASH;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check for breakout/volatility expansion
|
||
|
|
if(atr_pct > m_atr_threshold_high * 1.3)
|
||
|
|
{
|
||
|
|
return REGIME_BREAKOUT;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Determine trend strength
|
||
|
|
bool is_trending = (adx >= m_adx_threshold_trending);
|
||
|
|
bool is_strong_trend = (adx >= m_adx_threshold_strong);
|
||
|
|
|
||
|
|
// Classify by volatility + trend
|
||
|
|
if(atr_pct <= m_atr_threshold_low)
|
||
|
|
{
|
||
|
|
if(is_strong_trend) return REGIME_LOW_VOLATILITY;
|
||
|
|
return REGIME_RANGING;
|
||
|
|
}
|
||
|
|
else if(atr_pct >= m_atr_threshold_high)
|
||
|
|
{
|
||
|
|
if(is_trending) return REGIME_HIGH_VOLATILITY;
|
||
|
|
return REGIME_BREAKOUT; // Choppy high vol
|
||
|
|
}
|
||
|
|
else // Normal volatility
|
||
|
|
{
|
||
|
|
if(is_strong_trend) return REGIME_TRENDING_STRONG;
|
||
|
|
if(is_trending) return REGIME_TRENDING_WEAK;
|
||
|
|
return REGIME_NORMAL_VOLATILITY;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Update regime and track transitions |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
ENUM_MARKET_REGIME new_regime = DetectRegime();
|
||
|
|
|
||
|
|
if(new_regime != m_current_regime)
|
||
|
|
{
|
||
|
|
m_previous_regime = m_current_regime;
|
||
|
|
m_current_regime = new_regime;
|
||
|
|
m_regime_start_time = TimeCurrent();
|
||
|
|
m_regime_duration_bars = 0;
|
||
|
|
|
||
|
|
LogRegimeChange();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_regime_duration_bars++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Log regime change for telemetry |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void LogRegimeChange()
|
||
|
|
{
|
||
|
|
string msg = StringFormat("[RegimeChange] %s -> %s (ATR: %.2f%%, ADX: %.1f)",
|
||
|
|
RegimeToString(m_previous_regime),
|
||
|
|
RegimeToString(m_current_regime),
|
||
|
|
GetATRPct() * 100,
|
||
|
|
m_feature_cache != NULL ? m_feature_cache.GetADXMain() : 0);
|
||
|
|
|
||
|
|
Print(msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Convert regime to string |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
string RegimeToString(ENUM_MARKET_REGIME regime)
|
||
|
|
{
|
||
|
|
switch(regime)
|
||
|
|
{
|
||
|
|
case REGIME_UNKNOWN: return "Unknown";
|
||
|
|
case REGIME_LOW_VOLATILITY: return "LowVol";
|
||
|
|
case REGIME_NORMAL_VOLATILITY: return "Normal";
|
||
|
|
case REGIME_HIGH_VOLATILITY: return "HighVol";
|
||
|
|
case REGIME_TRENDING_STRONG: return "StrongTrend";
|
||
|
|
case REGIME_TRENDING_WEAK: return "WeakTrend";
|
||
|
|
case REGIME_RANGING: return "Ranging";
|
||
|
|
case REGIME_BREAKOUT: return "Breakout";
|
||
|
|
case REGIME_CRASH: return "CRASH";
|
||
|
|
default: return "Unknown";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Get current ATR percentage |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double GetATRPct()
|
||
|
|
{
|
||
|
|
if(m_feature_cache == NULL) return 0;
|
||
|
|
double atr = m_feature_cache.GetATR20();
|
||
|
|
double price = m_feature_cache.GetBid();
|
||
|
|
return (price > 0) ? atr / price : 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Get parameters for current regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
SRegimeParameters GetCurrentParameters()
|
||
|
|
{
|
||
|
|
return m_regime_params[m_current_regime];
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Get smoothed parameters (for gradual transitions) |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
SRegimeParameters GetSmoothedParameters()
|
||
|
|
{
|
||
|
|
if(m_previous_regime == REGIME_UNKNOWN || m_regime_duration_bars > 5)
|
||
|
|
{
|
||
|
|
return m_regime_params[m_current_regime];
|
||
|
|
}
|
||
|
|
|
||
|
|
// Smooth transition between previous and current regime
|
||
|
|
SRegimeParameters current = m_regime_params[m_current_regime];
|
||
|
|
SRegimeParameters previous = m_regime_params[m_previous_regime];
|
||
|
|
|
||
|
|
double f = m_param_transition_factor;
|
||
|
|
double inv_f = 1.0 - f;
|
||
|
|
|
||
|
|
SRegimeParameters smoothed;
|
||
|
|
smoothed.position_size_multiplier =
|
||
|
|
current.position_size_multiplier * f + previous.position_size_multiplier * inv_f;
|
||
|
|
smoothed.sl_multiplier =
|
||
|
|
current.sl_multiplier * f + previous.sl_multiplier * inv_f;
|
||
|
|
smoothed.tp_multiplier =
|
||
|
|
current.tp_multiplier * f + previous.tp_multiplier * inv_f;
|
||
|
|
smoothed.min_confidence =
|
||
|
|
current.min_confidence * f + previous.min_confidence * inv_f;
|
||
|
|
smoothed.min_win_rate =
|
||
|
|
current.min_win_rate * f + previous.min_win_rate * inv_f;
|
||
|
|
|
||
|
|
smoothed.allow_new_trades = current.allow_new_trades;
|
||
|
|
smoothed.max_concurrent_positions = current.max_concurrent_positions;
|
||
|
|
smoothed.risk_per_trade_pct = current.risk_per_trade_pct;
|
||
|
|
|
||
|
|
return smoothed;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Apply regime-adapted position sizing |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double AdjustPositionSize(double base_size)
|
||
|
|
{
|
||
|
|
SRegimeParameters params = GetSmoothedParameters();
|
||
|
|
return base_size * params.position_size_multiplier;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Apply regime-adapted stop loss distance |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double AdjustStopLoss(double base_sl_distance)
|
||
|
|
{
|
||
|
|
SRegimeParameters params = GetSmoothedParameters();
|
||
|
|
return base_sl_distance * params.sl_multiplier;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Apply regime-adapted take profit distance |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double AdjustTakeProfit(double base_tp_distance)
|
||
|
|
{
|
||
|
|
SRegimeParameters params = GetSmoothedParameters();
|
||
|
|
return base_tp_distance * params.tp_multiplier;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Check if trading is allowed in current regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool IsTradingAllowed(string &reason)
|
||
|
|
{
|
||
|
|
SRegimeParameters params = GetCurrentParameters();
|
||
|
|
|
||
|
|
if(!params.allow_new_trades)
|
||
|
|
{
|
||
|
|
reason = "Trading suspended - " + RegimeToString(m_current_regime) + " regime";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Get minimum confidence threshold for current regime |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
double GetMinConfidenceThreshold()
|
||
|
|
{
|
||
|
|
return GetSmoothedParameters().min_confidence;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Getters |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
ENUM_MARKET_REGIME GetCurrentRegime() { return m_current_regime; }
|
||
|
|
ENUM_MARKET_REGIME GetPreviousRegime() { return m_previous_regime; }
|
||
|
|
int GetRegimeDurationBars() { return m_regime_duration_bars; }
|
||
|
|
datetime GetRegimeStartTime() { return m_regime_start_time; }
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Set volatility thresholds |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void SetVolatilityThresholds(double low_pct, double high_pct)
|
||
|
|
{
|
||
|
|
m_atr_threshold_low = low_pct;
|
||
|
|
m_atr_threshold_high = high_pct;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// Global instance
|
||
|
|
CRegimeAwareStrategy* g_regime_strategy = NULL;
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Initialize Regime-Aware Strategy |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool InitializeRegimeStrategy(CGateFeatureCache* cache = NULL)
|
||
|
|
{
|
||
|
|
if(g_regime_strategy != NULL)
|
||
|
|
{
|
||
|
|
delete g_regime_strategy;
|
||
|
|
}
|
||
|
|
|
||
|
|
g_regime_strategy = new CRegimeAwareStrategy(cache);
|
||
|
|
|
||
|
|
// Set custom thresholds for gold (XAUUSD)
|
||
|
|
if(_Symbol == "XAUUSD" || _Symbol == "GOLD")
|
||
|
|
{
|
||
|
|
g_regime_strategy.SetVolatilityThresholds(0.003, 0.008); // Gold specific
|
||
|
|
}
|
||
|
|
|
||
|
|
Print("[RegimeStrategy] Initialized for " + _Symbol);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Shutdown Regime Strategy |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void ShutdownRegimeStrategy()
|
||
|
|
{
|
||
|
|
if(g_regime_strategy != NULL)
|
||
|
|
{
|
||
|
|
delete g_regime_strategy;
|
||
|
|
g_regime_strategy = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif // CREGIMEAWARESTRATEGY_MQH
|