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
1461 lines
No EOL
51 KiB
MQL5
1461 lines
No EOL
51 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| ERMT 8.0 - Institutional Grade |
|
|
//| External Risk Management Tool v7.1 |
|
|
//| Ultra-Low Latency & ML-Enhanced |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Institutional Risk Management System v8.0"
|
|
#property version "7.1"
|
|
#property strict
|
|
#property description "Next-gen modular risk system with ML and HFT optimizations"
|
|
|
|
//--- Include system modules
|
|
#include <Trade/Trade.mqh>
|
|
#include <Math/Stat/Math.mqh>
|
|
#include <Arrays/ArrayObj.mqh>
|
|
#include "Modules/RiskManager_v71.mqh"
|
|
#include "Modules/TradeManager_v71.mqh"
|
|
#include "Modules/EntrySystem_v71.mqh"
|
|
#include "Modules/TechnicalAnalysis_v71.mqh"
|
|
#include "Modules/Dashboard_v71.mqh"
|
|
#include "Modules/Utilities_v71.mqh"
|
|
#include "Modules/MultiTradeReporter_v71.mqh"
|
|
#include "Modules/MLPredictor.mqh"
|
|
#include "Modules/OrderFlowAnalyzer.mqh"
|
|
#include "Modules/ExecutionOptimizer.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| PERFORMANCE OPTIMIZATIONS |
|
|
//+------------------------------------------------------------------+
|
|
#define CACHE_SIZE 1024 // Tick cache size
|
|
#define MAX_SYMBOLS 50 // Maximum monitored symbols
|
|
#define CORRELATION_WINDOW 100 // Bars for correlation calc
|
|
#define ML_LOOKBACK 500 // ML training window
|
|
#define TICK_BUFFER_SIZE 10000 // High-frequency tick buffer
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INPUT PARAMETERS - INSTITUTIONAL CONFIGURATION |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//--- System Configuration
|
|
input group "=== SYSTEM CONFIGURATION ==="
|
|
input bool SystemEnabled = true; // Master Switch
|
|
input int TradingMagic = 12345; // EA Magic Number
|
|
input bool ManageExternalTrades = true; // Manage External Trades
|
|
input int MagicNumberFilter = 0; // External Magic Filter
|
|
input ENUM_LOG_LEVEL LogLevel = LOG_ERROR; // Logging Level (Optimized)
|
|
input bool UltraLowLatencyMode = true; // Ultra-Low Latency Mode
|
|
input int TickProcessingInterval = 1; // Tick Processing Interval (ms)
|
|
|
|
//--- Entry System Parameters
|
|
input group "=== ENTRY SYSTEM ==="
|
|
input ENUM_ENTRY_MODE EntryMode = ENTRY_ML_ENHANCED; // Entry System Type
|
|
input bool EnableMultipleEntries = true; // Allow Pyramiding
|
|
input int MaxPositions = 10; // Maximum Positions
|
|
input double MinTimeBetweenTrades = 5; // Min Seconds Between Trades
|
|
input bool UseMLPrediction = true; // Use ML Entry Prediction
|
|
input double MLConfidenceThreshold = 0.75; // ML Confidence Threshold
|
|
|
|
//--- Risk Management Parameters
|
|
input group "=== ADVANCED RISK MANAGEMENT ==="
|
|
input ENUM_POSITION_SIZING SizingMode = PS_KELLY_ML; // Position Sizing Mode
|
|
input double BaseRiskPercent = 1.0; // Base Risk Per Trade %
|
|
input double MaxPortfolioRisk = 6.0; // Max Portfolio Risk %
|
|
input double DailyVaRLimit = 3.0; // Daily VaR Limit %
|
|
input double CVaRMultiplier = 1.5; // CVaR Risk Multiplier
|
|
input bool UsePortfolioOptimization = true; // Portfolio Optimization
|
|
input double MaxCorrelationExposure = 0.7; // Max Correlation Exposure
|
|
|
|
//--- Execution Parameters
|
|
input group "=== EXECUTION OPTIMIZATION ==="
|
|
input bool UseSmartRouting = true; // Smart Order Routing
|
|
input ENUM_EXECUTION_ALGO ExecutionAlgo = EXEC_ADAPTIVE; // Execution Algorithm
|
|
input double MaxSlippagePips = 2.0; // Max Acceptable Slippage
|
|
input bool UseIcebergOrders = true; // Use Iceberg Orders
|
|
input double IcebergShowPercent = 20.0; // Iceberg Display %
|
|
input int ExecutionRetries = 3; // Execution Retry Attempts
|
|
|
|
//--- ML Configuration
|
|
input group "=== MACHINE LEARNING ==="
|
|
input bool EnableMLAdaptation = true; // Enable ML Adaptation
|
|
input int MLUpdateFrequency = 3600; // ML Update Frequency (sec)
|
|
input double MLLearningRate = 0.01; // ML Learning Rate
|
|
input int MLMinTrainingSize = 100; // Min Training Samples
|
|
input bool UseDeepLearning = true; // Use Deep Neural Network
|
|
|
|
//--- Order Flow Analysis
|
|
input group "=== ORDER FLOW ANALYSIS ==="
|
|
input bool EnableOrderFlow = true; // Enable Order Flow Analysis
|
|
input int VolumeProfilePeriod = 20; // Volume Profile Period
|
|
input double LiquidityThreshold = 1000000; // Liquidity Threshold ($)
|
|
input bool DetectInstitutionalFlow = true; // Detect Large Orders
|
|
input double BlockTradeThreshold = 100000; // Block Trade Threshold ($)
|
|
|
|
//--- Performance Monitoring
|
|
input group "=== PERFORMANCE MONITORING ==="
|
|
input bool EnableRealtimeAnalytics = true; // Real-time Analytics
|
|
input int PerformanceUpdateMs = 100; // Performance Update (ms)
|
|
input bool TrackExecutionQuality = true; // Track Execution Quality
|
|
input bool GenerateInstitutionalReports = true; // Institutional Reports
|
|
input string FIXGatewayID = ""; // FIX Gateway ID
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GLOBAL VARIABLES - OPTIMIZED STRUCTURES |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//--- Module instances
|
|
CRiskManagerV71* RiskMgr;
|
|
CTradeManagerV71* TradeMgr;
|
|
CEntrySystemV71* EntrySys;
|
|
CTechnicalAnalysisV71* TechAnalysis;
|
|
CDashboardV71* Dashboard;
|
|
CUtilitiesV71* Utils;
|
|
CMultiTradeReporterV71* Reporter;
|
|
CMLPredictor* MLEngine;
|
|
COrderFlowAnalyzer* OrderFlow;
|
|
CExecutionOptimizer* ExecOptimizer;
|
|
|
|
//--- System state with atomic operations
|
|
struct SystemStateV71
|
|
{
|
|
bool is_active;
|
|
int magic_number;
|
|
double start_balance;
|
|
double peak_balance;
|
|
datetime session_start;
|
|
int tick_count;
|
|
long last_tick_time;
|
|
double current_var;
|
|
double current_cvar;
|
|
double portfolio_beta;
|
|
double sharpe_real_time;
|
|
CorrelationMatrix correlation_matrix;
|
|
};
|
|
|
|
SystemStateV71 g_SystemState;
|
|
PerformanceMetricsV71 g_Performance;
|
|
MarketConditionsV71 g_MarketConditions;
|
|
|
|
//--- Trade tracking with lock-free structures
|
|
ManagedTradeV71 g_ManagedTrades[];
|
|
int g_TotalTrades = 0;
|
|
ulong g_TradeVersion = 0; // Version for lock-free updates
|
|
|
|
//--- High-performance tick cache
|
|
struct TickCache
|
|
{
|
|
MqlTick ticks[TICK_BUFFER_SIZE];
|
|
int write_index;
|
|
int read_index;
|
|
int count;
|
|
ulong last_update;
|
|
};
|
|
|
|
TickCache g_TickCache[];
|
|
int g_CacheCount = 0;
|
|
|
|
//--- Symbol monitoring with pre-calculated values
|
|
struct SymbolDataV71
|
|
{
|
|
string symbol;
|
|
double tick_value;
|
|
double tick_size;
|
|
double min_lot;
|
|
double max_lot;
|
|
double lot_step;
|
|
double contract_size;
|
|
int digits;
|
|
double point;
|
|
double spread_average;
|
|
double volatility_1m;
|
|
double volatility_5m;
|
|
double liquidity_score;
|
|
datetime last_update;
|
|
bool is_active;
|
|
};
|
|
|
|
SymbolDataV71 g_SymbolData[MAX_SYMBOLS];
|
|
int g_ActiveSymbols = 0;
|
|
|
|
//--- ML prediction cache
|
|
struct MLPredictionCache
|
|
{
|
|
string symbol;
|
|
ENUM_ORDER_TYPE predicted_direction;
|
|
double confidence;
|
|
double expected_return;
|
|
double predicted_volatility;
|
|
datetime prediction_time;
|
|
bool is_valid;
|
|
};
|
|
|
|
MLPredictionCache g_MLCache[MAX_SYMBOLS];
|
|
|
|
//--- Execution quality metrics
|
|
struct ExecutionMetrics
|
|
{
|
|
double avg_slippage;
|
|
double positive_slippage_rate;
|
|
double avg_fill_time_ms;
|
|
int rejected_orders;
|
|
double improvement_rate;
|
|
double vwap_performance;
|
|
};
|
|
|
|
ExecutionMetrics g_ExecMetrics;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EXPERT INITIALIZATION - ULTRA OPTIMIZED |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Start performance timer
|
|
ulong init_start = GetMicrosecondCount();
|
|
|
|
//--- Initialize system state
|
|
g_SystemState.is_active = SystemEnabled;
|
|
g_SystemState.magic_number = TradingMagic;
|
|
g_SystemState.start_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
g_SystemState.peak_balance = g_SystemState.start_balance;
|
|
g_SystemState.session_start = TimeCurrent();
|
|
g_SystemState.tick_count = 0;
|
|
g_SystemState.last_tick_time = 0;
|
|
|
|
//--- Create module instances with optimized memory allocation
|
|
RiskMgr = new CRiskManagerV71();
|
|
TradeMgr = new CTradeManagerV71();
|
|
EntrySys = new CEntrySystemV71();
|
|
TechAnalysis = new CTechnicalAnalysisV71();
|
|
Dashboard = new CDashboardV71();
|
|
Utils = new CUtilitiesV71();
|
|
Reporter = new CMultiTradeReporterV71();
|
|
|
|
//--- Initialize ML and advanced modules
|
|
if(UseMLPrediction || EnableMLAdaptation)
|
|
{
|
|
MLEngine = new CMLPredictor();
|
|
if(!MLEngine.Initialize(ML_LOOKBACK, MLMinTrainingSize, UseDeepLearning))
|
|
{
|
|
Print("Failed to initialize ML Engine");
|
|
return(INIT_FAILED);
|
|
}
|
|
}
|
|
|
|
if(EnableOrderFlow)
|
|
{
|
|
OrderFlow = new COrderFlowAnalyzer();
|
|
if(!OrderFlow.Initialize(VolumeProfilePeriod, LiquidityThreshold))
|
|
{
|
|
Print("Failed to initialize Order Flow Analyzer");
|
|
return(INIT_FAILED);
|
|
}
|
|
}
|
|
|
|
if(UseSmartRouting)
|
|
{
|
|
ExecOptimizer = new CExecutionOptimizer();
|
|
if(!ExecOptimizer.Initialize(ExecutionAlgo, MaxSlippagePips))
|
|
{
|
|
Print("Failed to initialize Execution Optimizer");
|
|
return(INIT_FAILED);
|
|
}
|
|
}
|
|
|
|
//--- Initialize all modules
|
|
if(!InitializeModulesV71())
|
|
{
|
|
Print("Failed to initialize core modules");
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
//--- Pre-calculate symbol data for all monitored symbols
|
|
if(!InitializeSymbolData())
|
|
{
|
|
Print("Failed to initialize symbol data cache");
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
//--- Initialize tick caches for active symbols
|
|
if(UltraLowLatencyMode)
|
|
{
|
|
ArrayResize(g_TickCache, g_ActiveSymbols);
|
|
for(int i = 0; i < g_ActiveSymbols; i++)
|
|
{
|
|
g_TickCache[i].write_index = 0;
|
|
g_TickCache[i].read_index = 0;
|
|
g_TickCache[i].count = 0;
|
|
g_TickCache[i].last_update = 0;
|
|
}
|
|
}
|
|
|
|
//--- Load existing positions with optimized scanning
|
|
LoadExistingPositionsOptimized();
|
|
|
|
//--- Initialize correlation matrix
|
|
if(UsePortfolioOptimization)
|
|
{
|
|
InitializeCorrelationMatrix();
|
|
}
|
|
|
|
//--- Create dashboard with institutional metrics
|
|
if(ShowDashboard)
|
|
{
|
|
Dashboard.CreateInstitutional(DashboardX, DashboardY);
|
|
Dashboard.UpdateInstitutional(g_Performance, g_SystemState, g_ExecMetrics);
|
|
}
|
|
|
|
//--- Set high-frequency timer if enabled
|
|
if(UltraLowLatencyMode)
|
|
{
|
|
EventSetMillisecondTimer(TickProcessingInterval);
|
|
}
|
|
else
|
|
{
|
|
EventSetTimer(1); // Standard 1-second timer
|
|
}
|
|
|
|
//--- Log initialization metrics
|
|
ulong init_time = GetMicrosecondCount() - init_start;
|
|
Utils.Log(LOG_INFO, StringFormat("ERMT 7.1 initialized in %.2f ms. Symbols: %d, ML: %s, OrderFlow: %s",
|
|
init_time / 1000.0, g_ActiveSymbols,
|
|
UseMLPrediction ? "ON" : "OFF",
|
|
EnableOrderFlow ? "ON" : "OFF"));
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EXPERT DEINITIALIZATION |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//--- Kill timers
|
|
EventKillTimer();
|
|
|
|
//--- Save ML model if enabled
|
|
if(MLEngine != NULL && EnableMLAdaptation)
|
|
{
|
|
MLEngine.SaveModel("ERMT71_ML_Model.bin");
|
|
}
|
|
|
|
//--- Generate final institutional report
|
|
if(Reporter != NULL && GenerateInstitutionalReports)
|
|
{
|
|
Reporter.GenerateInstitutionalReport(g_Performance, g_ManagedTrades, g_ExecMetrics);
|
|
}
|
|
|
|
//--- Cleanup modules
|
|
delete MLEngine;
|
|
delete OrderFlow;
|
|
delete ExecOptimizer;
|
|
delete Reporter;
|
|
delete RiskMgr;
|
|
delete TradeMgr;
|
|
delete EntrySys;
|
|
delete TechAnalysis;
|
|
delete Dashboard;
|
|
delete Utils;
|
|
|
|
Print("ERMT 7.1 shutdown complete: ", GetUninitReasonText(reason));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EXPERT TICK FUNCTION - ULTRA LOW LATENCY |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//--- Ultra-fast system check
|
|
if(!g_SystemState.is_active || !SystemEnabled) return;
|
|
|
|
//--- Get current microsecond timestamp
|
|
ulong tick_start = GetMicrosecondCount();
|
|
|
|
//--- Update tick counter
|
|
g_SystemState.tick_count++;
|
|
|
|
//--- Process current symbol tick with minimal latency
|
|
MqlTick tick;
|
|
if(!SymbolInfoTick(_Symbol, tick)) return;
|
|
|
|
//--- Cache tick if in ultra-low latency mode
|
|
if(UltraLowLatencyMode)
|
|
{
|
|
CacheTickData(_Symbol, tick);
|
|
}
|
|
|
|
//--- Fast order flow analysis
|
|
if(EnableOrderFlow && OrderFlow != NULL)
|
|
{
|
|
OrderFlow.ProcessTick(_Symbol, tick);
|
|
|
|
//--- Check for institutional flow signals
|
|
if(DetectInstitutionalFlow)
|
|
{
|
|
double flow_imbalance = OrderFlow.GetFlowImbalance(_Symbol);
|
|
if(MathAbs(flow_imbalance) > 0.7)
|
|
{
|
|
g_MarketConditions.institutional_flow = flow_imbalance;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- Update ML predictions if needed
|
|
if(UseMLPrediction && MLEngine != NULL)
|
|
{
|
|
UpdateMLPredictions(_Symbol);
|
|
}
|
|
|
|
//--- Quick position check using cached data
|
|
int symbol_index = GetSymbolIndex(_Symbol);
|
|
if(symbol_index >= 0)
|
|
{
|
|
QuickPositionUpdate(symbol_index);
|
|
}
|
|
|
|
//--- Process entry signals with ML enhancement
|
|
if(EntryMode != ENTRY_DISABLED && EntrySys != NULL)
|
|
{
|
|
ProcessEntrySignalsOptimized();
|
|
}
|
|
|
|
//--- Risk monitoring with VaR/CVaR
|
|
if(RiskMgr != NULL)
|
|
{
|
|
MonitorPortfolioRiskRealtime();
|
|
}
|
|
|
|
//--- Update execution metrics
|
|
if(TrackExecutionQuality)
|
|
{
|
|
UpdateExecutionMetrics();
|
|
}
|
|
|
|
//--- Record tick processing time
|
|
g_SystemState.last_tick_time = GetMicrosecondCount() - tick_start;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| TIMER FUNCTION - HIGH FREQUENCY PROCESSING |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
//--- Process all cached ticks
|
|
if(UltraLowLatencyMode)
|
|
{
|
|
ProcessCachedTicks();
|
|
}
|
|
|
|
//--- Update all positions
|
|
UpdateAllPositionsOptimized();
|
|
|
|
//--- Portfolio rebalancing check
|
|
if(UsePortfolioOptimization && g_SystemState.tick_count % 100 == 0)
|
|
{
|
|
OptimizePortfolioWeights();
|
|
}
|
|
|
|
//--- ML model update
|
|
if(EnableMLAdaptation && MLEngine != NULL)
|
|
{
|
|
if(TimeCurrent() - MLEngine.GetLastUpdateTime() > MLUpdateFrequency)
|
|
{
|
|
MLEngine.UpdateModel(g_ManagedTrades);
|
|
}
|
|
}
|
|
|
|
//--- Update institutional dashboard
|
|
if(ShowDashboard && Dashboard != NULL)
|
|
{
|
|
Dashboard.UpdateInstitutional(g_Performance, g_SystemState, g_ExecMetrics);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| MILLISECOND TIMER - ULTRA LOW LATENCY |
|
|
//+------------------------------------------------------------------+
|
|
void OnMillisecondTimer()
|
|
{
|
|
if(!UltraLowLatencyMode) return;
|
|
|
|
//--- Process high-priority tasks
|
|
ProcessHighPriorityTasks();
|
|
|
|
//--- Update real-time analytics
|
|
if(EnableRealtimeAnalytics && g_SystemState.tick_count % (PerformanceUpdateMs / TickProcessingInterval) == 0)
|
|
{
|
|
UpdateRealtimeAnalytics();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INITIALIZE MODULES V7.1 |
|
|
//+------------------------------------------------------------------+
|
|
bool InitializeModulesV71()
|
|
{
|
|
//--- Risk Manager with advanced features
|
|
RiskManagerConfigV71 risk_config;
|
|
risk_config.sizing_mode = SizingMode;
|
|
risk_config.risk_percent = BaseRiskPercent;
|
|
risk_config.max_risk = MaxPortfolioRisk;
|
|
risk_config.daily_var_limit = DailyVaRLimit;
|
|
risk_config.cvar_multiplier = CVaRMultiplier;
|
|
risk_config.use_portfolio_optimization = UsePortfolioOptimization;
|
|
risk_config.max_correlation = MaxCorrelationExposure;
|
|
|
|
if(!RiskMgr.Initialize(risk_config))
|
|
return false;
|
|
|
|
//--- Trade Manager with execution optimization
|
|
TradeManagerConfigV71 trade_config;
|
|
trade_config.magic_number = TradingMagic;
|
|
trade_config.use_smart_routing = UseSmartRouting;
|
|
trade_config.execution_algo = ExecutionAlgo;
|
|
trade_config.max_slippage = MaxSlippagePips;
|
|
trade_config.use_iceberg = UseIcebergOrders;
|
|
trade_config.iceberg_percent = IcebergShowPercent;
|
|
trade_config.retry_attempts = ExecutionRetries;
|
|
|
|
if(!TradeMgr.Initialize(trade_config))
|
|
return false;
|
|
|
|
//--- Entry System with ML
|
|
EntrySystemConfigV71 entry_config;
|
|
entry_config.mode = EntryMode;
|
|
entry_config.use_ml = UseMLPrediction;
|
|
entry_config.ml_threshold = MLConfidenceThreshold;
|
|
entry_config.max_positions = MaxPositions;
|
|
entry_config.min_time_between = MinTimeBetweenTrades;
|
|
|
|
if(!EntrySys.Initialize(entry_config))
|
|
return false;
|
|
|
|
//--- Technical Analysis enhanced
|
|
if(!TechAnalysis.InitializeEnhanced(CORRELATION_WINDOW))
|
|
return false;
|
|
|
|
//--- Utilities with performance optimization
|
|
if(!Utils.InitializeOptimized(LogLevel, UltraLowLatencyMode))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INITIALIZE SYMBOL DATA CACHE |
|
|
//+------------------------------------------------------------------+
|
|
bool InitializeSymbolData()
|
|
{
|
|
g_ActiveSymbols = 0;
|
|
|
|
//--- Get all symbols in Market Watch
|
|
int total_symbols = SymbolsTotal(true);
|
|
|
|
for(int i = 0; i < total_symbols && g_ActiveSymbols < MAX_SYMBOLS; i++)
|
|
{
|
|
string symbol = SymbolName(i, true);
|
|
|
|
//--- Skip if not selected in Market Watch
|
|
if(!SymbolInfoInteger(symbol, SYMBOL_SELECT))
|
|
continue;
|
|
|
|
//--- Cache symbol data
|
|
g_SymbolData[g_ActiveSymbols].symbol = symbol;
|
|
g_SymbolData[g_ActiveSymbols].tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
g_SymbolData[g_ActiveSymbols].tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
g_SymbolData[g_ActiveSymbols].min_lot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
|
g_SymbolData[g_ActiveSymbols].max_lot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
|
g_SymbolData[g_ActiveSymbols].lot_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
|
g_SymbolData[g_ActiveSymbols].contract_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
|
|
g_SymbolData[g_ActiveSymbols].digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
|
g_SymbolData[g_ActiveSymbols].point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
|
g_SymbolData[g_ActiveSymbols].is_active = true;
|
|
g_SymbolData[g_ActiveSymbols].last_update = TimeCurrent();
|
|
|
|
//--- Calculate initial volatility
|
|
double atr = TechAnalysis.GetSymbolATR(symbol, 14);
|
|
g_SymbolData[g_ActiveSymbols].volatility_5m = atr;
|
|
|
|
g_ActiveSymbols++;
|
|
}
|
|
|
|
Print("Initialized ", g_ActiveSymbols, " symbols in cache");
|
|
return g_ActiveSymbols > 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CACHE TICK DATA FOR BATCH PROCESSING |
|
|
//+------------------------------------------------------------------+
|
|
void CacheTickData(string symbol, MqlTick &tick)
|
|
{
|
|
int index = GetSymbolIndex(symbol);
|
|
if(index < 0 || index >= ArraySize(g_TickCache))
|
|
return;
|
|
|
|
//--- Add tick to circular buffer
|
|
int write_pos = g_TickCache[index].write_index;
|
|
g_TickCache[index].ticks[write_pos] = tick;
|
|
|
|
//--- Update indices
|
|
g_TickCache[index].write_index = (write_pos + 1) % TICK_BUFFER_SIZE;
|
|
if(g_TickCache[index].count < TICK_BUFFER_SIZE)
|
|
g_TickCache[index].count++;
|
|
else
|
|
g_TickCache[index].read_index = (g_TickCache[index].read_index + 1) % TICK_BUFFER_SIZE;
|
|
|
|
g_TickCache[index].last_update = tick.time_msc;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| PROCESS CACHED TICKS IN BATCH |
|
|
//+------------------------------------------------------------------+
|
|
void ProcessCachedTicks()
|
|
{
|
|
for(int i = 0; i < g_ActiveSymbols; i++)
|
|
{
|
|
if(g_TickCache[i].count == 0)
|
|
continue;
|
|
|
|
//--- Process available ticks
|
|
while(g_TickCache[i].read_index != g_TickCache[i].write_index)
|
|
{
|
|
MqlTick tick = g_TickCache[i].ticks[g_TickCache[i].read_index];
|
|
|
|
//--- Update spread tracking
|
|
double spread = (tick.ask - tick.bid) / g_SymbolData[i].point;
|
|
g_SymbolData[i].spread_average = 0.9 * g_SymbolData[i].spread_average + 0.1 * spread;
|
|
|
|
//--- Update volatility estimate
|
|
static double last_price[MAX_SYMBOLS] = {0};
|
|
if(last_price[i] > 0)
|
|
{
|
|
double price_change = MathAbs(tick.bid - last_price[i]);
|
|
g_SymbolData[i].volatility_1m = 0.95 * g_SymbolData[i].volatility_1m + 0.05 * price_change;
|
|
}
|
|
last_price[i] = tick.bid;
|
|
|
|
//--- Move to next tick
|
|
g_TickCache[i].read_index = (g_TickCache[i].read_index + 1) % TICK_BUFFER_SIZE;
|
|
g_TickCache[i].count--;
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UPDATE ML PREDICTIONS |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateMLPredictions(string symbol)
|
|
{
|
|
int index = GetSymbolIndex(symbol);
|
|
if(index < 0 || MLEngine == NULL)
|
|
return;
|
|
|
|
//--- Check if prediction is still valid
|
|
if(g_MLCache[index].is_valid &&
|
|
TimeCurrent() - g_MLCache[index].prediction_time < 60) // 1-minute cache
|
|
return;
|
|
|
|
//--- Get new prediction
|
|
MLPrediction prediction = MLEngine.Predict(symbol);
|
|
|
|
//--- Update cache
|
|
g_MLCache[index].symbol = symbol;
|
|
g_MLCache[index].predicted_direction = prediction.direction;
|
|
g_MLCache[index].confidence = prediction.confidence;
|
|
g_MLCache[index].expected_return = prediction.expected_return;
|
|
g_MLCache[index].predicted_volatility = prediction.volatility;
|
|
g_MLCache[index].prediction_time = TimeCurrent();
|
|
g_MLCache[index].is_valid = true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| PROCESS ENTRY SIGNALS WITH ML |
|
|
//+------------------------------------------------------------------+
|
|
void ProcessEntrySignalsOptimized()
|
|
{
|
|
//--- Check position limits
|
|
if(ArraySize(g_ManagedTrades) >= MaxPositions)
|
|
return;
|
|
|
|
//--- Check time between trades
|
|
static datetime last_trade_time = 0;
|
|
if(TimeCurrent() - last_trade_time < MinTimeBetweenTrades)
|
|
return;
|
|
|
|
//--- Get base signal
|
|
EntrySignalV71 signal = EntrySys.CheckSignalEnhanced(_Symbol, g_MarketConditions);
|
|
|
|
//--- Enhance with ML if enabled
|
|
if(UseMLPrediction && signal.strength > 0)
|
|
{
|
|
int index = GetSymbolIndex(_Symbol);
|
|
if(index >= 0 && g_MLCache[index].is_valid)
|
|
{
|
|
//--- Combine signals
|
|
if(g_MLCache[index].confidence >= MLConfidenceThreshold)
|
|
{
|
|
signal.strength *= (1.0 + g_MLCache[index].confidence);
|
|
signal.expected_return = g_MLCache[index].expected_return;
|
|
signal.ml_enhanced = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- Validate with order flow
|
|
if(EnableOrderFlow && OrderFlow != NULL)
|
|
{
|
|
double flow_signal = OrderFlow.GetSignalStrength(_Symbol);
|
|
signal.strength *= (1.0 + flow_signal * 0.5);
|
|
}
|
|
|
|
//--- Execute if signal is strong enough
|
|
if(signal.strength >= EntrySys.GetMinSignalStrength())
|
|
{
|
|
ExecuteOptimizedEntry(signal);
|
|
last_trade_time = TimeCurrent();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EXECUTE OPTIMIZED ENTRY |
|
|
//+------------------------------------------------------------------+
|
|
void ExecuteOptimizedEntry(EntrySignalV71 &signal)
|
|
{
|
|
//--- Calculate position size with portfolio optimization
|
|
double position_size = RiskMgr.CalculateOptimalSize(
|
|
signal.symbol,
|
|
signal.stop_loss,
|
|
signal.expected_return,
|
|
g_SystemState.correlation_matrix
|
|
);
|
|
|
|
//--- Apply execution optimization
|
|
if(UseSmartRouting && ExecOptimizer != NULL)
|
|
{
|
|
ExecutionPlan plan = ExecOptimizer.CreatePlan(
|
|
signal.symbol,
|
|
signal.direction,
|
|
position_size,
|
|
signal.entry_price
|
|
);
|
|
|
|
//--- Execute with smart routing
|
|
bool success = TradeMgr.ExecuteSmartOrder(plan);
|
|
|
|
//--- Track execution quality
|
|
if(success && TrackExecutionQuality)
|
|
{
|
|
double slippage = TradeMgr.GetLastExecutionSlippage();
|
|
UpdateExecutionStats(slippage);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//--- Standard execution
|
|
TradeMgr.OpenPosition(
|
|
signal.symbol,
|
|
signal.direction,
|
|
position_size,
|
|
signal.stop_loss,
|
|
signal.take_profit,
|
|
signal.comment
|
|
);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| MONITOR PORTFOLIO RISK IN REAL-TIME |
|
|
//+------------------------------------------------------------------+
|
|
void MonitorPortfolioRiskRealtime()
|
|
{
|
|
//--- Calculate current VaR
|
|
g_SystemState.current_var = RiskMgr.CalculatePortfolioVaR(
|
|
g_ManagedTrades,
|
|
0.95, // 95% confidence
|
|
1 // 1-day horizon
|
|
);
|
|
|
|
//--- Calculate CVaR
|
|
g_SystemState.current_cvar = RiskMgr.CalculatePortfolioCVaR(
|
|
g_ManagedTrades,
|
|
0.95,
|
|
1
|
|
);
|
|
|
|
//--- Check limits
|
|
if(g_SystemState.current_var > DailyVaRLimit)
|
|
{
|
|
Utils.Log(LOG_WARNING, StringFormat("VaR limit exceeded: %.2f%% > %.2f%%",
|
|
g_SystemState.current_var, DailyVaRLimit));
|
|
|
|
//--- Reduce positions if needed
|
|
if(UsePortfolioOptimization)
|
|
{
|
|
ReducePortfolioRisk();
|
|
}
|
|
}
|
|
|
|
//--- Update correlation matrix
|
|
if(g_SystemState.tick_count % 1000 == 0)
|
|
{
|
|
UpdateCorrelationMatrix();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UPDATE CORRELATION MATRIX |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateCorrelationMatrix()
|
|
{
|
|
int active_count = 0;
|
|
string active_symbols[];
|
|
|
|
//--- Get active symbols from positions
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
bool found = false;
|
|
for(int j = 0; j < active_count; j++)
|
|
{
|
|
if(active_symbols[j] == g_ManagedTrades[i].symbol)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
{
|
|
ArrayResize(active_symbols, active_count + 1);
|
|
active_symbols[active_count] = g_ManagedTrades[i].symbol;
|
|
active_count++;
|
|
}
|
|
}
|
|
|
|
//--- Calculate correlations
|
|
if(active_count > 1)
|
|
{
|
|
g_SystemState.correlation_matrix = TechAnalysis.CalculateCorrelationMatrix(
|
|
active_symbols,
|
|
CORRELATION_WINDOW
|
|
);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| OPTIMIZE PORTFOLIO WEIGHTS |
|
|
//+------------------------------------------------------------------+
|
|
void OptimizePortfolioWeights()
|
|
{
|
|
if(!UsePortfolioOptimization || ArraySize(g_ManagedTrades) < 2)
|
|
return;
|
|
|
|
//--- Get optimal weights using Markowitz optimization
|
|
double weights[];
|
|
double expected_returns[];
|
|
double covariance_matrix[];
|
|
|
|
//--- Prepare data
|
|
int n = ArraySize(g_ManagedTrades);
|
|
ArrayResize(weights, n);
|
|
ArrayResize(expected_returns, n);
|
|
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
expected_returns[i] = g_ManagedTrades[i].expected_return;
|
|
}
|
|
|
|
//--- Calculate optimal weights
|
|
RiskMgr.CalculateOptimalWeights(
|
|
expected_returns,
|
|
g_SystemState.correlation_matrix,
|
|
g_SystemState.current_var,
|
|
weights
|
|
);
|
|
|
|
//--- Rebalance positions
|
|
RebalancePortfolio(weights);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GET SYMBOL INDEX IN CACHE |
|
|
//+------------------------------------------------------------------+
|
|
int GetSymbolIndex(string symbol)
|
|
{
|
|
for(int i = 0; i < g_ActiveSymbols; i++)
|
|
{
|
|
if(g_SymbolData[i].symbol == symbol)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| QUICK POSITION UPDATE |
|
|
//+------------------------------------------------------------------+
|
|
void QuickPositionUpdate(int symbol_index)
|
|
{
|
|
//--- Update positions for specific symbol
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
if(g_ManagedTrades[i].symbol == g_SymbolData[symbol_index].symbol)
|
|
{
|
|
//--- Fast update using cached values
|
|
if(PositionSelectByTicket(g_ManagedTrades[i].ticket))
|
|
{
|
|
g_ManagedTrades[i].profit = PositionGetDouble(POSITION_PROFIT);
|
|
g_ManagedTrades[i].swap = PositionGetDouble(POSITION_SWAP);
|
|
|
|
//--- Update risk metrics
|
|
double current_price = (g_ManagedTrades[i].type == POSITION_TYPE_BUY) ?
|
|
SymbolInfoDouble(g_ManagedTrades[i].symbol, SYMBOL_BID) :
|
|
SymbolInfoDouble(g_ManagedTrades[i].symbol, SYMBOL_ASK);
|
|
|
|
//--- Apply management rules
|
|
if(TradeMgr != NULL)
|
|
{
|
|
TradeMgr.ManageTradeOptimized(g_ManagedTrades[i], g_SymbolData[symbol_index]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UPDATE ALL POSITIONS OPTIMIZED |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateAllPositionsOptimized()
|
|
{
|
|
//--- Batch update all positions
|
|
ulong start_time = GetMicrosecondCount();
|
|
|
|
int positions_total = PositionsTotal();
|
|
|
|
//--- First pass: collect all position tickets
|
|
ulong tickets[];
|
|
ArrayResize(tickets, positions_total);
|
|
|
|
for(int i = 0; i < positions_total; i++)
|
|
{
|
|
tickets[i] = PositionGetTicket(i);
|
|
}
|
|
|
|
//--- Second pass: update managed trades
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
bool found = false;
|
|
|
|
for(int j = 0; j < positions_total; j++)
|
|
{
|
|
if(g_ManagedTrades[i].ticket == tickets[j])
|
|
{
|
|
found = true;
|
|
|
|
//--- Update position data
|
|
if(PositionSelectByTicket(tickets[j]))
|
|
{
|
|
UpdateManagedTrade(g_ManagedTrades[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//--- Remove if position closed
|
|
if(!found)
|
|
{
|
|
RemoveManagedTrade(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
//--- Third pass: add new external trades
|
|
if(ManageExternalTrades)
|
|
{
|
|
CheckForNewExternalTradesOptimized(tickets);
|
|
}
|
|
|
|
//--- Update performance metrics
|
|
UpdatePerformanceMetrics();
|
|
|
|
//--- Log update time in microseconds
|
|
ulong update_time = GetMicrosecondCount() - start_time;
|
|
if(update_time > 1000) // Log if takes more than 1ms
|
|
{
|
|
Utils.Log(LOG_DEBUG, StringFormat("Position update took %.2f ms", update_time / 1000.0));
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| LOAD EXISTING POSITIONS OPTIMIZED |
|
|
//+------------------------------------------------------------------+
|
|
void LoadExistingPositionsOptimized()
|
|
{
|
|
int positions = PositionsTotal();
|
|
ArrayResize(g_ManagedTrades, 0);
|
|
|
|
for(int i = 0; i < positions; i++)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if(ticket == 0) continue;
|
|
|
|
if(PositionSelectByTicket(ticket))
|
|
{
|
|
//--- Check if we should manage this position
|
|
long magic = PositionGetInteger(POSITION_MAGIC);
|
|
|
|
if(magic == TradingMagic ||
|
|
(ManageExternalTrades && (MagicNumberFilter == 0 || magic == MagicNumberFilter)))
|
|
{
|
|
//--- Create managed trade
|
|
ManagedTradeV71 trade;
|
|
if(CreateManagedTradeOptimized(ticket, trade))
|
|
{
|
|
ArrayResize(g_ManagedTrades, ArraySize(g_ManagedTrades) + 1);
|
|
g_ManagedTrades[ArraySize(g_ManagedTrades) - 1] = trade;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
g_TotalTrades = ArraySize(g_ManagedTrades);
|
|
Print("Loaded ", g_TotalTrades, " existing positions");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CREATE MANAGED TRADE OPTIMIZED |
|
|
//+------------------------------------------------------------------+
|
|
bool CreateManagedTradeOptimized(ulong ticket, ManagedTradeV71 &trade)
|
|
{
|
|
if(!PositionSelectByTicket(ticket))
|
|
return false;
|
|
|
|
//--- Fill basic data
|
|
trade.ticket = ticket;
|
|
trade.symbol = PositionGetString(POSITION_SYMBOL);
|
|
trade.magic = PositionGetInteger(POSITION_MAGIC);
|
|
trade.type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
trade.volume = PositionGetDouble(POSITION_VOLUME);
|
|
trade.open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
trade.open_time = (datetime)PositionGetInteger(POSITION_TIME);
|
|
trade.sl = PositionGetDouble(POSITION_SL);
|
|
trade.tp = PositionGetDouble(POSITION_TP);
|
|
trade.profit = PositionGetDouble(POSITION_PROFIT);
|
|
trade.swap = PositionGetDouble(POSITION_SWAP);
|
|
trade.comment = PositionGetString(POSITION_COMMENT);
|
|
|
|
//--- Get symbol data
|
|
int symbol_index = GetSymbolIndex(trade.symbol);
|
|
if(symbol_index < 0)
|
|
return false;
|
|
|
|
//--- Calculate risk metrics using cached data
|
|
if(trade.sl > 0)
|
|
{
|
|
double stop_distance = (trade.type == POSITION_TYPE_BUY) ?
|
|
trade.open_price - trade.sl :
|
|
trade.sl - trade.open_price;
|
|
|
|
double potential_loss = (stop_distance / g_SymbolData[symbol_index].tick_size) *
|
|
g_SymbolData[symbol_index].tick_value * trade.volume;
|
|
|
|
trade.risk_amount = potential_loss;
|
|
trade.risk_percent = (potential_loss / AccountInfoDouble(ACCOUNT_BALANCE)) * 100;
|
|
}
|
|
|
|
//--- Initialize management flags
|
|
trade.is_managed = true;
|
|
trade.is_external = (trade.magic != TradingMagic);
|
|
trade.management_start = TimeCurrent();
|
|
|
|
//--- Get ML prediction if available
|
|
if(UseMLPrediction && g_MLCache[symbol_index].is_valid)
|
|
{
|
|
trade.expected_return = g_MLCache[symbol_index].expected_return;
|
|
trade.ml_confidence = g_MLCache[symbol_index].confidence;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CHECK FOR NEW EXTERNAL TRADES OPTIMIZED |
|
|
//+------------------------------------------------------------------+
|
|
void CheckForNewExternalTradesOptimized(ulong &tickets[])
|
|
{
|
|
int ticket_count = ArraySize(tickets);
|
|
|
|
for(int i = 0; i < ticket_count; i++)
|
|
{
|
|
if(!PositionSelectByTicket(tickets[i]))
|
|
continue;
|
|
|
|
long magic = PositionGetInteger(POSITION_MAGIC);
|
|
|
|
//--- Skip our own trades
|
|
if(magic == TradingMagic)
|
|
continue;
|
|
|
|
//--- Check magic filter
|
|
if(MagicNumberFilter != 0 && magic != MagicNumberFilter)
|
|
continue;
|
|
|
|
//--- Check if already managed
|
|
bool already_managed = false;
|
|
for(int j = 0; j < ArraySize(g_ManagedTrades); j++)
|
|
{
|
|
if(g_ManagedTrades[j].ticket == tickets[i])
|
|
{
|
|
already_managed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!already_managed)
|
|
{
|
|
//--- Add new external trade
|
|
ManagedTradeV71 trade;
|
|
if(CreateManagedTradeOptimized(tickets[i], trade))
|
|
{
|
|
ArrayResize(g_ManagedTrades, ArraySize(g_ManagedTrades) + 1);
|
|
g_ManagedTrades[ArraySize(g_ManagedTrades) - 1] = trade;
|
|
|
|
Utils.Log(LOG_INFO, StringFormat("New external trade detected: #%d", tickets[i]));
|
|
|
|
//--- Apply risk rules
|
|
if(RiskMgr != NULL)
|
|
{
|
|
RiskMgr.EnforceRiskRulesOptimized(g_ManagedTrades[ArraySize(g_ManagedTrades) - 1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UPDATE MANAGED TRADE |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateManagedTrade(ManagedTradeV71 &trade)
|
|
{
|
|
//--- Update current values
|
|
trade.profit = PositionGetDouble(POSITION_PROFIT);
|
|
trade.swap = PositionGetDouble(POSITION_SWAP);
|
|
trade.commission = Utils.CalculateCommissionOptimized(trade.ticket);
|
|
|
|
//--- Update derived metrics
|
|
double current_pl = trade.profit + trade.swap + trade.commission;
|
|
if(trade.risk_amount > 0)
|
|
{
|
|
trade.r_multiple = current_pl / trade.risk_amount;
|
|
}
|
|
|
|
//--- Track MAE/MFE
|
|
if(current_pl < trade.mae)
|
|
trade.mae = current_pl;
|
|
if(current_pl > trade.mfe)
|
|
trade.mfe = current_pl;
|
|
|
|
//--- Update time in trade
|
|
trade.bars_in_trade = iBars(trade.symbol, PERIOD_CURRENT) -
|
|
iBarShift(trade.symbol, PERIOD_CURRENT, trade.open_time);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| REMOVE MANAGED TRADE |
|
|
//+------------------------------------------------------------------+
|
|
void RemoveManagedTrade(int index)
|
|
{
|
|
if(index < 0 || index >= ArraySize(g_ManagedTrades))
|
|
return;
|
|
|
|
//--- Save to history if enabled
|
|
if(GenerateReports)
|
|
{
|
|
Utils.SaveTradeHistoryOptimized(g_ManagedTrades[index]);
|
|
}
|
|
|
|
//--- Update performance metrics
|
|
g_Performance.total_trades++;
|
|
if(g_ManagedTrades[index].profit > 0)
|
|
{
|
|
g_Performance.winning_trades++;
|
|
g_Performance.gross_profit += g_ManagedTrades[index].profit;
|
|
}
|
|
else
|
|
{
|
|
g_Performance.losing_trades++;
|
|
g_Performance.gross_loss += MathAbs(g_ManagedTrades[index].profit);
|
|
}
|
|
|
|
//--- Remove from array
|
|
ArrayRemove(g_ManagedTrades, index, 1);
|
|
g_TotalTrades = ArraySize(g_ManagedTrades);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UPDATE PERFORMANCE METRICS |
|
|
//+------------------------------------------------------------------+
|
|
void UpdatePerformanceMetrics()
|
|
{
|
|
//--- Calculate basic metrics
|
|
g_Performance.net_profit = g_Performance.gross_profit - g_Performance.gross_loss;
|
|
g_Performance.profit_factor = (g_Performance.gross_loss > 0) ?
|
|
g_Performance.gross_profit / g_Performance.gross_loss : 0;
|
|
|
|
g_Performance.win_rate = (g_Performance.total_trades > 0) ?
|
|
(double)g_Performance.winning_trades / g_Performance.total_trades * 100 : 0;
|
|
|
|
//--- Update drawdown
|
|
double current_balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
if(current_balance > g_SystemState.peak_balance)
|
|
g_SystemState.peak_balance = current_balance;
|
|
|
|
double drawdown = g_SystemState.peak_balance - current_balance;
|
|
double drawdown_percent = (g_SystemState.peak_balance > 0) ?
|
|
drawdown / g_SystemState.peak_balance * 100 : 0;
|
|
|
|
if(drawdown_percent > g_Performance.max_drawdown_percent)
|
|
{
|
|
g_Performance.max_drawdown = drawdown;
|
|
g_Performance.max_drawdown_percent = drawdown_percent;
|
|
}
|
|
|
|
//--- Calculate Sharpe ratio (simplified)
|
|
if(g_Performance.total_trades > 30)
|
|
{
|
|
double returns[];
|
|
ArrayResize(returns, g_Performance.total_trades);
|
|
|
|
// Simplified: use fixed return calculation
|
|
double avg_return = g_Performance.net_profit / g_Performance.total_trades;
|
|
double std_dev = MathSqrt(g_Performance.gross_loss / g_Performance.total_trades);
|
|
|
|
if(std_dev > 0)
|
|
g_Performance.sharpe_ratio = avg_return / std_dev * MathSqrt(252); // Annualized
|
|
}
|
|
|
|
//--- Update real-time Sharpe
|
|
g_SystemState.sharpe_real_time = g_Performance.sharpe_ratio;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UPDATE EXECUTION METRICS |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateExecutionMetrics()
|
|
{
|
|
//--- Get latest execution data from trade manager
|
|
if(TradeMgr != NULL)
|
|
{
|
|
ExecutionStats stats = TradeMgr.GetExecutionStats();
|
|
|
|
//--- Update metrics with exponential smoothing
|
|
g_ExecMetrics.avg_slippage = 0.9 * g_ExecMetrics.avg_slippage +
|
|
0.1 * stats.last_slippage;
|
|
|
|
g_ExecMetrics.avg_fill_time_ms = 0.9 * g_ExecMetrics.avg_fill_time_ms +
|
|
0.1 * stats.last_fill_time;
|
|
|
|
if(stats.last_slippage < 0)
|
|
g_ExecMetrics.positive_slippage_rate = 0.95 * g_ExecMetrics.positive_slippage_rate + 0.05;
|
|
else
|
|
g_ExecMetrics.positive_slippage_rate = 0.95 * g_ExecMetrics.positive_slippage_rate;
|
|
|
|
g_ExecMetrics.rejected_orders = stats.total_rejected;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| PROCESS HIGH PRIORITY TASKS |
|
|
//+------------------------------------------------------------------+
|
|
void ProcessHighPriorityTasks()
|
|
{
|
|
//--- Check for stop loss hits
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
if(g_ManagedTrades[i].sl > 0)
|
|
{
|
|
double current_price = (g_ManagedTrades[i].type == POSITION_TYPE_BUY) ?
|
|
SymbolInfoDouble(g_ManagedTrades[i].symbol, SYMBOL_BID) :
|
|
SymbolInfoDouble(g_ManagedTrades[i].symbol, SYMBOL_ASK);
|
|
|
|
bool sl_hit = (g_ManagedTrades[i].type == POSITION_TYPE_BUY && current_price <= g_ManagedTrades[i].sl) ||
|
|
(g_ManagedTrades[i].type == POSITION_TYPE_SELL && current_price >= g_ManagedTrades[i].sl);
|
|
|
|
if(sl_hit && UseSmartRouting)
|
|
{
|
|
//--- Execute emergency close with smart routing
|
|
ExecOptimizer.ExecuteEmergencyClose(g_ManagedTrades[i].ticket);
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- Check for critical risk events
|
|
if(g_SystemState.current_var > DailyVaRLimit * 1.2)
|
|
{
|
|
Utils.Log(LOG_CRITICAL, "Critical VaR breach - initiating risk reduction");
|
|
EmergencyRiskReduction();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UPDATE REAL-TIME ANALYTICS |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateRealtimeAnalytics()
|
|
{
|
|
//--- Portfolio Greeks
|
|
if(UsePortfolioOptimization)
|
|
{
|
|
g_SystemState.portfolio_beta = RiskMgr.CalculatePortfolioBeta(g_ManagedTrades);
|
|
}
|
|
|
|
//--- Liquidity analysis
|
|
if(EnableOrderFlow && OrderFlow != NULL)
|
|
{
|
|
for(int i = 0; i < g_ActiveSymbols; i++)
|
|
{
|
|
g_SymbolData[i].liquidity_score = OrderFlow.GetLiquidityScore(g_SymbolData[i].symbol);
|
|
}
|
|
}
|
|
|
|
//--- Performance attribution
|
|
if(Reporter != NULL && g_Performance.total_trades > 0)
|
|
{
|
|
Reporter.UpdatePerformanceAttribution(g_ManagedTrades, g_Performance);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| REDUCE PORTFOLIO RISK |
|
|
//+------------------------------------------------------------------+
|
|
void ReducePortfolioRisk()
|
|
{
|
|
//--- Sort trades by risk contribution
|
|
RiskContribution contributions[];
|
|
ArrayResize(contributions, ArraySize(g_ManagedTrades));
|
|
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
contributions[i].index = i;
|
|
contributions[i].risk = g_ManagedTrades[i].risk_percent;
|
|
contributions[i].correlation_risk = RiskMgr.CalculateCorrelationRisk(
|
|
g_ManagedTrades[i],
|
|
g_SystemState.correlation_matrix
|
|
);
|
|
}
|
|
|
|
//--- Sort by total risk contribution
|
|
ArraySort(contributions);
|
|
|
|
//--- Reduce highest risk positions
|
|
int positions_to_reduce = MathMin(3, ArraySize(contributions));
|
|
for(int i = 0; i < positions_to_reduce; i++)
|
|
{
|
|
int index = contributions[ArraySize(contributions) - 1 - i].index;
|
|
|
|
//--- Reduce position by 50%
|
|
double reduce_volume = g_ManagedTrades[index].volume * 0.5;
|
|
TradeMgr.PartialCloseOptimized(g_ManagedTrades[index].ticket, reduce_volume);
|
|
|
|
Utils.Log(LOG_WARNING, StringFormat("Reduced position #%d by 50%% due to risk limits",
|
|
g_ManagedTrades[index].ticket));
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EMERGENCY RISK REDUCTION |
|
|
//+------------------------------------------------------------------+
|
|
void EmergencyRiskReduction()
|
|
{
|
|
//--- Close all losing positions immediately
|
|
for(int i = ArraySize(g_ManagedTrades) - 1; i >= 0; i--)
|
|
{
|
|
if(g_ManagedTrades[i].profit < 0)
|
|
{
|
|
TradeMgr.ClosePositionOptimized(g_ManagedTrades[i].ticket);
|
|
}
|
|
}
|
|
|
|
//--- Reduce all winning positions by 75%
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
if(g_ManagedTrades[i].profit > 0)
|
|
{
|
|
double reduce_volume = g_ManagedTrades[i].volume * 0.75;
|
|
TradeMgr.PartialCloseOptimized(g_ManagedTrades[i].ticket, reduce_volume);
|
|
}
|
|
}
|
|
|
|
//--- Disable new entries
|
|
g_SystemState.is_active = false;
|
|
Utils.Log(LOG_CRITICAL, "Emergency risk reduction completed - system disabled");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| REBALANCE PORTFOLIO |
|
|
//+------------------------------------------------------------------+
|
|
void RebalancePortfolio(double &target_weights[])
|
|
{
|
|
//--- Calculate current weights
|
|
double total_value = 0;
|
|
double current_values[];
|
|
ArrayResize(current_values, ArraySize(g_ManagedTrades));
|
|
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
current_values[i] = g_ManagedTrades[i].volume *
|
|
SymbolInfoDouble(g_ManagedTrades[i].symbol, SYMBOL_BID) *
|
|
g_SymbolData[GetSymbolIndex(g_ManagedTrades[i].symbol)].contract_size;
|
|
total_value += current_values[i];
|
|
}
|
|
|
|
//--- Calculate adjustments needed
|
|
for(int i = 0; i < ArraySize(g_ManagedTrades); i++)
|
|
{
|
|
double current_weight = current_values[i] / total_value;
|
|
double weight_diff = target_weights[i] - current_weight;
|
|
|
|
if(MathAbs(weight_diff) > 0.05) // 5% threshold
|
|
{
|
|
//--- Calculate volume adjustment
|
|
double target_value = total_value * target_weights[i];
|
|
double value_diff = target_value - current_values[i];
|
|
|
|
int symbol_index = GetSymbolIndex(g_ManagedTrades[i].symbol);
|
|
double adj_volume = MathAbs(value_diff) /
|
|
(SymbolInfoDouble(g_ManagedTrades[i].symbol, SYMBOL_BID) *
|
|
g_SymbolData[symbol_index].contract_size);
|
|
|
|
//--- Normalize to lot step
|
|
adj_volume = MathRound(adj_volume / g_SymbolData[symbol_index].lot_step) *
|
|
g_SymbolData[symbol_index].lot_step;
|
|
|
|
if(value_diff < 0 && adj_volume > 0)
|
|
{
|
|
//--- Reduce position
|
|
TradeMgr.PartialCloseOptimized(g_ManagedTrades[i].ticket, adj_volume);
|
|
}
|
|
else if(value_diff > 0 && adj_volume > 0)
|
|
{
|
|
//--- Increase position (if allowed)
|
|
if(EnableMultipleEntries)
|
|
{
|
|
TradeMgr.AddToPositionOptimized(g_ManagedTrades[i], adj_volume);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GET UNINIT REASON TEXT |
|
|
//+------------------------------------------------------------------+
|
|
string GetUninitReasonText(int reason)
|
|
{
|
|
switch(reason)
|
|
{
|
|
case REASON_PROGRAM: return "Program terminated";
|
|
case REASON_REMOVE: return "Program removed from chart";
|
|
case REASON_RECOMPILE: return "Program recompiled";
|
|
case REASON_CHARTCHANGE: return "Symbol or timeframe changed";
|
|
case REASON_CHARTCLOSE: return "Chart closed";
|
|
case REASON_PARAMETERS: return "Input parameters changed";
|
|
case REASON_ACCOUNT: return "Account changed";
|
|
default: return "Other reason";
|
|
}
|
|
} |