mql5/Shared Projects/ERMT-ML/ERMT_8x.mq5
darashikoh 0fb1bd1b0a Module Integration Summary for External Trade Management
Overview
To fully integrate the enhanced external trade management system, updates are required to 5 out of 7 existing modules. The updates maintain backward compatibility while adding new functionality for external trade handling.
Module Update Requirements
🟢 No Updates Required (2 modules)

TechnicalAnalysis.mqh - Already provides necessary calculations
EntrySystem.mqh - Only handles EA's own entry signals

🟡 Minor Updates (2 modules)

DataTypes.mqh - Add external trade structures and fields
Utilities.mqh - Enhanced logging for external trades

🟠 Moderate Updates (3 modules)

RiskManager.mqh - Enhanced risk enforcement methods
TradeManager.mqh - Improved stop management for externals
Dashboard.mqh - Display external trade information

Integration Steps
Phase 1: Data Structures (DataTypes.mqh)

Add ENUM_EXTERNAL_STATUS enumeration
Extend ManagedTrade structure with external-specific fields
Add ExternalTradeStats structure for metrics
Update DashboardConfig with show_external flag

Key additions:

external_status - Track state of external trade
source_name - Identify where trade came from
stops_modified - Track if we modified the trade
original_sl/tp - Store original values for comparison

Phase 2: Risk Management (RiskManager.mqh)

Add EnforceRiskRulesEnhanced() method
Implement GetExternalExposure() for risk aggregation
Add UpdateExternalStats() for tracking
Enhance ValidateAndAdjustRiskExternal() method

Key features:

Separate risk calculation for external trades
Cache mechanism for performance
Statistical tracking of external positions
Smart risk adjustment without closing trades

Phase 3: Trade Management (TradeManager.mqh)

Add ApplyDefaultStopsEnhanced() with better logic
Implement OverrideExternalStops() with smart override
Create ManageExternalTrade() with different rules
Add ApplyBreakevenExternal() with wider triggers

Key features:

Smart stop override (only improve, never worsen)
Different management rules for external trades
Respect minimum broker distances
Track modification success/failure rates

Phase 4: User Interface (Dashboard.mqh)

Add CreateExternalSection() for display area
Implement UpdateExternalSection() for real-time updates
Add SetCustomText() for flexible display
Create ShowExternalTrades() toggle method

Key features:

Real-time external trade count and risk
Color-coded risk warnings
List of active external positions
Modification statistics display

Phase 5: Logging (Utilities.mqh)

Add LogExternalTrade() for detailed event logging
Create separate CSV log for external trades
Enhance GenerateReportEnhanced() with external section
Add IdentifyTradeSource() for magic number interpretation

Key features:

Separate CSV log for external trade events
Detailed tracking of all modifications
Source identification from magic numbers
Enhanced reporting with external statistics
2025-08-27 14:21:02 +01:00

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";
}
}