mql5/Shared Projects/ERMT-ML/ERMT_8x.mq5

1461 lines
51 KiB
MQL5
Raw Permalink Normal View History

Module Integration Summary for External Trade Management Overview To fully integrate the enhanced external trade management system, updates are required to 5 out of 7 existing modules. The updates maintain backward compatibility while adding new functionality for external trade handling. Module Update Requirements 🟢 No Updates Required (2 modules) TechnicalAnalysis.mqh - Already provides necessary calculations EntrySystem.mqh - Only handles EA's own entry signals 🟡 Minor Updates (2 modules) DataTypes.mqh - Add external trade structures and fields Utilities.mqh - Enhanced logging for external trades 🟠 Moderate Updates (3 modules) RiskManager.mqh - Enhanced risk enforcement methods TradeManager.mqh - Improved stop management for externals Dashboard.mqh - Display external trade information Integration Steps Phase 1: Data Structures (DataTypes.mqh) Add ENUM_EXTERNAL_STATUS enumeration Extend ManagedTrade structure with external-specific fields Add ExternalTradeStats structure for metrics Update DashboardConfig with show_external flag Key additions: external_status - Track state of external trade source_name - Identify where trade came from stops_modified - Track if we modified the trade original_sl/tp - Store original values for comparison Phase 2: Risk Management (RiskManager.mqh) Add EnforceRiskRulesEnhanced() method Implement GetExternalExposure() for risk aggregation Add UpdateExternalStats() for tracking Enhance ValidateAndAdjustRiskExternal() method Key features: Separate risk calculation for external trades Cache mechanism for performance Statistical tracking of external positions Smart risk adjustment without closing trades Phase 3: Trade Management (TradeManager.mqh) Add ApplyDefaultStopsEnhanced() with better logic Implement OverrideExternalStops() with smart override Create ManageExternalTrade() with different rules Add ApplyBreakevenExternal() with wider triggers Key features: Smart stop override (only improve, never worsen) Different management rules for external trades Respect minimum broker distances Track modification success/failure rates Phase 4: User Interface (Dashboard.mqh) Add CreateExternalSection() for display area Implement UpdateExternalSection() for real-time updates Add SetCustomText() for flexible display Create ShowExternalTrades() toggle method Key features: Real-time external trade count and risk Color-coded risk warnings List of active external positions Modification statistics display Phase 5: Logging (Utilities.mqh) Add LogExternalTrade() for detailed event logging Create separate CSV log for external trades Enhance GenerateReportEnhanced() with external section Add IdentifyTradeSource() for magic number interpretation Key features: Separate CSV log for external trade events Detailed tracking of all modifications Source identification from magic numbers Enhanced reporting with external statistics
2025-08-27 14:21:02 +01:00
//+------------------------------------------------------------------+
//| 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";
}
}