766 lines
27 KiB
MQL5
766 lines
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
|