//+------------------------------------------------------------------+ //| 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 #include #include #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; }