mql5/Include/Trade/RiskManager.mqh
Salman Khan 2b2e3f6905 🚀 Revolutionary AI Trading System - MQL5 Professional Edition
 Complete Expert Advisor with AI intelligence
 Professional MQL5 library structure
 Advanced risk management and trade execution
 Comprehensive installation documentation

🎯 MQL5 Features:
- Conviction-based trading intelligence
- Probability-driven position sizing (Kelly Criterion)
- Market edge strength analysis
- Dynamic TP/SL management based on risk scenarios
- AI-powered market narratives dashboard
- Multi-layered risk management system

📦 Installation:
- Copy RevolutionaryAI_EA_FINAL.mq5 to MQL5/Experts/
- Copy Include/ folder to MQL5/Include/
- Compile and attach to chart
- Works standalone - no external dependencies required

🧠 Built for the MQL5 community with professional standards

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-29 17:02:40 -04:00

530 lines
No EOL
18 KiB
MQL5

//+------------------------------------------------------------------+
//| RiskManager.mqh - Advanced Risk Management System |
//| Professional Risk Control and Position Sizing |
//+------------------------------------------------------------------+
#ifndef RISK_MANAGER_MQH
#define RISK_MANAGER_MQH
enum ENUM_RISK_LEVEL
{
RISK_LOW = 1,
RISK_MEDIUM = 2,
RISK_HIGH = 3,
RISK_EXTREME = 4
};
struct RiskParameters
{
double maxRiskPerTrade; // Maximum risk per trade (%)
double maxDailyRisk; // Maximum daily risk (%)
double maxDrawdown; // Maximum allowed drawdown (%)
double maxCorrelation; // Maximum correlation between positions
double maxPositionSize; // Maximum position size (%)
int maxOpenPositions; // Maximum number of open positions
double emergencyStopLevel; // Emergency stop level (%)
};
struct PositionRisk
{
ulong ticket;
string symbol;
double volume;
double riskAmount;
double riskPercent;
double unrealizedPL;
double var95; // Value at Risk 95%
double correlationScore;
};
struct PortfolioRisk
{
double totalRisk;
double dailyRisk;
double portfolioVar;
double currentDrawdown;
double correlationRisk;
ENUM_RISK_LEVEL riskLevel;
string riskStatus;
};
class CAdvancedRiskManager
{
private:
RiskParameters m_riskParams;
double m_accountBalance;
double m_accountEquity;
double m_startingBalance;
double m_peakBalance;
double m_dailyStartBalance;
// Risk tracking
double m_currentRisk;
double m_dailyRisk;
double m_maxHistoricalDrawdown;
datetime m_lastResetTime;
// Position tracking
PositionRisk m_positions[50]; // Max 50 positions
int m_positionCount;
public:
CAdvancedRiskManager(void);
~CAdvancedRiskManager(void);
// Initialization
bool Initialize(void);
void SetRiskParameters(RiskParameters &params);
// Risk Assessment
bool IsTradeAllowed(string symbol, ENUM_ORDER_TYPE orderType, double volume);
double CalculateOptimalLotSize(string symbol, double riskPercent, double stopLossPips);
double CalculatePositionRisk(string symbol, double volume, double stopLoss);
// Portfolio Risk Management
PortfolioRisk GetPortfolioRisk(void);
bool CheckRiskLimits(void);
double GetMaxAllowedVolume(string symbol);
// Position Management
void UpdatePositionRisk(void);
void AddPosition(ulong ticket, string symbol, double volume, double stopLoss);
void RemovePosition(ulong ticket);
// Risk Monitoring
ENUM_RISK_LEVEL AssessRiskLevel(void);
bool IsEmergencyStop(void);
void UpdateDailyRisk(void);
void ResetDailyCounters(void);
// Value at Risk (VaR)
double CalculateVaR(string symbol, double volume, int confidence = 95);
double CalculatePortfolioVaR(void);
// Drawdown Management
double GetCurrentDrawdown(void);
double GetMaxDrawdown(void);
bool IsDrawdownExceeded(void);
// Utility Methods
void PrintRiskReport(void);
string GetRiskStatusString(void);
double GetRiskReward(double stopLoss, double takeProfit);
// Getters
double GetCurrentRisk(void) { return m_currentRisk; }
double GetDailyRisk(void) { return m_dailyRisk; }
int GetPositionCount(void) { return m_positionCount; }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CAdvancedRiskManager::CAdvancedRiskManager(void)
{
// Initialize default risk parameters
m_riskParams.maxRiskPerTrade = 2.0;
m_riskParams.maxDailyRisk = 6.0;
m_riskParams.maxDrawdown = 15.0;
m_riskParams.maxCorrelation = 0.7;
m_riskParams.maxPositionSize = 10.0;
m_riskParams.maxOpenPositions = 5;
m_riskParams.emergencyStopLevel = 20.0;
m_currentRisk = 0;
m_dailyRisk = 0;
m_positionCount = 0;
m_maxHistoricalDrawdown = 0;
m_lastResetTime = TimeCurrent();
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CAdvancedRiskManager::~CAdvancedRiskManager(void)
{
}
//+------------------------------------------------------------------+
//| Initialize risk manager |
//+------------------------------------------------------------------+
bool CAdvancedRiskManager::Initialize(void)
{
m_accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
m_accountEquity = AccountInfoDouble(ACCOUNT_EQUITY);
m_startingBalance = m_accountBalance;
m_peakBalance = m_accountBalance;
m_dailyStartBalance = m_accountBalance;
UpdatePositionRisk();
return true;
}
//+------------------------------------------------------------------+
//| Set risk parameters |
//+------------------------------------------------------------------+
void CAdvancedRiskManager::SetRiskParameters(RiskParameters &params)
{
m_riskParams = params;
}
//+------------------------------------------------------------------+
//| Check if trade is allowed |
//+------------------------------------------------------------------+
bool CAdvancedRiskManager::IsTradeAllowed(string symbol, ENUM_ORDER_TYPE orderType, double volume)
{
// Update current risk state
UpdatePositionRisk();
UpdateDailyRisk();
// Check emergency stop
if(IsEmergencyStop())
{
Print("🛑 Emergency stop activated - no new trades allowed");
return false;
}
// Check daily risk limit
if(m_dailyRisk >= m_riskParams.maxDailyRisk)
{
Print("⚠️ Daily risk limit exceeded: ", DoubleToString(m_dailyRisk, 2), "%");
return false;
}
// Check maximum positions
if(m_positionCount >= m_riskParams.maxOpenPositions)
{
Print("⚠️ Maximum position count reached: ", m_positionCount);
return false;
}
// Check drawdown
if(IsDrawdownExceeded())
{
Print("⚠️ Maximum drawdown exceeded: ", DoubleToString(GetCurrentDrawdown(), 2), "%");
return false;
}
// Check position size limit
double positionRisk = CalculatePositionRisk(symbol, volume, 0);
if(positionRisk > m_riskParams.maxRiskPerTrade)
{
Print("⚠️ Position risk too high: ", DoubleToString(positionRisk, 2), "%");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Calculate optimal lot size |
//+------------------------------------------------------------------+
double CAdvancedRiskManager::CalculateOptimalLotSize(string symbol, double riskPercent, double stopLossPips)
{
if(stopLossPips <= 0) return 0;
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = accountBalance * riskPercent / 100.0;
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
double pointValue = SymbolInfoDouble(symbol, SYMBOL_POINT);
double pipValue = tickValue * stopLossPips;
if(pipValue <= 0) return 0;
double lotSize = riskAmount / pipValue;
// Normalize to symbol specifications
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
double stepLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
lotSize = MathMax(minLot, lotSize);
lotSize = MathMin(maxLot, lotSize);
lotSize = MathRound(lotSize / stepLot) * stepLot;
return lotSize;
}
//+------------------------------------------------------------------+
//| Calculate position risk |
//+------------------------------------------------------------------+
double CAdvancedRiskManager::CalculatePositionRisk(string symbol, double volume, double stopLoss)
{
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
double currentPrice = SymbolInfoDouble(symbol, SYMBOL_ASK);
double riskAmount = 0;
if(stopLoss > 0)
{
double stopLossPips = MathAbs(currentPrice - stopLoss) / SymbolInfoDouble(symbol, SYMBOL_POINT);
riskAmount = volume * stopLossPips * tickValue;
}
else
{
// Use default 2% risk if no stop loss specified
riskAmount = accountBalance * 0.02;
}
return (riskAmount / accountBalance) * 100.0;
}
//+------------------------------------------------------------------+
//| Get portfolio risk |
//+------------------------------------------------------------------+
PortfolioRisk CAdvancedRiskManager::GetPortfolioRisk(void)
{
PortfolioRisk risk;
UpdatePositionRisk();
risk.totalRisk = m_currentRisk;
risk.dailyRisk = m_dailyRisk;
risk.portfolioVar = CalculatePortfolioVaR();
risk.currentDrawdown = GetCurrentDrawdown();
risk.correlationRisk = 0; // Simplified for now
risk.riskLevel = AssessRiskLevel();
risk.riskStatus = GetRiskStatusString();
return risk;
}
//+------------------------------------------------------------------+
//| Assess risk level |
//+------------------------------------------------------------------+
ENUM_RISK_LEVEL CAdvancedRiskManager::AssessRiskLevel(void)
{
double riskScore = 0;
// Risk from current positions
riskScore += (m_currentRisk / m_riskParams.maxRiskPerTrade) * 25;
// Risk from daily exposure
riskScore += (m_dailyRisk / m_riskParams.maxDailyRisk) * 25;
// Risk from drawdown
double drawdown = GetCurrentDrawdown();
riskScore += (drawdown / m_riskParams.maxDrawdown) * 25;
// Position count risk
riskScore += ((double)m_positionCount / m_riskParams.maxOpenPositions) * 25;
if(riskScore < 25) return RISK_LOW;
if(riskScore < 50) return RISK_MEDIUM;
if(riskScore < 75) return RISK_HIGH;
return RISK_EXTREME;
}
//+------------------------------------------------------------------+
//| Check if emergency stop is needed |
//+------------------------------------------------------------------+
bool CAdvancedRiskManager::IsEmergencyStop(void)
{
double currentDrawdown = GetCurrentDrawdown();
return (currentDrawdown >= m_riskParams.emergencyStopLevel);
}
//+------------------------------------------------------------------+
//| Get current drawdown |
//+------------------------------------------------------------------+
double CAdvancedRiskManager::GetCurrentDrawdown(void)
{
m_accountEquity = AccountInfoDouble(ACCOUNT_EQUITY);
m_peakBalance = MathMax(m_peakBalance, m_accountEquity);
if(m_peakBalance <= 0) return 0;
double drawdown = ((m_peakBalance - m_accountEquity) / m_peakBalance) * 100.0;
m_maxHistoricalDrawdown = MathMax(m_maxHistoricalDrawdown, drawdown);
return drawdown;
}
//+------------------------------------------------------------------+
//| Check if drawdown is exceeded |
//+------------------------------------------------------------------+
bool CAdvancedRiskManager::IsDrawdownExceeded(void)
{
return (GetCurrentDrawdown() >= m_riskParams.maxDrawdown);
}
//+------------------------------------------------------------------+
//| Update position risk |
//+------------------------------------------------------------------+
void CAdvancedRiskManager::UpdatePositionRisk(void)
{
m_positionCount = 0;
m_currentRisk = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
if(PositionSelectByTicket(PositionGetTicket(i)))
{
double unrealizedPL = PositionGetDouble(POSITION_PROFIT);
double volume = PositionGetDouble(POSITION_VOLUME);
string symbol = PositionGetString(POSITION_SYMBOL);
if(m_positionCount < 50) // Max 50 positions
{
m_positions[m_positionCount].ticket = PositionGetInteger(POSITION_TICKET);
m_positions[m_positionCount].symbol = symbol;
m_positions[m_positionCount].volume = volume;
m_positions[m_positionCount].unrealizedPL = unrealizedPL;
m_positions[m_positionCount].riskPercent = CalculatePositionRisk(symbol, volume, PositionGetDouble(POSITION_SL));
m_currentRisk += m_positions[m_positionCount].riskPercent;
m_positionCount++;
}
}
}
}
//+------------------------------------------------------------------+
//| Calculate portfolio Value at Risk |
//+------------------------------------------------------------------+
double CAdvancedRiskManager::CalculatePortfolioVaR(void)
{
// Simplified VaR calculation
// In a real implementation, this would use historical data and Monte Carlo simulation
double totalExposure = 0;
for(int i = 0; i < m_positionCount; i++)
{
totalExposure += m_positions[i].riskAmount;
}
// Assume 95% confidence level with 1.65 standard deviations
double portfolioVolatility = 0.02; // 2% daily volatility assumption
double var95 = totalExposure * 1.65 * portfolioVolatility;
return var95;
}
//+------------------------------------------------------------------+
//| Print risk report |
//+------------------------------------------------------------------+
void CAdvancedRiskManager::PrintRiskReport(void)
{
PortfolioRisk risk = GetPortfolioRisk();
Print("=== RISK MANAGEMENT REPORT ===");
Print("Current Risk: ", DoubleToString(risk.totalRisk, 2), "%");
Print("Daily Risk: ", DoubleToString(risk.dailyRisk, 2), "%");
Print("Portfolio VaR: $", DoubleToString(risk.portfolioVar, 2));
Print("Current Drawdown: ", DoubleToString(risk.currentDrawdown, 2), "%");
Print("Risk Level: ", EnumToString(risk.riskLevel));
Print("Open Positions: ", m_positionCount);
Print("=============================");
}
//+------------------------------------------------------------------+
//| Get risk status string |
//+------------------------------------------------------------------+
string CAdvancedRiskManager::GetRiskStatusString(void)
{
ENUM_RISK_LEVEL level = AssessRiskLevel();
switch(level)
{
case RISK_LOW: return "🟢 LOW RISK";
case RISK_MEDIUM: return "🟡 MEDIUM RISK";
case RISK_HIGH: return "🟠 HIGH RISK";
case RISK_EXTREME: return "🔴 EXTREME RISK";
default: return "UNKNOWN";
}
}
//+------------------------------------------------------------------+
//| Update daily risk |
//+------------------------------------------------------------------+
void CAdvancedRiskManager::UpdateDailyRisk(void)
{
// Check if new day
datetime currentTime = TimeCurrent();
MqlDateTime timeStruct;
TimeToStruct(currentTime, timeStruct);
MqlDateTime lastResetStruct;
TimeToStruct(m_lastResetTime, lastResetStruct);
if(timeStruct.day != lastResetStruct.day)
{
ResetDailyCounters();
}
// Calculate daily P&L
double dailyPL = m_accountEquity - m_dailyStartBalance;
m_dailyRisk = MathAbs(dailyPL / m_dailyStartBalance) * 100.0;
}
//+------------------------------------------------------------------+
//| Reset daily counters |
//+------------------------------------------------------------------+
void CAdvancedRiskManager::ResetDailyCounters(void)
{
m_dailyStartBalance = AccountInfoDouble(ACCOUNT_EQUITY);
m_dailyRisk = 0;
m_lastResetTime = TimeCurrent();
Print("📅 Daily risk counters reset");
}
//+------------------------------------------------------------------+
//| Get max drawdown |
//+------------------------------------------------------------------+
double CAdvancedRiskManager::GetMaxDrawdown(void)
{
return m_maxHistoricalDrawdown;
}
//+------------------------------------------------------------------+
//| Add position to tracking |
//+------------------------------------------------------------------+
void CAdvancedRiskManager::AddPosition(ulong ticket, string symbol, double volume, double stopLoss)
{
if(m_positionCount < 50)
{
m_positions[m_positionCount].ticket = ticket;
m_positions[m_positionCount].symbol = symbol;
m_positions[m_positionCount].volume = volume;
m_positions[m_positionCount].riskPercent = CalculatePositionRisk(symbol, volume, stopLoss);
m_positionCount++;
}
}
//+------------------------------------------------------------------+
//| Remove position from tracking |
//+------------------------------------------------------------------+
void CAdvancedRiskManager::RemovePosition(ulong ticket)
{
for(int i = 0; i < m_positionCount; i++)
{
if(m_positions[i].ticket == ticket)
{
// Shift remaining positions
for(int j = i; j < m_positionCount - 1; j++)
{
m_positions[j] = m_positions[j + 1];
}
m_positionCount--;
break;
}
}
}
//+------------------------------------------------------------------+
//| Calculate VaR for specific position |
//+------------------------------------------------------------------+
double CAdvancedRiskManager::CalculateVaR(string symbol, double volume, int confidence = 95)
{
// Simplified VaR calculation
double volatility = 0.015; // 1.5% daily volatility assumption
double confidenceLevel = (confidence == 95) ? 1.65 : 2.33; // 95% or 99%
double positionValue = volume * SymbolInfoDouble(symbol, SYMBOL_ASK);
double var = positionValue * volatility * confidenceLevel;
return var;
}
#endif // RISK_MANAGER_MQH