mql5/Include/Escape/PositionManager.mqh

615 righe
23 KiB
MQL5

2025-08-05 01:57:33 -04:00
//+------------------------------------------------------------------+
//| 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;
}