mql5/Shared Projects/ERMT-ML/Modules-ML8x/TradeManager_v71.mqh

766 lines
27 KiB
MQL5
Raw Permalink Normal View History

Module Integration Summary for External Trade Management Overview To fully integrate the enhanced external trade management system, updates are required to 5 out of 7 existing modules. The updates maintain backward compatibility while adding new functionality for external trade handling. Module Update Requirements 🟢 No Updates Required (2 modules) TechnicalAnalysis.mqh - Already provides necessary calculations EntrySystem.mqh - Only handles EA's own entry signals 🟡 Minor Updates (2 modules) DataTypes.mqh - Add external trade structures and fields Utilities.mqh - Enhanced logging for external trades 🟠 Moderate Updates (3 modules) RiskManager.mqh - Enhanced risk enforcement methods TradeManager.mqh - Improved stop management for externals Dashboard.mqh - Display external trade information Integration Steps Phase 1: Data Structures (DataTypes.mqh) Add ENUM_EXTERNAL_STATUS enumeration Extend ManagedTrade structure with external-specific fields Add ExternalTradeStats structure for metrics Update DashboardConfig with show_external flag Key additions: external_status - Track state of external trade source_name - Identify where trade came from stops_modified - Track if we modified the trade original_sl/tp - Store original values for comparison Phase 2: Risk Management (RiskManager.mqh) Add EnforceRiskRulesEnhanced() method Implement GetExternalExposure() for risk aggregation Add UpdateExternalStats() for tracking Enhance ValidateAndAdjustRiskExternal() method Key features: Separate risk calculation for external trades Cache mechanism for performance Statistical tracking of external positions Smart risk adjustment without closing trades Phase 3: Trade Management (TradeManager.mqh) Add ApplyDefaultStopsEnhanced() with better logic Implement OverrideExternalStops() with smart override Create ManageExternalTrade() with different rules Add ApplyBreakevenExternal() with wider triggers Key features: Smart stop override (only improve, never worsen) Different management rules for external trades Respect minimum broker distances Track modification success/failure rates Phase 4: User Interface (Dashboard.mqh) Add CreateExternalSection() for display area Implement UpdateExternalSection() for real-time updates Add SetCustomText() for flexible display Create ShowExternalTrades() toggle method Key features: Real-time external trade count and risk Color-coded risk warnings List of active external positions Modification statistics display Phase 5: Logging (Utilities.mqh) Add LogExternalTrade() for detailed event logging Create separate CSV log for external trades Enhance GenerateReportEnhanced() with external section Add IdentifyTradeSource() for magic number interpretation Key features: Separate CSV log for external trade events Detailed tracking of all modifications Source identification from magic numbers Enhanced reporting with external statistics
2025-08-27 14:21:02 +01:00
//+------------------------------------------------------------------+
//| TradeManager_v71.mqh |
//| Smart Trade Execution Module v7.1 |
//| Iceberg Orders, TWAP/VWAP, Execution Optimization |
//+------------------------------------------------------------------+
#ifndef TRADE_MANAGER_V71_MQH
#define TRADE_MANAGER_V71_MQH
#include "DataTypes_v71.mqh"
#include <Trade/Trade.mqh>
#include <Trade/SymbolInfo.mqh>
#include <Trade/PositionInfo.mqh>
#include <Trade/OrderInfo.mqh>
//+------------------------------------------------------------------+
//| Trade Manager Class - Institutional Execution |
//+------------------------------------------------------------------+
class CTradeManagerV71
{
private:
//--- Configuration
TradeManagerConfigV71 m_config;
//--- Trade operations
CTrade m_trade;
CPositionInfo m_position;
COrderInfo m_order;
//--- Execution tracking
ExecutionStats m_exec_stats;
datetime m_last_execution;
//--- Iceberg order management
struct IcebergOrder
{
ulong parent_ticket;
string symbol;
ENUM_ORDER_TYPE type;
double total_volume;
double displayed_volume;
double filled_volume;
double price_limit;
datetime expiry;
bool is_active;
};
IcebergOrder m_iceberg_orders[];
//--- TWAP/VWAP tracking
struct TWAPOrder
{
string symbol;
ENUM_ORDER_TYPE type;
double total_volume;
double filled_volume;
datetime start_time;
datetime end_time;
int slices;
double last_slice_time;
};
TWAPOrder m_twap_orders[];
//--- Smart routing cache
struct LiquidityProvider
{
string name;
double spread;
double depth;
double last_latency;
int priority;
};
LiquidityProvider m_liquidity_providers[];
//--- Helper methods
bool ExecuteMarketOrder(string symbol, ENUM_ORDER_TYPE type, double volume);
bool ExecuteLimitOrder(string symbol, ENUM_ORDER_TYPE type, double volume, double price);
bool ExecuteIcebergSlice(IcebergOrder &order);
bool ExecuteTWAPSlice(TWAPOrder &order);
double CalculateOptimalSliceSize(string symbol, double total_volume);
double GetBestExecutionPrice(string symbol, ENUM_ORDER_TYPE type, double volume);
void UpdateExecutionMetrics(double slippage, ulong latency);
public:
CTradeManagerV71();
~CTradeManagerV71();
//--- Initialization
bool Initialize(const TradeManagerConfigV71 &config);
//--- Standard trade operations
bool OpenPosition(string symbol, ENUM_ORDER_TYPE type, double volume,
double sl = 0, double tp = 0, string comment = "");
bool ClosePosition(ulong ticket);
bool ClosePositionOptimized(ulong ticket);
bool ModifyPosition(ulong ticket, double sl, double tp);
//--- Smart execution methods
bool ExecuteSmartOrder(ExecutionPlan &plan);
bool ExecuteAdaptiveOrder(string symbol, ENUM_ORDER_TYPE type, double volume);
bool ExecuteTWAPOrder(string symbol, ENUM_ORDER_TYPE type, double volume, int minutes);
bool ExecuteVWAPOrder(string symbol, ENUM_ORDER_TYPE type, double volume);
bool ExecuteIcebergOrder(string symbol, ENUM_ORDER_TYPE type,
double total_volume, double display_percent);
//--- Position management
void ManageTrade(ManagedTradeV71 &trade);
void ManageTradeOptimized(ManagedTradeV71 &trade, SymbolDataV71 &symbol_data);
bool ApplyBreakeven(ManagedTradeV71 &trade);
bool ApplyTrailingStop(ManagedTradeV71 &trade);
bool ApplyPartialClose(ManagedTradeV71 &trade);
//--- Advanced operations
bool PartialCloseOptimized(ulong ticket, double volume);
bool AddToPositionOptimized(ManagedTradeV71 &trade, double add_volume);
void ProcessPendingOrders();
void ProcessIcebergOrders();
void ProcessTWAPOrders();
//--- Emergency operations
bool ExecuteEmergencyClose(ulong ticket);
void CloseAllPositions();
void CancelAllPendingOrders();
//--- Execution quality
double GetLastExecutionSlippage() { return m_exec_stats.last_slippage; }
ExecutionStats GetExecutionStats() { return m_exec_stats; }
double CalculateSlippage(string symbol, ENUM_ORDER_TYPE type,
double expected_price, double fill_price);
//--- Setters
void SetSlippageLimit(double pips) { m_config.max_slippage = pips; }
void SetExecutionAlgorithm(ENUM_EXECUTION_ALGO algo) { m_config.execution_algo = algo; }
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CTradeManagerV71::CTradeManagerV71()
{
m_last_execution = 0;
//--- Initialize execution stats
m_exec_stats.last_slippage = 0;
m_exec_stats.last_fill_time = 0;
m_exec_stats.avg_slippage = 0;
m_exec_stats.positive_slippage_rate = 0;
m_exec_stats.total_fills = 0;
m_exec_stats.total_rejected = 0;
m_exec_stats.improvement_amount = 0;
m_exec_stats.vwap_tracking_error = 0;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CTradeManagerV71::~CTradeManagerV71()
{
ArrayFree(m_iceberg_orders);
ArrayFree(m_twap_orders);
ArrayFree(m_liquidity_providers);
}
//+------------------------------------------------------------------+
//| Initialize trade manager |
//+------------------------------------------------------------------+
bool CTradeManagerV71::Initialize(const TradeManagerConfigV71 &config)
{
m_config = config;
//--- Setup trade object
m_trade.SetExpertMagicNumber(m_config.magic_number);
m_trade.SetDeviationInPoints((int)(m_config.max_slippage * 10));
m_trade.SetTypeFilling(ORDER_FILLING_IOC);
//--- Initialize liquidity providers (simplified)
ArrayResize(m_liquidity_providers, 3);
m_liquidity_providers[0].name = "Primary";
m_liquidity_providers[0].priority = 1;
m_liquidity_providers[1].name = "ECN";
m_liquidity_providers[1].priority = 2;
m_liquidity_providers[2].name = "Dark";
m_liquidity_providers[2].priority = 3;
Print("TradeManagerV71 initialized with smart execution");
return true;
}
//+------------------------------------------------------------------+
//| Execute smart order based on plan |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteSmartOrder(ExecutionPlan &plan)
{
bool result = false;
ulong start_time = GetMicrosecondCount();
switch(plan.algorithm)
{
case EXEC_MARKET:
result = ExecuteMarketOrder(plan.symbol, plan.direction, plan.total_volume);
break;
case EXEC_LIMIT:
result = ExecuteLimitOrder(plan.symbol, plan.direction, plan.total_volume, plan.limit_price);
break;
case EXEC_ADAPTIVE:
result = ExecuteAdaptiveOrder(plan.symbol, plan.direction, plan.total_volume);
break;
case EXEC_TWAP:
result = ExecuteTWAPOrder(plan.symbol, plan.direction, plan.total_volume, plan.time_horizon / 60);
break;
case EXEC_VWAP:
result = ExecuteVWAPOrder(plan.symbol, plan.direction, plan.total_volume);
break;
case EXEC_ICEBERG:
{
double display_percent = plan.display_volume / plan.total_volume * 100;
result = ExecuteIcebergOrder(plan.symbol, plan.direction, plan.total_volume, display_percent);
}
break;
case EXEC_SNIPER:
//--- Aggressive fill at best available price
m_trade.SetDeviationInPoints(100); // Wider slippage for aggressive fill
result = ExecuteMarketOrder(plan.symbol, plan.direction, plan.total_volume);
m_trade.SetDeviationInPoints((int)(m_config.max_slippage * 10)); // Reset
break;
}
//--- Update execution metrics
if(result)
{
ulong execution_time = GetMicrosecondCount() - start_time;
m_exec_stats.last_fill_time = execution_time / 1000.0; // Convert to ms
m_exec_stats.total_fills++;
}
else
{
m_exec_stats.total_rejected++;
}
return result;
}
//+------------------------------------------------------------------+
//| Execute adaptive order based on market conditions |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteAdaptiveOrder(string symbol, ENUM_ORDER_TYPE type, double volume)
{
//--- Analyze current market conditions
double spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD);
double avg_spread = spread; // Simplified - would track average
MqlTick tick;
SymbolInfoTick(symbol, tick);
//--- Check liquidity
double bid_volume = tick.volume_real;
//--- Adaptive logic
if(spread > avg_spread * 1.5)
{
//--- Wide spread - use limit order
double price = (type == ORDER_TYPE_BUY) ? tick.ask - SymbolInfoDouble(symbol, SYMBOL_POINT) :
tick.bid + SymbolInfoDouble(symbol, SYMBOL_POINT);
return ExecuteLimitOrder(symbol, type, volume, price);
}
else if(volume > bid_volume * 0.1 && m_config.use_iceberg)
{
//--- Large order relative to liquidity - use iceberg
return ExecuteIcebergOrder(symbol, type, volume, 20); // Show 20%
}
else
{
//--- Normal conditions - market order
return ExecuteMarketOrder(symbol, type, volume);
}
}
//+------------------------------------------------------------------+
//| Execute TWAP order |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteTWAPOrder(string symbol, ENUM_ORDER_TYPE type,
double volume, int minutes)
{
//--- Create TWAP order
TWAPOrder twap;
twap.symbol = symbol;
twap.type = type;
twap.total_volume = volume;
twap.filled_volume = 0;
twap.start_time = TimeCurrent();
twap.end_time = twap.start_time + minutes * 60;
twap.slices = MathMax(5, minutes); // One slice per minute, minimum 5
twap.last_slice_time = 0;
//--- Add to tracking array
int size = ArraySize(m_twap_orders);
ArrayResize(m_twap_orders, size + 1);
m_twap_orders[size] = twap;
//--- Execute first slice immediately
ProcessTWAPOrders();
return true;
}
//+------------------------------------------------------------------+
//| Execute VWAP order |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteVWAPOrder(string symbol, ENUM_ORDER_TYPE type, double volume)
{
//--- Analyze volume profile
double total_volume = 0;
double vwap = 0;
//--- Get recent ticks for volume analysis
MqlTick ticks[];
int copied = CopyTicks(symbol, ticks, COPY_TICKS_TRADE, TimeCurrent() - 3600, 1000);
if(copied > 0)
{
//--- Calculate VWAP
for(int i = 0; i < copied; i++)
{
vwap += ticks[i].last * ticks[i].volume_real;
total_volume += ticks[i].volume_real;
}
if(total_volume > 0)
vwap /= total_volume;
}
//--- Execute based on VWAP
if(vwap > 0)
{
MqlTick current_tick;
SymbolInfoTick(symbol, current_tick);
//--- If price is better than VWAP, execute immediately
if((type == ORDER_TYPE_BUY && current_tick.ask <= vwap) ||
(type == ORDER_TYPE_SELL && current_tick.bid >= vwap))
{
return ExecuteMarketOrder(symbol, type, volume);
}
else
{
//--- Use limit order at VWAP
return ExecuteLimitOrder(symbol, type, volume, vwap);
}
}
//--- Fallback to market order
return ExecuteMarketOrder(symbol, type, volume);
}
//+------------------------------------------------------------------+
//| Execute iceberg order |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteIcebergOrder(string symbol, ENUM_ORDER_TYPE type,
double total_volume, double display_percent)
{
//--- Calculate displayed volume
double displayed = total_volume * display_percent / 100.0;
//--- Normalize to lot step
double lot_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
displayed = MathRound(displayed / lot_step) * lot_step;
//--- Ensure minimum lot
double min_lot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
displayed = MathMax(displayed, min_lot);
//--- Create iceberg order
IcebergOrder iceberg;
iceberg.parent_ticket = 0;
iceberg.symbol = symbol;
iceberg.type = type;
iceberg.total_volume = total_volume;
iceberg.displayed_volume = displayed;
iceberg.filled_volume = 0;
iceberg.price_limit = 0;
iceberg.expiry = TimeCurrent() + 86400; // 24 hours
iceberg.is_active = true;
//--- Add to tracking
int size = ArraySize(m_iceberg_orders);
ArrayResize(m_iceberg_orders, size + 1);
m_iceberg_orders[size] = iceberg;
//--- Execute first slice
return ExecuteIcebergSlice(m_iceberg_orders[size]);
}
//+------------------------------------------------------------------+
//| Execute market order |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteMarketOrder(string symbol, ENUM_ORDER_TYPE type, double volume)
{
//--- Get current price
MqlTick tick;
if(!SymbolInfoTick(symbol, tick))
return false;
double price = (type == ORDER_TYPE_BUY) ? tick.ask : tick.bid;
//--- Execute order
bool result = false;
if(type == ORDER_TYPE_BUY)
result = m_trade.Buy(volume, symbol);
else
result = m_trade.Sell(volume, symbol);
//--- Track execution quality
if(result)
{
//--- Get fill price
if(m_trade.ResultDeal() > 0)
{
double fill_price = m_trade.ResultPrice();
double slippage = CalculateSlippage(symbol, type, price, fill_price);
UpdateExecutionMetrics(slippage, m_trade.ResultRetcodeDescription());
}
}
return result;
}
//+------------------------------------------------------------------+
//| Execute limit order |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteLimitOrder(string symbol, ENUM_ORDER_TYPE type,
double volume, double price)
{
bool result = false;
if(type == ORDER_TYPE_BUY)
result = m_trade.BuyLimit(volume, price, symbol);
else
result = m_trade.SellLimit(volume, price, symbol);
return result;
}
//+------------------------------------------------------------------+
//| Execute iceberg slice |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteIcebergSlice(IcebergOrder &order)
{
//--- Calculate remaining volume
double remaining = order.total_volume - order.filled_volume;
if(remaining <= 0)
{
order.is_active = false;
return true;
}
//--- Determine slice size
double slice_volume = MathMin(order.displayed_volume, remaining);
//--- Execute slice
bool result = ExecuteMarketOrder(order.symbol, order.type, slice_volume);
if(result)
{
order.filled_volume += slice_volume;
//--- Store parent ticket if first slice
if(order.parent_ticket == 0 && m_trade.ResultDeal() > 0)
{
order.parent_ticket = m_trade.ResultDeal();
}
}
return result;
}
//+------------------------------------------------------------------+
//| Process pending iceberg orders |
//+------------------------------------------------------------------+
void CTradeManagerV71::ProcessIcebergOrders()
{
for(int i = 0; i < ArraySize(m_iceberg_orders); i++)
{
if(!m_iceberg_orders[i].is_active)
continue;
//--- Check if current slice is filled
if(m_iceberg_orders[i].parent_ticket > 0)
{
//--- Check position
if(!PositionSelectByTicket(m_iceberg_orders[i].parent_ticket))
{
//--- Position closed, execute next slice
ExecuteIcebergSlice(m_iceberg_orders[i]);
}
}
//--- Check expiry
if(TimeCurrent() > m_iceberg_orders[i].expiry)
{
m_iceberg_orders[i].is_active = false;
}
}
}
//+------------------------------------------------------------------+
//| Process TWAP orders |
//+------------------------------------------------------------------+
void CTradeManagerV71::ProcessTWAPOrders()
{
datetime current_time = TimeCurrent();
for(int i = 0; i < ArraySize(m_twap_orders); i++)
{
TWAPOrder &twap = m_twap_orders[i];
//--- Check if order is complete
if(twap.filled_volume >= twap.total_volume || current_time > twap.end_time)
continue;
//--- Calculate time for next slice
double time_elapsed = current_time - twap.start_time;
double total_time = twap.end_time - twap.start_time;
double progress = time_elapsed / total_time;
//--- Calculate expected filled volume
double expected_filled = twap.total_volume * progress;
//--- Execute slice if behind schedule
if(twap.filled_volume < expected_filled)
{
double slice_size = (expected_filled - twap.filled_volume);
//--- Normalize
double lot_step = SymbolInfoDouble(twap.symbol, SYMBOL_VOLUME_STEP);
slice_size = MathRound(slice_size / lot_step) * lot_step;
//--- Ensure minimum
double min_lot = SymbolInfoDouble(twap.symbol, SYMBOL_VOLUME_MIN);
slice_size = MathMax(slice_size, min_lot);
//--- Execute
if(ExecuteMarketOrder(twap.symbol, twap.type, slice_size))
{
twap.filled_volume += slice_size;
twap.last_slice_time = current_time;
}
}
}
}
//+------------------------------------------------------------------+
//| Manage trade with optimized logic |
//+------------------------------------------------------------------+
void CTradeManagerV71::ManageTradeOptimized(ManagedTradeV71 &trade, SymbolDataV71 &symbol_data)
{
//--- Quick checks using cached data
if(!trade.is_managed || trade.ticket == 0)
return;
//--- Get current price from last tick
double current_price = (trade.type == POSITION_TYPE_BUY) ?
SymbolInfoDouble(trade.symbol, SYMBOL_BID) :
SymbolInfoDouble(trade.symbol, SYMBOL_ASK);
//--- Calculate current profit in points
double profit_points = (trade.type == POSITION_TYPE_BUY) ?
(current_price - trade.open_price) :
(trade.open_price - current_price);
profit_points /= symbol_data.point;
//--- Breakeven management
if(!trade.be_activated && profit_points >= m_config.be_trigger_atr * 100)
{
double new_sl = (trade.type == POSITION_TYPE_BUY) ?
trade.open_price + m_config.be_offset_atr * symbol_data.volatility_5m :
trade.open_price - m_config.be_offset_atr * symbol_data.volatility_5m;
if((trade.type == POSITION_TYPE_BUY && new_sl > trade.sl) ||
(trade.type == POSITION_TYPE_SELL && new_sl < trade.sl))
{
if(m_trade.PositionModify(trade.ticket, new_sl, trade.tp))
{
trade.sl = new_sl;
trade.be_activated = true;
}
}
}
//--- Trailing stop
if(trade.be_activated && profit_points >= m_config.trail_trigger_atr * 100)
{
double trail_distance = m_config.trail_distance_atr * symbol_data.volatility_5m;
double new_sl = (trade.type == POSITION_TYPE_BUY) ?
current_price - trail_distance :
current_price + trail_distance;
if((trade.type == POSITION_TYPE_BUY && new_sl > trade.sl) ||
(trade.type == POSITION_TYPE_SELL && new_sl < trade.sl))
{
if(m_trade.PositionModify(trade.ticket, new_sl, trade.tp))
{
trade.sl = new_sl;
trade.trailing_activated = true;
}
}
}
//--- Partial close with smart execution
if(m_config.use_partial_close && trade.partial_count == 0 &&
profit_points >= m_config.partial_close_trigger * 100)
{
double close_volume = trade.volume * m_config.partial_close_percent / 100.0;
//--- Use iceberg for partial close if large
if(close_volume > symbol_data.min_lot * 10 && m_config.use_iceberg)
{
ExecuteIcebergOrder(trade.symbol,
(trade.type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY,
close_volume, 30); // Show 30%
}
else
{
PartialCloseOptimized(trade.ticket, close_volume);
}
trade.partial_count++;
}
}
//+------------------------------------------------------------------+
//| Close position with optimization |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ClosePositionOptimized(ulong ticket)
{
if(!PositionSelectByTicket(ticket))
return false;
string symbol = PositionGetString(POSITION_SYMBOL);
double volume = PositionGetDouble(POSITION_VOLUME);
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
//--- Use smart execution for large positions
if(volume > SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN) * 20 && m_config.use_smart_routing)
{
ExecutionPlan plan;
plan.symbol = symbol;
plan.direction = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
plan.total_volume = volume;
plan.algorithm = m_config.execution_algo;
plan.urgency = 0.8; // High urgency for closes
return ExecuteSmartOrder(plan);
}
//--- Standard close
return m_trade.PositionClose(ticket);
}
//+------------------------------------------------------------------+
//| Partial close with optimization |
//+------------------------------------------------------------------+
bool CTradeManagerV71::PartialCloseOptimized(ulong ticket, double volume)
{
if(!PositionSelectByTicket(ticket))
return false;
//--- Normalize volume
string symbol = PositionGetString(POSITION_SYMBOL);
double lot_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
volume = MathRound(volume / lot_step) * lot_step;
//--- Ensure minimum
double min_lot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
volume = MathMax(volume, min_lot);
//--- Execute partial close
return m_trade.PositionClosePartial(ticket, volume);
}
//+------------------------------------------------------------------+
//| Add to position with smart execution |
//+------------------------------------------------------------------+
bool CTradeManagerV71::AddToPositionOptimized(ManagedTradeV71 &trade, double add_volume)
{
//--- Create execution plan
ExecutionPlan plan;
plan.symbol = trade.symbol;
plan.direction = (trade.type == POSITION_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
plan.total_volume = add_volume;
plan.algorithm = m_config.execution_algo;
plan.urgency = 0.5; // Medium urgency for additions
return ExecuteSmartOrder(plan);
}
//+------------------------------------------------------------------+
//| Calculate slippage |
//+------------------------------------------------------------------+
double CTradeManagerV71::CalculateSlippage(string symbol, ENUM_ORDER_TYPE type,
double expected_price, double fill_price)
{
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
if(point == 0) return 0;
double slippage = 0;
if(type == ORDER_TYPE_BUY || type == ORDER_TYPE_BUY_LIMIT)
slippage = (fill_price - expected_price) / point;
else
slippage = (expected_price - fill_price) / point;
return slippage / 10.0; // Convert to pips
}
//+------------------------------------------------------------------+
//| Update execution metrics |
//+------------------------------------------------------------------+
void CTradeManagerV71::UpdateExecutionMetrics(double slippage, ulong latency)
{
m_exec_stats.last_slippage = slippage;
//--- Update average slippage
m_exec_stats.avg_slippage = (m_exec_stats.avg_slippage * m_exec_stats.total_fills + slippage) /
(m_exec_stats.total_fills + 1);
//--- Track positive slippage
if(slippage < 0) // Negative slippage is positive for trader
{
m_exec_stats.positive_slippage_rate =
(m_exec_stats.positive_slippage_rate * m_exec_stats.total_fills + 1) /
(m_exec_stats.total_fills + 1);
m_exec_stats.improvement_amount += MathAbs(slippage);
}
else
{
m_exec_stats.positive_slippage_rate =
(m_exec_stats.positive_slippage_rate * m_exec_stats.total_fills) /
(m_exec_stats.total_fills + 1);
}
}
//+------------------------------------------------------------------+
//| Execute emergency close |
//+------------------------------------------------------------------+
bool CTradeManagerV71::ExecuteEmergencyClose(ulong ticket)
{
//--- Set maximum slippage for emergency
int old_deviation = m_trade.GetDeviationInPoints();
m_trade.SetDeviationInPoints(1000); // 100 pips emergency slippage
bool result = m_trade.PositionClose(ticket);
//--- Restore normal slippage
m_trade.SetDeviationInPoints(old_deviation);
return result;
}
#endif // TRADE_MANAGER_V71_MQH