mql5/Shared Projects/ERMT-ML/Modules-ML8x/TradeManager_v71.mqh
darashikoh 0fb1bd1b0a 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

766 lines
No EOL
27 KiB
MQL5

//+------------------------------------------------------------------+
//| 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