forked from Princeec13/mql5
306 lines
11 KiB
MQL5
306 lines
11 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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);
|
|
}
|