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