| //+------------------------------------------------------------------+
|
| //| PositionSizer.mqh |
|
| //| Copyright 2025, Your Company Name |
|
| //| https://www.yoursite.com |
|
| //+------------------------------------------------------------------+
|
| #property copyright "Copyright 2025, Your Company Name"
|
| #property link "https://www.yoursite.com"
|
| #property version "1.00"
|
| #property strict
|
|
|
| #include "RiskParameters.mqh"
|
| #include "RiskMetrics.mqh"
|
|
|
| //+------------------------------------------------------------------+
|
| //| Position Sizer Class |
|
| //+------------------------------------------------------------------+
|
| class CPositionSizer
|
| {
|
| private:
|
| CRiskParameters* m_params; // Risk parameters
|
| CRiskMetrics* m_metrics; // Risk metrics
|
|
|
| // Position sizing parameters
|
| double m_volatilityFactor; // Current volatility adjustment factor
|
| double m_correlationFactor; // Correlation adjustment factor
|
|
|
| // State
|
| bool m_isInitialized; // Initialization flag
|
|
|
| // Private methods
|
| double CalculateBasePositionSize(const string symbol, const double stopLossPips,
|
| const double riskPercent, const double accountEquity);
|
| double ApplyVolatilityAdjustment(const string symbol, const double size);
|
| double ApplyCorrelationAdjustment(const string symbol, const double size);
|
| double ApplyLeverageAdjustment(const double size);
|
| double ApplyLotStepRounding(const string symbol, const double size);
|
|
|
| public:
|
| // Constructor/Destructor
|
| CPositionSizer();
|
| ~CPositionSizer();
|
|
|
| // Initialization
|
| bool Initialize(CRiskParameters* params = NULL, CRiskMetrics* metrics = NULL);
|
| void Deinitialize();
|
|
|
| // Position sizing
|
| bool CalculateSize(const string symbol, const double stopLossPips,
|
| const double riskPercent, const double accountEquity,
|
| double &size);
|
|
|
| // Update methods
|
| void UpdateVolatility(const double volatility);
|
| void UpdateCorrelation(const double correlation);
|
|
|
| // Getters
|
| double GetVolatilityFactor() const { return m_volatilityFactor; }
|
| double GetCorrelationFactor() const { return m_correlationFactor; }
|
| bool IsInitialized() const { return m_isInitialized; }
|
| };
|
|
|
| //+------------------------------------------------------------------+
|
| //| Constructor |
|
| //+------------------------------------------------------------------+
|
| CPositionSizer::CPositionSizer() :
|
| m_params(NULL),
|
| m_metrics(NULL),
|
| m_volatilityFactor(1.0),
|
| m_correlationFactor(1.0),
|
| m_isInitialized(false)
|
| {
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Destructor |
|
| //+------------------------------------------------------------------+
|
| CPositionSizer::~CPositionSizer()
|
| {
|
| Deinitialize();
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Initialize position sizer |
|
| //+------------------------------------------------------------------+
|
| bool CPositionSizer::Initialize(CRiskParameters* params = NULL, CRiskMetrics* metrics = NULL)
|
| {
|
| m_params = params;
|
| m_metrics = metrics;
|
| m_volatilityFactor = 1.0;
|
| m_correlationFactor = 1.0;
|
|
|
| m_isInitialized = true;
|
| return true;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Deinitialize position sizer |
|
| //+------------------------------------------------------------------+
|
| void CPositionSizer::Deinitialize()
|
| {
|
| m_params = NULL;
|
| m_metrics = NULL;
|
| m_isInitialized = false;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Calculate position size |
|
| //+------------------------------------------------------------------+
|
| bool CPositionSizer::CalculateSize(const string symbol, const double stopLossPips,
|
| const double riskPercent, const double accountEquity,
|
| double &size)
|
| {
|
| if (!m_isInitialized || stopLossPips <= 0.0 || riskPercent <= 0.0 || accountEquity <= 0.0)
|
| return false;
|
|
|
| // Calculate base position size based on risk percentage
|
| double baseSize = CalculateBasePositionSize(symbol, stopLossPips, riskPercent, accountEquity);
|
| if (baseSize <= 0.0)
|
| return false;
|
|
|
| // Apply adjustments
|
| double adjustedSize = baseSize;
|
|
|
| // Apply volatility adjustment if metrics are available
|
| if (m_metrics != NULL)
|
| {
|
| adjustedSize = ApplyVolatilityAdjustment(symbol, adjustedSize);
|
| }
|
|
|
| // Apply correlation adjustment if metrics are available
|
| if (m_metrics != NULL)
|
| {
|
| adjustedSize = ApplyCorrelationAdjustment(symbol, adjustedSize);
|
| }
|
|
|
| // Apply leverage adjustment
|
| adjustedSize = ApplyLeverageAdjustment(adjustedSize);
|
|
|
| // Apply lot step rounding
|
| adjustedSize = ApplyLotStepRounding(symbol, adjustedSize);
|
|
|
| // Ensure size is within allowed limits
|
| if (m_params != NULL)
|
| {
|
| adjustedSize = MathMin(adjustedSize, m_params.GetMaxLotsPerTrade());
|
| adjustedSize = MathMax(adjustedSize, m_params.GetMinPositionSize());
|
| }
|
|
|
| size = adjustedSize;
|
| return (size > 0.0);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Calculate base position size based on risk percentage |
|
| //+------------------------------------------------------------------+
|
| double CPositionSizer::CalculateBasePositionSize(const string symbol, const double stopLossPips,
|
| const double riskPercent, const double accountEquity)
|
| {
|
| // Get symbol information
|
| double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
|
| double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
|
| double lotSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
|
| double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
|
|
| if (tickSize <= 0.0 || tickValue <= 0.0 || lotSize <= 0.0 || point <= 0.0)
|
| return 0.0;
|
|
|
| // Calculate pip value (accounting for 5-digit brokers)
|
| double pipValue = point * 10.0;
|
|
|
| // Calculate value per pip
|
| double valuePerPip = (tickValue / tickSize) * pipValue;
|
|
|
| // Calculate risk amount in account currency
|
| double riskAmount = accountEquity * (riskPercent / 100.0);
|
|
|
| // Calculate position size in lots
|
| double stopLossValue = stopLossPips * valuePerPip;
|
| if (stopLossValue <= 0.0)
|
| return 0.0;
|
|
|
| double positionSize = riskAmount / stopLossValue;
|
|
|
| // Convert to lots
|
| double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
| if (lotStep > 0.0)
|
| {
|
| positionSize = MathFloor(positionSize / lotStep) * lotStep;
|
| }
|
|
|
| return positionSize;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Apply volatility adjustment to position size |
|
| //+------------------------------------------------------------------
|
| double CPositionSizer::ApplyVolatilityAdjustment(const string symbol, const double size)
|
| {
|
| if (m_metrics == NULL || !m_params.UseVolatility())
|
| return size;
|
|
|
| double currentVol = m_metrics.GetCurrentVolatility();
|
| double historicalVol = m_metrics.GetHistoricalVolatility();
|
|
|
| // If we don't have valid volatility data, return original size
|
| if (currentVol <= 0.0 || historicalVol <= 0.0)
|
| return size;
|
|
|
| // Calculate volatility ratio (current / historical)
|
| double volRatio = currentVol / historicalVol;
|
|
|
| // Apply inverse relationship: higher volatility = smaller position
|
| // Cap the adjustment to avoid extreme position sizing
|
| volRatio = MathMax(0.5, MathMin(2.0, 1.0 / volRatio));
|
|
|
| // Apply volatility factor from parameters
|
| if (m_params != NULL)
|
| {
|
| volRatio *= m_params.GetVolatilityFactor();
|
| }
|
|
|
| m_volatilityFactor = volRatio;
|
| return size * volRatio;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Apply correlation adjustment to position size |
|
| //+------------------------------------------------------------------
|
| double CPositionSizer::ApplyCorrelationAdjustment(const string symbol, const double size)
|
| {
|
| if (m_metrics == NULL || !m_params.UseCorrelation())
|
| return size;
|
|
|
| // This is a simplified implementation
|
| // In practice, you would check correlation with existing positions
|
|
|
| // For now, we'll just return the original size
|
| // A full implementation would use the correlation matrix
|
|
|
| return size;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Apply leverage adjustment to position size |
|
| //+------------------------------------------------------------------
|
| double CPositionSizer::ApplyLeverageAdjustment(const double size)
|
| {
|
| if (m_params == NULL)
|
| return size;
|
|
|
| double maxLeverage = m_params.GetMaxLeverage();
|
| double accountLeverage = (double)AccountInfoInteger(ACCOUNT_LEVERAGE);
|
|
|
| if (maxLeverage <= 0.0 || accountLeverage <= 0.0)
|
| return size;
|
|
|
| // Adjust position size based on leverage
|
| double leverageRatio = MathMin(1.0, maxLeverage / accountLeverage);
|
| return size * leverageRatio;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Apply lot step rounding |
|
| //+------------------------------------------------------------------
|
| double CPositionSizer::ApplyLotStepRounding(const string symbol, const double size)
|
| {
|
| double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
| double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
| double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
|
|
| if (lotStep <= 0.0)
|
| return size;
|
|
|
| // Round to nearest lot step
|
| double roundedSize = MathFloor(size / lotStep + 0.5) * lotStep;
|
|
|
| // Ensure within min/max limits
|
| if (minLot > 0.0)
|
| roundedSize = MathMax(roundedSize, minLot);
|
|
|
| if (maxLot > 0.0)
|
| roundedSize = MathMin(roundedSize, maxLot);
|
|
|
| return roundedSize;
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Update volatility factor |
|
| //+------------------------------------------------------------------
|
| void CPositionSizer::UpdateVolatility(const double volatility)
|
| {
|
| if (volatility > 0.0)
|
| {
|
| // Store the inverse of volatility (higher volatility = smaller position)
|
| m_volatilityFactor = 1.0 / (1.0 + volatility);
|
| }
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| Update correlation factor |
|
| //+------------------------------------------------------------------
|
| void CPositionSizer::UpdateCorrelation(const double correlation)
|
| {
|
| // Store the inverse of correlation (higher correlation = smaller position)
|
| m_correlationFactor = 1.0 - (0.5 * correlation);
|
| }
|