308 lines
11 KiB
MQL5
308 lines
11 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| 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();
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
|