mql5/Include/Experts/RiskManager_Advanced.mqh

309 lines
11 KiB
MQL5
Raw Permalink Normal View History

2025-08-16 12:30:04 -04:00
//+------------------------------------------------------------------+
//| RiskManager_Advanced.mqh |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
// Include the base RiskManager class
#include "RiskManager.mqh"
//+------------------------------------------------------------------+
//| Calculate correlation-adjusted position size |
//+------------------------------------------------------------------+
double CRiskManager::CalculateCorrelationAdjustedSize(double baseLots, string symbol1, string symbol2, ENUM_TIMEFRAMES timeframe, int period)
{
if(baseLots <= 0 || symbol1 == "" || symbol2 == "" || period <= 0)
return baseLots;
// Get correlation between the two symbols
double correlation = CalculateCorrelationIndex(symbol1, symbol2, timeframe, period);
// Convert correlation from -100..100 to 0..1 range
double correlationFactor = (correlation + 100.0) / 200.0;
// Adjust position size based on correlation
// Higher correlation = smaller position size to reduce risk
double adjustedLots = baseLots * (1.0 - (correlationFactor * 0.5));
// Ensure we don't go below minimum lot size
double minLot = SymbolInfoDouble(symbol1, SYMBOL_VOLUME_MIN);
return MathMax(adjustedLots, minLot);
}
//+------------------------------------------------------------------+
//| Calculate regime-adjusted position size |
//+------------------------------------------------------------------+
double CRiskManager::CalculateRegimeAdjustedSize(double baseLots, ENUM_MARKET_REGIME regime)
{
if(baseLots <= 0)
return 0.0;
double adjustedLots = baseLots;
switch(regime)
{
case REGIME_TRENDING_UP:
case REGIME_TRENDING_DOWN:
// Increase position size in strong trends
adjustedLots *= 1.2;
break;
case REGIME_RANGING:
// Reduce position size in ranging markets
adjustedLots *= 0.7;
break;
case REGIME_VOLATILE:
// Reduce position size in high volatility
adjustedLots *= 0.6;
break;
case REGIME_LOW_VOLATILITY:
// Slightly reduce position size in low volatility
adjustedLots *= 0.9;
break;
default:
break;
}
// Ensure we don't exceed maximum position size
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
return MathMin(adjustedLots, maxLot);
}
//+------------------------------------------------------------------+
//| Calculate ML-adjusted position size |
//+------------------------------------------------------------------+
double CRiskManager::CalculateMLAdjustedSize(double baseLots, double mlConfidence)
{
if(baseLots <= 0)
return 0.0;
// Ensure confidence is in valid range (0-1)
mlConfidence = MathMax(0.0, MathMin(1.0, mlConfidence));
// Calculate position size adjustment based on confidence
// Higher confidence = larger position size (up to 2x)
// Lower confidence = smaller position size (down to 0.1x)
double adjustmentFactor = 0.1 + (mlConfidence * 1.9);
// Apply adjustment
double adjustedLots = baseLots * adjustmentFactor;
// Ensure we don't exceed maximum position size
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
return MathMin(adjustedLots, maxLot);
}
//+------------------------------------------------------------------+
//| Calculate correlation index between two symbols |
//+------------------------------------------------------------------+
double CRiskManager::CalculateCorrelationIndex(string symbol1, string symbol2, ENUM_TIMEFRAMES timeframe, int period)
{
if(period <= 0)
return 0.0;
// Get close prices for both symbols
double closes1[], closes2[];
ArraySetAsSeries(closes1, true);
ArraySetAsSeries(closes2, true);
int copied1 = CopyClose(symbol1, timeframe, 0, period, closes1);
int copied2 = CopyClose(symbol2, timeframe, 0, period, closes2);
if(copied1 != period || copied2 != period || copied1 != copied2)
return 0.0;
// Calculate correlation coefficient (Pearson's r)
double sum1 = 0, sum2 = 0, sum1Sq = 0, sum2Sq = 0, sumProd = 0;
for(int i = 0; i < period; i++)
{
sum1 += closes1[i];
sum2 += closes2[i];
sum1Sq += closes1[i] * closes1[i];
sum2Sq += closes2[i] * closes2[i];
sumProd += closes1[i] * closes2[i];
}
double numerator = sumProd - (sum1 * sum2 / period);
double denominator = MathSqrt((sum1Sq - (sum1 * sum1 / period)) * (sum2Sq - (sum2 * sum2 / period)));
if(denominator == 0)
return 0.0;
double correlation = numerator / denominator;
// Convert to -100..100 range
return correlation * 100.0;
}
//+------------------------------------------------------------------+
//| Calculate volatility index |
//+------------------------------------------------------------------+
double CRiskManager::CalculateVolatilityIndex(int period = 14)
{
if(m_symbol == NULL || period <= 0)
return 0.0;
// Calculate ATR as percentage of price
double atr = m_atr != NULL ? m_atr.Main(0) : 0;
double price = m_symbol.Ask();
if(price <= 0)
return 0.0;
double atrPercent = (atr / price) * 100.0;
// Convert to 0-100 scale (adjust these thresholds based on your needs)
const double MIN_ATR = 0.2; // 0.2%
const double MAX_ATR = 2.0; // 2.0%
double volatilityIndex = 100.0 * (atrPercent - MIN_ATR) / (MAX_ATR - MIN_ATR);
// Ensure within bounds
return MathMax(0.0, MathMin(100.0, volatilityIndex));
}
//+------------------------------------------------------------------+
//| Calculate trend strength |
//+------------------------------------------------------------------+
double CRiskManager::CalculateTrendStrength(int period = 20)
{
if(m_symbol == NULL || period <= 0)
return 0.0;
// Simple implementation using ADX
int adxHandle = iADX(m_symbol.Name(), PERIOD_CURRENT, period);
if(adxHandle == INVALID_HANDLE)
return 0.0;
double adx[];
ArraySetAsSeries(adx, true);
if(CopyBuffer(adxHandle, 0, 0, 1, adx) != 1)
{
IndicatorRelease(adxHandle);
return 0.0;
}
IndicatorRelease(adxHandle);
// ADX is already on a 0-100 scale
return adx[0];
}
//+------------------------------------------------------------------+
//| Save risk manager state to file |
//+------------------------------------------------------------------+
void CRiskManager::SaveState()
{
int handle = FileOpen("RiskManagerState.dat", FILE_WRITE|FILE_BIN);
if(handle != INVALID_HANDLE)
{
// Save basic risk parameters
FileWriteDouble(handle, m_riskPerTrade);
FileWriteDouble(handle, m_maxLeverage);
FileWriteInteger(handle, m_maxOpenTrades);
FileWriteDouble(handle, m_dailyLossLimit);
FileWriteDouble(handle, m_maxPortfolioRisk);
FileWriteDouble(handle, m_maxDrawdown);
// Save advanced risk metrics
FileWriteDouble(handle, m_riskOfRuin);
FileWriteDouble(handle, m_sharpeRatio);
FileWriteDouble(handle, m_sortinoRatio);
FileWriteDouble(handle, m_valueAtRisk);
FileWriteDouble(handle, m_expectedShortfall);
FileWriteDouble(handle, m_maxAdverseExcursion);
FileWriteDouble(handle, m_winLossRatio);
FileWriteDouble(handle, m_profitFactor);
FileWriteDouble(handle, m_recoveryFactor);
FileWriteInteger(handle, m_consecutiveLosses);
FileWriteInteger(handle, m_consecutiveWins);
FileWriteDouble(handle, m_avgWin);
FileWriteDouble(handle, m_avgLoss);
FileWriteInteger(handle, m_totalTrades);
FileWriteDouble(handle, m_winRate);
// Save market regime info
FileWriteInteger(handle, (int)m_marketRegime);
FileWriteDouble(handle, m_volatilityIndex);
FileWriteDouble(handle, m_trendStrength);
FileWriteDouble(handle, m_correlationIndex);
FileClose(handle);
}
}
//+------------------------------------------------------------------+
//| Load risk manager state from file |
//+------------------------------------------------------------------+
bool CRiskManager::LoadState()
{
int handle = FileOpen("RiskManagerState.dat", FILE_READ|FILE_BIN);
if(handle != INVALID_HANDLE)
{
// Load basic risk parameters
m_riskPerTrade = FileReadDouble(handle);
m_maxLeverage = FileReadDouble(handle);
m_maxOpenTrades = (int)FileReadInteger(handle);
m_dailyLossLimit = FileReadDouble(handle);
m_maxPortfolioRisk = FileReadDouble(handle);
m_maxDrawdown = FileReadDouble(handle);
// Load advanced risk metrics
m_riskOfRuin = FileReadDouble(handle);
m_sharpeRatio = FileReadDouble(handle);
m_sortinoRatio = FileReadDouble(handle);
m_valueAtRisk = FileReadDouble(handle);
m_expectedShortfall = FileReadDouble(handle);
m_maxAdverseExcursion = FileReadDouble(handle);
m_winLossRatio = FileReadDouble(handle);
m_profitFactor = FileReadDouble(handle);
m_recoveryFactor = FileReadDouble(handle);
m_consecutiveLosses = (int)FileReadInteger(handle);
m_consecutiveWins = (int)FileReadInteger(handle);
m_avgWin = FileReadDouble(handle);
m_avgLoss = FileReadDouble(handle);
m_totalTrades = (int)FileReadInteger(handle);
m_winRate = FileReadDouble(handle);
// Load market regime info
m_marketRegime = (ENUM_MARKET_REGIME)FileReadInteger(handle);
m_volatilityIndex = FileReadDouble(handle);
m_trendStrength = FileReadDouble(handle);
m_correlationIndex = FileReadDouble(handle);
FileClose(handle);
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Trigger recovery mode |
//+------------------------------------------------------------------+
void CRiskManager::TriggerRecovery()
{
// Set risk state to recovery
m_riskState = RISK_STATE_RECOVERY;
// Log the recovery trigger
Print("RiskManager: Recovery mode triggered. Risk state set to RECOVERY.");
// Implement any additional recovery logic here
// For example, you might want to close some positions, reduce position sizes, etc.
// Save the current state
SaveState();
}
//+------------------------------------------------------------------+