mql5/Experts/Advisors/DualEA/PaperEA/AdaptiveEngine.mqh

558 lines
21 KiB
MQL5
Raw Permalink Normal View History

2025-10-16 18:03:47 -04:00
//+------------------------------------------------------------------+
//| AdaptiveEngine.mqh - NUCLEAR GRADE Universal Auto-Detection |
//| Automatically adapts to ANY symbol and timeframe |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Symbol Profile Structure - Comprehensive Analysis |
//+------------------------------------------------------------------+
struct SymbolProfile {
string symbol;
double avg_atr_ratio; // ATR/Price ratio for volatility scaling
double avg_spread_pct; // Spread as % of price
double volatility_percentile; // Current volatility vs historical
double liquidity_score; // Volume-based liquidity assessment
double optimal_sl_mult; // Auto-calculated optimal SL
double optimal_tp_mult; // Auto-calculated optimal TP
double risk_multiplier; // Auto-calculated risk adjustment
double timeframe_mult; // Timeframe-specific multiplier
};
//+------------------------------------------------------------------+
//| Baseline Symbol Configurations (Fallback Only) |
//+------------------------------------------------------------------+
struct SymbolConfig {
string symbol;
double base_sl_mult;
double base_tp_mult;
double volatility_class;
double spread_threshold;
};
SymbolConfig g_symbol_configs[] = {
{"EURUSD", 150.0, 300.0, 1.0, 0.00020},
{"GBPUSD", 180.0, 360.0, 1.2, 0.00025},
{"USDJPY", 120.0, 240.0, 0.8, 0.00015},
{"XAUUSD", 350.0, 700.0, 3.0, 0.50},
{"AUDUSD", 150.0, 300.0, 1.1, 0.00022},
{"USDCAD", 140.0, 280.0, 1.0, 0.00020},
{"GBPJPY", 200.0, 400.0, 1.5, 0.00030},
{"EURJPY", 160.0, 320.0, 1.2, 0.00025},
{"BTCUSD", 800.0, 1600.0, 5.0, 10.0},
{"USOIL", 500.0, 1000.0, 2.5, 0.05},
{"NGAS", 400.0, 800.0, 3.5, 0.01}
};
//+------------------------------------------------------------------+
//| UNIVERSAL AUTO-DETECTION ENGINE - Works on ANY Symbol/Timeframe |
//+------------------------------------------------------------------+
class CUniversalDetector {
private:
SymbolProfile m_profile;
string m_symbol;
ENUM_TIMEFRAMES m_timeframe;
public:
CUniversalDetector() {}
// Analyze any symbol and timeframe - returns optimized parameters
SymbolProfile AnalyzeSymbol(const string symbol, const ENUM_TIMEFRAMES tf) {
m_symbol = symbol;
m_timeframe = tf;
// Real-time ATR analysis
int atr_handle = iATR(symbol, tf, 14);
double atr_buffer[];
ArraySetAsSeries(atr_buffer, true);
double atr = 0.0;
if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) > 0) {
atr = atr_buffer[0];
}
IndicatorRelease(atr_handle);
// Current price for ratio calculation
double price = SymbolInfoDouble(symbol, SYMBOL_BID);
if(price <= 0) price = SymbolInfoDouble(symbol, SYMBOL_ASK);
m_profile.symbol = symbol;
m_profile.avg_atr_ratio = (price > 0) ? (atr / price) : 0.01;
// Spread analysis
double spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * SymbolInfoDouble(symbol, SYMBOL_POINT);
m_profile.avg_spread_pct = (price > 0) ? ((spread / price) * 100.0) : 0.001;
2026-02-24 12:47:37 -05:00
// DEBUG: Log raw spread values
PrintFormat("[DEBUG-SPREAD] %s | SpreadPoints=%d | Point=%.8f | RawSpread=%.8f | Price=%.4f | SpreadPct=%.6f",
symbol,
(int)SymbolInfoInteger(symbol, SYMBOL_SPREAD),
SymbolInfoDouble(symbol, SYMBOL_POINT),
spread,
price,
m_profile.avg_spread_pct);
2025-10-16 18:03:47 -04:00
// Volatility percentile (20-period lookback)
m_profile.volatility_percentile = CalculateVolatilityPercentile(symbol, tf, 20);
// Liquidity score (volume-based)
m_profile.liquidity_score = CalculateLiquidityScore(symbol, tf);
// Timeframe multiplier
m_profile.timeframe_mult = GetTimeframeMultiplier(tf);
// Auto-calculate optimal parameters
m_profile.optimal_sl_mult = CalculateOptimalSL(m_profile);
m_profile.optimal_tp_mult = CalculateOptimalTP(m_profile);
m_profile.risk_multiplier = CalculateOptimalRisk(m_profile);
return m_profile;
}
SymbolProfile GetProfile() { return m_profile; }
private:
// Calculate optimal SL based on symbol characteristics
double CalculateOptimalSL(const SymbolProfile& profile) {
double base_sl = 150.0; // Default for EURUSD-like pairs
// ATR-based scaling: higher volatility = wider SL
double atr_scaling = 1.0 + (profile.avg_atr_ratio * 50.0);
if(atr_scaling > 5.0) atr_scaling = 5.0;
// Spread adjustment
double spread_adj = MathMax(1.0, profile.avg_spread_pct * 20.0);
if(spread_adj > 3.0) spread_adj = 3.0;
// Timeframe scaling
double tf_mult = profile.timeframe_mult;
// Combined calculation
double optimal_sl = base_sl * atr_scaling * spread_adj * tf_mult;
// Clamp to reasonable range (50-2000 pips)
return MathMax(50.0, MathMin(2000.0, optimal_sl));
}
// Calculate optimal TP based on SL and volatility
double CalculateOptimalTP(const SymbolProfile& profile) {
double sl = CalculateOptimalSL(profile);
double base_ratio = 2.0; // TP/SL ratio
// Volatility bonus: higher volatility = higher TP potential
double volatility_bonus = MapRange(profile.volatility_percentile, 0, 100, 0.0, 1.0);
// Liquidity bonus: higher liquidity = tighter TP
double liquidity_bonus = MapRange(profile.liquidity_score, 0, 100, 0.5, 0.0);
double tp_ratio = base_ratio + volatility_bonus + liquidity_bonus;
return sl * tp_ratio;
}
// Calculate optimal risk multiplier (AGGRESSIVE profile)
double CalculateOptimalRisk(const SymbolProfile& profile) {
double base_risk = 1.5; // AGGRESSIVE: 1.5%
// Reduce risk for high volatility
double volatility_penalty = MapRange(profile.volatility_percentile, 0, 100, 1.2, 0.6);
// Reduce risk for wide spreads
double spread_penalty = MapRange(profile.avg_spread_pct, 0, 0.1, 1.0, 0.5);
if(spread_penalty < 0.5) spread_penalty = 0.5;
double optimal_risk = base_risk * volatility_penalty * spread_penalty;
// Clamp to AGGRESSIVE range (0.5% - 3.0%)
return MathMax(0.5, MathMin(3.0, optimal_risk));
}
// Calculate volatility percentile
double CalculateVolatilityPercentile(const string symbol, const ENUM_TIMEFRAMES tf, const int lookback) {
int atr_handle = iATR(symbol, tf, 14);
double atr_values[];
ArraySetAsSeries(atr_values, true);
if(CopyBuffer(atr_handle, 0, 0, lookback, atr_values) < lookback) {
IndicatorRelease(atr_handle);
return 50.0; // Default to median
}
double current_atr = atr_values[0];
int count_below = 0;
for(int i = 0; i < lookback; i++) {
if(atr_values[i] <= current_atr) count_below++;
}
IndicatorRelease(atr_handle);
return (double)count_below / (double)lookback * 100.0;
}
// Calculate liquidity score based on volume
double CalculateLiquidityScore(const string symbol, const ENUM_TIMEFRAMES tf) {
long volume[];
ArraySetAsSeries(volume, true);
if(CopyTickVolume(symbol, tf, 0, 20, volume) < 20) {
return 50.0; // Default to median
}
double avg_volume = 0.0;
for(int i = 0; i < 20; i++) {
avg_volume += (double)volume[i];
}
avg_volume /= 20.0;
double current_volume = (double)volume[0];
double ratio = (avg_volume > 0) ? (current_volume / avg_volume) : 1.0;
return MathMin(100.0, ratio * 50.0);
}
// Timeframe multiplier
double GetTimeframeMultiplier(const ENUM_TIMEFRAMES tf) {
switch(tf) {
case PERIOD_M1: return 0.3;
case PERIOD_M5: return 0.5;
case PERIOD_M15: return 0.75;
case PERIOD_M30: return 1.0;
case PERIOD_H1: return 1.5;
case PERIOD_H4: return 2.5;
case PERIOD_D1: return 4.0;
case PERIOD_W1: return 8.0;
default: return 1.0;
}
}
// Map value from input range to output range
double MapRange(const double value, const double in_min, const double in_max,
const double out_min, const double out_max) {
if(in_max == in_min) return out_min;
double mapped = out_min + (value - in_min) * (out_max - out_min) / (in_max - in_min);
return MathMax(out_min, MathMin(out_max, mapped));
}
};
//+------------------------------------------------------------------+
//| LIVE ADAPTATION ENGINE - Evolves Parameters Based on Performance|
//+------------------------------------------------------------------+
class CLiveAdaptation {
private:
struct PerformanceMetrics {
double rolling_pf; // Rolling profit factor
double rolling_wr; // Rolling win rate
double rolling_dd; // Rolling max drawdown
double rolling_vol; // Rolling volatility
int trade_count; // Total trades
datetime last_update; // Last update time
};
PerformanceMetrics m_metrics;
public:
CLiveAdaptation() {
m_metrics.rolling_pf = 1.0;
m_metrics.rolling_wr = 0.5;
m_metrics.rolling_dd = 0.0;
m_metrics.rolling_vol = 1.0;
m_metrics.trade_count = 0;
m_metrics.last_update = 0;
}
// Update from live trading performance
void UpdateFromLiveTrading(const double pf, const double wr, const double dd, const double vol) {
m_metrics.rolling_pf = pf;
m_metrics.rolling_wr = wr;
m_metrics.rolling_dd = dd;
m_metrics.rolling_vol = vol;
m_metrics.trade_count++;
m_metrics.last_update = TimeCurrent();
}
// Calculate adaptive adjustment multiplier
double CalculateAdaptiveAdjustment() {
if(m_metrics.trade_count < 10) return 1.0; // Need minimum sample
// Multi-factor adjustment
double pf_component = MapRange(m_metrics.rolling_pf, 1.9, 3.0, 0.8, 1.2);
double wr_component = MapRange(m_metrics.rolling_wr, 0.5, 1.0, 0.9, 1.1);
double dd_component = MapRange(m_metrics.rolling_dd, 0.0, 0.05, 1.2, 0.7);
double vol_component = MapRange(m_metrics.rolling_vol, 0.5, 2.0, 1.1, 0.9);
// Weighted average
double adjustment = (pf_component * 0.4 + wr_component * 0.3 + dd_component * 0.2 + vol_component * 0.1);
// Clamp to reasonable range (0.7 - 1.3)
return MathMax(0.7, MathMin(1.3, adjustment));
}
double GetProfitFactor() { return m_metrics.rolling_pf; }
double GetWinRate() { return m_metrics.rolling_wr; }
double GetDrawdown() { return m_metrics.rolling_dd; }
int GetTradeCount() { return m_metrics.trade_count; }
private:
double MapRange(const double value, const double in_min, const double in_max,
const double out_min, const double out_max) {
if(in_max == in_min) return out_min;
double mapped = out_min + (value - in_min) * (out_max - out_min) / (in_max - in_min);
return MathMax(out_min, MathMin(out_max, mapped));
}
};
//+------------------------------------------------------------------+
//| ENHANCED ADAPTIVE ENGINE - Integration Layer |
//+------------------------------------------------------------------+
class CAdaptiveEngine {
private:
double m_current_atr;
double m_current_spread;
double m_volatility_percentile;
double m_spread_percentile;
CUniversalDetector m_detector;
SymbolProfile m_current_profile;
public:
CAdaptiveEngine() {
m_current_atr = 0.0;
m_current_spread = 0.0;
m_volatility_percentile = 50.0;
m_spread_percentile = 50.0;
}
// Calculate symbol-specific multipliers using UNIVERSAL DETECTOR
void CalculateDynamicParameters(const string symbol, const ENUM_TIMEFRAMES timeframe) {
// Use nuclear-grade universal detector
m_current_profile = m_detector.AnalyzeSymbol(symbol, timeframe);
// Legacy compatibility - extract key metrics
int atr_handle = iATR(symbol, timeframe, 14);
double atr_buffer[];
ArraySetAsSeries(atr_buffer, true);
if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) > 0) {
m_current_atr = atr_buffer[0];
}
IndicatorRelease(atr_handle);
m_current_spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * SymbolInfoDouble(symbol, SYMBOL_POINT);
m_volatility_percentile = m_current_profile.volatility_percentile;
m_spread_percentile = m_current_profile.avg_spread_pct;
// Log auto-detection results
PrintFormat("🎯 [AUTO-DETECT] %s %s | SL=%.1f TP=%.1f Risk=%.2f%% | ATR Ratio=%.4f Spread=%.3f%% Vol=%d%%",
symbol, EnumToString(timeframe),
m_current_profile.optimal_sl_mult,
m_current_profile.optimal_tp_mult,
m_current_profile.risk_multiplier,
m_current_profile.avg_atr_ratio,
m_current_profile.avg_spread_pct * 100,
(int)m_current_profile.volatility_percentile);
}
// Get adjusted stop loss in pips - USES UNIVERSAL DETECTOR RESULTS
double GetDynamicSL(const string symbol, const ENUM_TIMEFRAMES timeframe) {
// Return optimal SL calculated by universal detector
if(m_current_profile.symbol == symbol) {
return m_current_profile.optimal_sl_mult;
}
// Fallback: recalculate
SymbolProfile profile = m_detector.AnalyzeSymbol(symbol, timeframe);
return profile.optimal_sl_mult;
}
// Get adjusted take profit in pips - USES UNIVERSAL DETECTOR RESULTS
double GetDynamicTP(const string symbol, const ENUM_TIMEFRAMES timeframe) {
// Return optimal TP calculated by universal detector
if(m_current_profile.symbol == symbol) {
return m_current_profile.optimal_tp_mult;
}
// Fallback: recalculate
SymbolProfile profile = m_detector.AnalyzeSymbol(symbol, timeframe);
return profile.optimal_tp_mult;
}
// Get risk-adjusted position size - USES UNIVERSAL DETECTOR RESULTS
double GetDynamicRisk(const string risk_profile) {
// Use optimal risk from universal detector (already tuned for AGGRESSIVE)
if(m_current_profile.symbol != "") {
return m_current_profile.risk_multiplier;
}
// Fallback to manual calculation
double base_risk = 1.0;
if(risk_profile == "CONSERVATIVE") base_risk = 0.5;
else if(risk_profile == "MODERATE") base_risk = 1.0;
else if(risk_profile == "AGGRESSIVE") base_risk = 1.5;
// Reduce risk in high volatility
double volatility_penalty = MapRange(m_volatility_percentile, 0, 100, 1.2, 0.6);
return base_risk * volatility_penalty;
}
// Get current symbol profile
SymbolProfile GetCurrentProfile() {
return m_current_profile;
}
private:
double GetSymbolBaseSL(const string symbol) {
for(int i = 0; i < ArraySize(g_symbol_configs); i++) {
if(StringFind(symbol, g_symbol_configs[i].symbol) >= 0) {
return g_symbol_configs[i].base_sl_mult;
}
}
return 10.0; // Default fallback
}
double GetSymbolBaseTP(const string symbol) {
for(int i = 0; i < ArraySize(g_symbol_configs); i++) {
if(StringFind(symbol, g_symbol_configs[i].symbol) >= 0) {
return g_symbol_configs[i].base_tp_mult;
}
}
return 20.0; // Default fallback
}
double GetTimeframeMultiplier(const int timeframe) {
switch(timeframe) {
case PERIOD_M1: return 0.25;
case PERIOD_M5: return 0.5;
case PERIOD_M15: return 0.75;
case PERIOD_M30: return 1.0;
case PERIOD_H1: return 1.5;
case PERIOD_H4: return 2.5;
case PERIOD_D1: return 5.0;
default: return 1.0;
}
}
double CalculateATRPercentile(const string symbol, const ENUM_TIMEFRAMES tf, const int lookback) {
int atr_handle = iATR(symbol, tf, 14);
double atr_values[];
ArraySetAsSeries(atr_values, true);
if(CopyBuffer(atr_handle, 0, 0, lookback, atr_values) < lookback) {
IndicatorRelease(atr_handle);
return 50.0; // Default to median on error
}
double current_atr = atr_values[0];
IndicatorRelease(atr_handle);
return CalculatePercentile(atr_values, current_atr);
}
double CalculateSpreadPercentile(const string symbol, const int lookback) {
double spread_values[];
ArrayResize(spread_values, lookback);
for(int i = 0; i < lookback; i++) {
spread_values[i] = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * SymbolInfoDouble(symbol, SYMBOL_POINT);
}
return CalculatePercentile(spread_values,
SymbolInfoInteger(symbol, SYMBOL_SPREAD) * SymbolInfoDouble(symbol, SYMBOL_POINT));
}
double CalculatePercentile(const double &values[], const double current_value) {
int count = 0;
for(int i = 0; i < ArraySize(values); i++) {
if(values[i] <= current_value) count++;
}
return (double)count / ArraySize(values) * 100.0;
}
double MapRange(const double value, const double in_min, const double in_max,
const double out_min, const double out_max) {
return out_min + (value - in_min) * (out_max - out_min) / (in_max - in_min);
}
};
//+------------------------------------------------------------------+
//| Machine Learning Adaptation Engine |
//+------------------------------------------------------------------+
class CMLAdaptationEngine {
private:
double m_recent_pf;
double m_recent_wr;
double m_recent_dd;
double m_recent_vol;
public:
CMLAdaptationEngine() {
m_recent_pf = 1.2;
m_recent_wr = 0.5;
m_recent_dd = 0.1;
m_recent_vol = 1.0;
}
// Calculate ML-based parameter adjustment
double CalculateAdjustment(const double profit_factor, const double win_rate,
const double max_drawdown, const double volatility) {
// Performance score (0-100)
double perf_score = 0.0;
perf_score += profit_factor * 25.0; // Max 50
perf_score += win_rate * 50.0; // Max 50
perf_score -= max_drawdown * 200.0; // Penalty for drawdown
perf_score = MathMax(0.0, MathMin(100.0, perf_score));
// Volatility adjustment factor
double vol_factor = MapRange(volatility, 0.5, 3.0, 1.2, 0.8);
// Combined adjustment
double adjustment = 1.0 + (perf_score - 50.0) / 100.0 * vol_factor;
return MathMax(0.5, MathMin(2.0, adjustment));
}
// Get recent performance metrics
double GetRecentProfitFactor(const int lookback_trades) {
// Implementation would query KnowledgeBase or trade history
return 1.2 + (MathRand() % 100 - 50) / 500.0; // Simulated: 1.0 to 1.4
}
double GetRecentWinRate(const int lookback_trades) {
// Implementation would query KnowledgeBase or trade history
return 0.45 + (MathRand() % 20) / 100.0; // Simulated: 0.45 to 0.65
}
double GetRecentMaxDrawdown(const int lookback_trades) {
// Implementation would query KnowledgeBase or trade history
return 0.05 + (MathRand() % 15) / 100.0; // Simulated: 0.05 to 0.20
}
double GetRecentVolatility(const int lookback_bars) {
// Calculate recent volatility from price data
return 1.0 + (MathRand() % 100 - 50) / 100.0; // Simulated: 0.5 to 1.5
}
private:
double MapRange(const double value, const double in_min, const double in_max,
const double out_min, const double out_max) {
if(in_max == in_min) return out_min;
double mapped = out_min + (value - in_min) * (out_max - out_min) / (in_max - in_min);
return MathMax(out_min, MathMin(out_max, mapped));
}
};
//+------------------------------------------------------------------+
//| Helper Functions |
//+------------------------------------------------------------------+
double GetSymbolSLMultiplier(const string symbol) {
for(int i = 0; i < ArraySize(g_symbol_configs); i++) {
if(StringFind(symbol, g_symbol_configs[i].symbol) >= 0) {
return g_symbol_configs[i].base_sl_mult;
}
}
return 10.0; // Default fallback
}
double GetSymbolTPMultiplier(const string symbol) {
for(int i = 0; i < ArraySize(g_symbol_configs); i++) {
if(StringFind(symbol, g_symbol_configs[i].symbol) >= 0) {
return g_symbol_configs[i].base_tp_mult;
}
}
return 20.0; // Default fallback
}