615 lines
23 KiB
MQL5
615 lines
23 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| PositionManager.mqh |
| |||
//| Copyright 2025, EscapeEA |
| |||
//| https://www.escapeea.com |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "Copyright 2025, EscapeEA"
| |||
#property link "https://www.escapeea.com"
| |||
#property version "1.00"
| |||
#property strict
| |||
| |||
#include <Trade\PositionInfo.mqh>
| |||
#include <Trade\SymbolInfo.mqh>
| |||
#include <Trade\Trade.mqh>
| |||
#include "InputValidation.mqh"
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Position scaling profiles |
| |||
//+------------------------------------------------------------------+
| |||
enum ENUM_SCALING_PROFILE {
| |||
SCALING_NONE, // No scaling
| |||
SCALING_CONSERVATIVE, // Conservative scaling
| |||
SCALING_MODERATE, // Moderate scaling
| |||
SCALING_AGGRESSIVE // Aggressive scaling
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Exit profiles |
| |||
//+------------------------------------------------------------------+
| |||
enum ENUM_EXIT_PROFILE {
| |||
EXIT_AGGRESSIVE, // Aggressive exit (tighter stops)
| |||
EXIT_BALANCED, // Balanced exit
| |||
EXIT_CONSERVATIVE // Conservative exit (wider stops)
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Position Manager class |
| |||
//+------------------------------------------------------------------+
| |||
class CPositionManager {
| |||
private:
| |||
CTrade *m_trade; // Trade object
| |||
CSymbolInfo *m_symbol; // Symbol info
| |||
CPositionInfo m_position; // Position info
| |||
| |||
// Configuration
| |||
double m_slPoints; // Stop loss in points
| |||
double m_tpPoints; // Take profit in points
| |||
double m_trailingStop; // Trailing stop in points
| |||
double m_breakEven; // Break even level in points
| |||
| |||
// State
| |||
bool m_initialized; // Initialization flag
| |||
bool m_autoBreakEven; // Auto break-even flag
| |||
bool m_scaleIn; // Scale into positions flag
| |||
bool m_scaleOut; // Scale out of positions flag
| |||
| |||
// Advanced position management
| |||
double m_breakEvenAt; // Pips in profit to move to break-even
| |||
double m_scaleInAt; // Pips in drawdown to scale in
| |||
double m_scaleOutAt; // Pips in profit to scale out
| |||
double m_scaleInFactor; // Scale-in volume factor
| |||
double m_scaleOutFactor; // Scale-out volume factor
| |||
| |||
// Private methods
| |||
bool CheckTrailingStop();
| |||
bool CheckBreakEven();
| |||
| |||
public:
| |||
// Constructor/Destructor
| |||
CPositionManager();
| |||
~CPositionManager();
| |||
| |||
// Initialization
| |||
bool Initialize(CTrade *trade, CSymbolInfo *symbol,
| |||
double slPoints, double tpPoints,
| |||
double trailingStop = 0, double breakEven = 0);
| |||
| |||
// Position management
| |||
bool OpenPosition(ENUM_ORDER_TYPE type, double volume,
| |||
double price, double sl, double tp,
| |||
const string comment = "");
| |||
bool ClosePosition(ulong ticket, const string comment = "");
| |||
bool CloseAllPositions(const string comment = "");
| |||
bool ModifyPosition(ulong ticket, double sl, double tp);
| |||
| |||
// Advanced position management
| |||
bool SetScalingProfile(ENUM_SCALING_PROFILE profile);
| |||
bool SetExitProfile(ENUM_EXIT_PROFILE profile);
| |||
| |||
// Getters
| |||
bool IsInitialized() const { return m_initialized; }
| |||
double GetPositionSize(ulong ticket);
| |||
double GetPositionProfit(ulong ticket);
| |||
double GetPositionStopLoss(ulong ticket);
| |||
double GetPositionTakeProfit(ulong ticket);
| |||
| |||
// Utility
| |||
void Update();
| |||
| |||
// Advanced methods
| |||
bool ScaleInPosition(ulong ticket, double volume);
| |||
bool ScaleOutPosition(ulong ticket, double volume);
| |||
double GetPositionRisk(ulong ticket);
| |||
bool SetDynamicRisk(bool enable, double maxDailyDrawdown = 5.0,
| |||
double maxPositionRisk = 2.0, double maxPortfolioRisk = 20.0,
| |||
double riskDecay = 0.9);
| |||
| |||
// Position clustering
| |||
bool SetPositionClustering(bool enable, double clusterDistance = 20.0, int maxClusters = 3);
| |||
| |||
// Market regime detection
| |||
bool SetRegimeFilter(bool enable, double trendThreshold = 0.3);
| |||
| |||
// News event handling
| |||
bool SetNewsFilter(bool enable, int minImpact = 2, int minutesBefore = 30, int minutesAfter = 15);
| |||
| |||
// Volatility-based position sizing
| |||
bool SetVolatilitySizing(bool enable, int period = 14, double multiplier = 1.5, double maxRisk = 2.0);
| |||
| |||
// Correlation management
| |||
bool SetCorrelationFilter(bool enable, const string &symbols = "", double maxCorrelation = 0.7);
| |||
| |||
// Grid trading
| |||
bool SetGridTrading(bool enable, double gridStep = 20.0, int maxLevels = 5, double volumeMultiplier = 1.5);
| |||
| |||
// Machine learning integration
| |||
bool SetMLIntegration(bool enable, double confidenceThreshold = 0.7);
| |||
| |||
// Adaptive position sizing
| |||
bool SetAdaptiveSizing(bool enable, double winRate = 0.5, double profitFactor = 1.5);
| |||
| |||
// Advanced exit strategies
| |||
bool SetTrailingDrawdown(bool enable, double drawdownPercent = 30.0);
| |||
bool SetVolatilityExit(bool enable, double volatilityLevel = 2.0);
| |||
| |||
// Time-based exit
| |||
bool SetTimeExit(bool enable, int maxHoldBars = 50);
| |||
| |||
// Position monitoring
| |||
bool UpdatePositionMetrics(ulong ticket);
| |||
| |||
// Risk management
| |||
bool CheckDailyDrawdown();
| |||
bool CheckPortfolioRisk();
| |||
| |||
// Position analysis
| |||
double CalculatePositionScore(const string symbol, ENUM_ORDER_TYPE type);
| |||
double CalculateOptimalF(double winRate, double winLossRatio);
| |||
double CalculateKellyCriterion(double winRate, double winLossRatio);
| |||
| |||
// Position clustering
| |||
bool IsInCluster(ulong ticket, double distance = 20.0);
| |||
| |||
// Market regime detection
| |||
ENUM_MARKET_REGIME GetMarketRegime();
| |||
| |||
// News impact analysis
| |||
int GetNewsImpact();
| |||
| |||
// Volatility analysis
| |||
double GetCurrentVolatility();
| |||
| |||
// Correlation analysis
| |||
double GetPortfolioCorrelation(const string symbol);
| |||
| |||
// Machine learning
| |||
bool LoadMLModel(const string modelFile);
| |||
double GetMLPositionScore(const string symbol, ENUM_ORDER_TYPE type);
| |||
bool UpdateMLModel(const MqlRates &rates[], const double &features[]);
| |||
| |||
// Advanced position monitoring
| |||
bool CheckPositionHealth(ulong ticket);
| |||
bool CheckMarketConditions();
| |||
bool CheckPositionTiming(ulong ticket);
| |||
| |||
// Advanced position adjustments
| |||
bool HedgePosition(ulong ticket);
| |||
bool AverageDown(ulong ticket, double maxDrawdown = 10.0);
| |||
bool ScaleOutAtProfit(ulong ticket, double profitTarget = 30.0, double scalePercent = 50.0);
| |||
| |||
// Position analysis
| |||
double CalculatePositionValue(ulong ticket);
| |||
double CalculatePositionRiskReward(ulong ticket);
| |||
double CalculatePositionScore(ulong ticket);
| |||
| |||
// Advanced order types
| |||
bool PlaceBracketOrder(const string symbol, ENUM_ORDER_TYPE type, double volume,
| |||
double entryPrice, double sl, double tp,
| |||
double breakEvenAt = 0, double trailingStop = 0,
| |||
datetime expiration = 0, const string comment = "");
| |||
| |||
// Advanced position management
| |||
bool ScalePosition(ulong ticket, double newVolume);
| |||
bool ScalePositionByRisk(ulong ticket, double riskPercent);
| |||
bool ScalePositionByVolatility(ulong ticket, double volatilityMultiplier = 1.0);
| |||
| |||
// Position monitoring and adjustment
| |||
bool CheckAndAdjustPosition(ulong ticket);
| |||
bool MonitorAndManagePositions();
| |||
| |||
// Advanced risk management
| |||
bool SetRiskParameters(double maxRiskPerTrade, double maxDailyRisk, double maxDrawdown);
| |||
bool CheckRiskParameters();
| |||
| |||
// Position analysis and optimization
| |||
double CalculateOptimalPositionSize(double riskAmount, double stopLoss);
| |||
double CalculatePositionRisk(double entryPrice, double stopLoss, double lotSize);
| |||
double CalculatePositionValue(double entryPrice, double lotSize);
| |||
| |||
// Advanced position monitoring
| |||
bool CheckPositionHealth(ulong ticket, double maxDrawdown = 20.0);
| |||
bool CheckPositionTiming(ulong ticket, int maxBars = 50);
| |||
| |||
// Advanced position adjustments
| |||
bool TrailingStop(ulong ticket, double trailingStop);
| |||
bool MoveToBreakEven(ulong ticket, double breakEvenAt);
| |||
| |||
// Position analysis
| |||
double CalculatePositionRiskReward(ulong ticket, double entryPrice, double stopLoss, double takeProfit);
| |||
double CalculatePositionScore(ulong ticket, double winRate, double profitFactor);
| |||
| |||
// Advanced order management
| |||
bool PlaceOCOOrders(ulong ticket, double stopLoss, double takeProfit);
| |||
bool PlaceBracketOrder(ulong ticket, double stopLoss, double takeProfit,
| |||
double breakEvenAt = 0, double trailingStop = 0);
| |||
| |||
// Position monitoring and management
| |||
bool MonitorPosition(ulong ticket);
| |||
bool ManagePosition(ulong ticket);
| |||
| |||
// Advanced position management
| |||
bool ScaleInAtDrawdown(ulong ticket, double drawdownPercent, double scaleFactor = 1.0);
| |||
bool ScaleOutAtProfit(ulong ticket, double profitPercent, double scaleFactor = 0.5);
| |||
| |||
// Position analysis and optimization
| |||
double CalculateOptimalPositionSize(double accountBalance, double riskPercent,
| |||
double stopLoss, double contractSize);
| |||
double CalculatePositionRisk(double entryPrice, double stopLoss,
| |||
double lotSize, double contractSize);
| |||
| |||
// Advanced position monitoring
| |||
bool CheckPositionHealth(ulong ticket, double maxDrawdownPercent,
| |||
int maxBarsHeld, double minRiskReward);
| |||
| |||
// Advanced position adjustments
| |||
bool AdjustStopLoss(ulong ticket, double newStopLoss);
| |||
bool AdjustTakeProfit(ulong ticket, double newTakeProfit);
| |||
| |||
// Position analysis
| |||
double CalculatePositionValue(double entryPrice, double lotSize, double contractSize);
| |||
double CalculatePositionRiskReward(ulong ticket, double currentPrice);
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Constructor |
| |||
//+------------------------------------------------------------------+
| |||
CPositionManager::CPositionManager() :
| |||
m_trade(NULL),
| |||
m_symbol(NULL),
| |||
m_initialized(false),
| |||
m_slPoints(0.0),
| |||
m_tpPoints(0.0),
| |||
m_trailingStop(0.0),
| |||
m_breakEven(0.0),
| |||
m_autoBreakEven(false),
| |||
m_scaleIn(false),
| |||
m_scaleOut(false),
| |||
m_breakEvenAt(0.0),
| |||
m_scaleInAt(0.0),
| |||
m_scaleOutAt(0.0),
| |||
m_scaleInFactor(1.0),
| |||
m_scaleOutFactor(0.5)
| |||
{
| |||
// Initialize member variables in the initialization list
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Destructor |
| |||
//+------------------------------------------------------------------+
| |||
CPositionManager::~CPositionManager() {
| |||
// Cleanup if needed
| |||
if(m_trade != NULL) {
| |||
delete m_trade;
| |||
m_trade = NULL;
| |||
}
| |||
| |||
if(m_symbol != NULL) {
| |||
delete m_symbol;
| |||
m_symbol = NULL;
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Initialize the position manager |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::Initialize(CTrade *trade, CSymbolInfo *symbol,
| |||
double slPoints, double tpPoints,
| |||
double trailingStop, double breakEven) {
| |||
// Validate inputs
| |||
if(trade == NULL || symbol == NULL) {
| |||
Print("Error: Invalid trade or symbol pointer");
| |||
return false;
| |||
}
| |||
| |||
if(slPoints < 0 || tpPoints < 0 || trailingStop < 0 || breakEven < 0) {
| |||
Print("Error: Invalid parameters");
| |||
return false;
| |||
}
| |||
| |||
// Store references
| |||
m_trade = trade;
| |||
m_symbol = symbol;
| |||
| |||
// Store parameters
| |||
m_slPoints = slPoints;
| |||
m_tpPoints = tpPoints;
| |||
m_trailingStop = trailingStop;
| |||
m_breakEven = breakEven;
| |||
| |||
m_initialized = true;
| |||
return true;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Open a new position |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::OpenPosition(ENUM_ORDER_TYPE type, double volume,
| |||
double price, double sl, double tp,
| |||
const string comment) {
| |||
if(!m_initialized) {
| |||
Print("Error: Position manager not initialized");
| |||
return false;
| |||
}
| |||
| |||
// Validate inputs
| |||
if(volume <= 0 || price <= 0) {
| |||
Print("Error: Invalid volume or price");
| |||
return false;
| |||
}
| |||
| |||
// Execute the trade
| |||
if(type == ORDER_TYPE_BUY) {
| |||
return m_trade.Buy(volume, m_symbol.Name(), price, sl, tp, comment);
| |||
}
| |||
else if(type == ORDER_TYPE_SELL) {
| |||
return m_trade.Sell(volume, m_symbol.Name(), price, sl, tp, comment);
| |||
}
| |||
| |||
return false;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Close a position by ticket |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::ClosePosition(ulong ticket, const string comment) {
| |||
if(!m_initialized) {
| |||
Print("Error: Position manager not initialized");
| |||
return false;
| |||
}
| |||
| |||
// Select the position
| |||
if(!m_position.SelectByTicket(ticket)) {
| |||
Print("Error selecting position ", ticket);
| |||
return false;
| |||
}
| |||
| |||
// Close the position
| |||
return m_trade.PositionClose(ticket, m_position.Deviation(), comment);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Close all open positions |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::CloseAllPositions(const string comment) {
| |||
if(!m_initialized) {
| |||
Print("Error: Position manager not initialized");
| |||
return false;
| |||
}
| |||
| |||
bool result = true;
| |||
int total = PositionsTotal();
| |||
| |||
for(int i = total - 1; i >= 0; i--) {
| |||
ulong ticket = PositionGetTicket(i);
| |||
if(ticket > 0) {
| |||
if(!ClosePosition(ticket, comment)) {
| |||
result = false;
| |||
}
| |||
}
| |||
}
| |||
| |||
return result;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Modify position stop loss and take profit |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::ModifyPosition(ulong ticket, double sl, double tp) {
| |||
if(!m_initialized) {
| |||
Print("Error: Position manager not initialized");
| |||
return false;
| |||
}
| |||
| |||
// Select the position
| |||
if(!m_position.SelectByTicket(ticket)) {
| |||
Print("Error selecting position ", ticket);
| |||
return false;
| |||
}
| |||
| |||
// Modify the position
| |||
return m_trade.PositionModify(ticket, sl, tp);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Set position scaling profile |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::SetScalingProfile(ENUM_SCALING_PROFILE profile) {
| |||
switch(profile) {
| |||
case SCALING_AGGRESSIVE:
| |||
m_scaleInFactor = 1.5;
| |||
m_scaleOutFactor = 0.5;
| |||
m_scaleInAt = 20.0;
| |||
m_scaleOutAt = 30.0;
| |||
break;
| |||
| |||
case SCALING_MODERATE:
| |||
m_scaleInFactor = 1.25;
| |||
m_scaleOutFactor = 0.75;
| |||
m_scaleInAt = 25.0;
| |||
m_scaleOutAt = 40.0;
| |||
break;
| |||
| |||
case SCALING_CONSERVATIVE:
| |||
m_scaleInFactor = 1.1;
| |||
m_scaleOutFactor = 0.9;
| |||
m_scaleInAt = 30.0;
| |||
m_scaleOutAt = 50.0;
| |||
break;
| |||
| |||
case SCALING_NONE:
| |||
default:
| |||
m_scaleIn = false;
| |||
m_scaleOut = false;
| |||
return true;
| |||
}
| |||
| |||
m_scaleIn = true;
| |||
m_scaleOut = true;
| |||
return true;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Set exit profile |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::SetExitProfile(ENUM_EXIT_PROFILE profile) {
| |||
switch(profile) {
| |||
case EXIT_AGGRESSIVE:
| |||
m_trailingStop = 20.0;
| |||
m_breakEvenAt = 15.0;
| |||
break;
| |||
| |||
case EXIT_BALANCED:
| |||
m_trailingStop = 30.0;
| |||
m_breakEvenAt = 25.0;
| |||
break;
| |||
| |||
case EXIT_CONSERVATIVE:
| |||
m_trailingStop = 50.0;
| |||
m_breakEvenAt = 40.0;
| |||
break;
| |||
}
| |||
| |||
return true;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Get position size |
| |||
//+------------------------------------------------------------------+
| |||
double CPositionManager::GetPositionSize(ulong ticket) {
| |||
if(m_position.SelectByTicket(ticket)) {
| |||
return m_position.Volume();
| |||
}
| |||
return 0.0;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Get position profit |
| |||
//+------------------------------------------------------------------+
| |||
double CPositionManager::GetPositionProfit(ulong ticket) {
| |||
if(m_position.SelectByTicket(ticket)) {
| |||
return m_position.Profit();
| |||
}
| |||
return 0.0;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Get position stop loss level |
| |||
//+------------------------------------------------------------------+
| |||
double CPositionManager::GetPositionStopLoss(ulong ticket) {
| |||
if(m_position.SelectByTicket(ticket)) {
| |||
return m_position.StopLoss();
| |||
}
| |||
return 0.0;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Get position take profit level |
| |||
//+------------------------------------------------------------------+
| |||
double CPositionManager::GetPositionTakeProfit(ulong ticket) {
| |||
if(m_position.SelectByTicket(ticket)) {
| |||
return m_position.TakeProfit();
| |||
}
| |||
return 0.0;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Update position manager (call in OnTick) |
| |||
//+------------------------------------------------------------------+
| |||
void CPositionManager::Update() {
| |||
if(!m_initialized) {
| |||
return;
| |||
}
| |||
| |||
// Update trailing stops if enabled
| |||
if(m_trailingStop > 0) {
| |||
CheckTrailingStop();
| |||
}
| |||
| |||
// Update break-even if enabled
| |||
if(m_breakEven > 0) {
| |||
CheckBreakEven();
| |||
}
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Check and update trailing stop |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::CheckTrailingStop() {
| |||
if(!m_initialized || m_trailingStop <= 0) {
| |||
return false;
| |||
}
| |||
| |||
bool result = true;
| |||
int total = PositionsTotal();
| |||
| |||
for(int i = 0; i < total; i++) {
| |||
ulong ticket = PositionGetTicket(i);
| |||
if(ticket > 0 && m_position.SelectByTicket(ticket)) {
| |||
double currentSl = m_position.StopLoss();
| |||
double currentPrice = (m_position.PositionType() == POSITION_TYPE_BUY) ?
| |||
m_position.PriceCurrent() : m_position.PriceOpen();
| |||
double newSl = 0.0;
| |||
| |||
if(m_position.PositionType() == POSITION_TYPE_BUY) {
| |||
newSl = m_symbol.Bid() - (m_trailingStop * m_symbol.Point());
| |||
if(newSl > currentSl && newSl < m_symbol.Bid()) {
| |||
if(!ModifyPosition(ticket, newSl, m_position.TakeProfit())) {
| |||
result = false;
| |||
}
| |||
}
| |||
}
| |||
else if(m_position.PositionType() == POSITION_TYPE_SELL) {
| |||
newSl = m_symbol.Ask() + (m_trailingStop * m_symbol.Point());
| |||
if((newSl < currentSl || currentSl == 0) && newSl > m_symbol.Ask()) {
| |||
if(!ModifyPosition(ticket, newSl, m_position.TakeProfit())) {
| |||
result = false;
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
return result;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Check and update break-even level |
| |||
//+------------------------------------------------------------------+
| |||
bool CPositionManager::CheckBreakEven() {
| |||
if(!m_initialized || m_breakEven <= 0) {
| |||
return false;
| |||
}
| |||
| |||
bool result = true;
| |||
int total = PositionsTotal();
| |||
| |||
for(int i = 0; i < total; i++) {
| |||
ulong ticket = PositionGetTicket(i);
| |||
if(ticket > 0 && m_position.SelectByTicket(ticket)) {
| |||
double currentSl = m_position.StopLoss();
| |||
double openPrice = m_position.PriceOpen();
| |||
double currentPrice = (m_position.PositionType() == POSITION_TYPE_BUY) ?
| |||
m_position.PriceCurrent() : m_position.PriceOpen();
| |||
double pointsProfit = MathAbs(currentPrice - openPrice) / m_symbol.Point();
| |||
| |||
if(pointsProfit >= m_breakEven) {
| |||
if(m_position.PositionType() == POSITION_TYPE_BUY) {
| |||
if(currentSl < openPrice) {
| |||
if(!ModifyPosition(ticket, openPrice, m_position.TakeProfit())) {
| |||
result = false;
| |||
}
| |||
}
| |||
}
| |||
else if(m_position.PositionType() == POSITION_TYPE_SELL) {
| |||
if(currentSl > openPrice || currentSl == 0) {
| |||
if(!ModifyPosition(ticket, openPrice, m_position.TakeProfit())) {
| |||
result = false;
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
return result;
| |||
}
|