mql5/Experts/Advisors/ERMT_6.8.mq5
2025-09-05 18:17:25 +01:00

1115 lines
No EOL
39 KiB
MQL5

//+------------------------------------------------------------------+
//| Risk Management Overlay EA v6.8 |
//| Enhanced External Trade Management System |
//| Optimized Main Coordinator File |
//+------------------------------------------------------------------+
#property copyright "ERMT v6.8 - Enhanced Architecture"
#property link ""
#property version "6.80"
#property description "Institutional-grade risk management and trade optimization"
#property strict
// Include all modules
#include "Modules/DataTypes.mqh"
#include "Modules/Utilities.mqh"
#include "Modules/RiskManager.mqh"
#include "Modules/TechnicalAnalysis.mqh"
#include "Modules/ExternalTradeManager.mqh"
#include "Modules/TradeManager.mqh"
#include "Modules/Dashboard.mqh"
//+------------------------------------------------------------------+
//| Input Parameters |
//+------------------------------------------------------------------+
// Risk Management
input group "=== Risk Management ==="
input double InpMaxRiskPerTrade = 2.0; // Max Risk Per Trade (%)
input double InpMaxDailyLoss = 6.0; // Max Daily Loss (%)
input double InpMaxDrawdown = 20.0; // Max Drawdown (%)
input int InpMaxPositions = 3; // Max Concurrent Positions
input double InpRiskRewardMin = 1.5; // Minimum Risk/Reward Ratio
// Position Management
input group "=== Position Management ==="
input ENUM_POSITION_SIZING InpSizingMethod = SIZING_FIXED_PERCENT; // Position Sizing Method
input double InpFixedLotSize = 0.1; // Fixed Lot Size
input double InpATRMultiplierSL = 2.0; // ATR Multiplier for SL
input double InpATRMultiplierTP = 3.0; // ATR Multiplier for TP
input ENUM_TP_METHOD InpTPMethod = TP_FIXED_RR; // Take Profit Method
input double InpTPRatio = 2.0; // TP Risk/Reward Ratio
// External Trade Management
input group "=== External Trade Management ==="
input bool InpManageExternal = true; // Manage External Trades
input ENUM_MANAGEMENT_MODE InpExternalMode = MODE_STOPS_ONLY; // Management Mode
input double InpExternalRiskLimit = 5.0; // External Trade Risk Limit (%)
input bool InpApplyTrailingExternal = true; // Apply Trailing to External
// Trailing Stop
input group "=== Trailing Stop Settings ==="
input ENUM_TRAILING_METHOD InpTrailingMethod = TRAIL_ATR; // Trailing Method
input double InpTrailStart = 30; // Trail Start (points)
input double InpTrailStep = 10; // Trail Step (points)
input double InpTrailDistance = 20; // Trail Distance (points)
input bool InpMoveToBreakeven = true; // Move to Breakeven
input double InpBreakevenTrigger = 20; // Breakeven Trigger (points)
input double InpBreakevenOffset = 2; // Breakeven Offset (points)
// Trading Settings
input group "=== Trading Settings ==="
input int InpMagicNumber = 68000; // Magic Number
input string InpComment = "ERMT_v6.8"; // Trade Comment
input double InpSlippage = 3; // Max Slippage (points)
input bool InpTradeOnNewBar = false; // Trade Only on New Bar
input bool InpAllowHedging = false; // Allow Hedging
input bool InpCloseOnOpposite = true; // Close on Opposite Signal
// Technical Indicators
input group "=== Technical Settings ==="
input int InpATRPeriod = 14; // ATR Period
input int InpRSIPeriod = 14; // RSI Period
input int InpMAPeriod = 20; // MA Period
input ENUM_MA_METHOD InpMAMethod = MODE_SMA; // MA Method
input double InpBBDeviation = 2.0; // Bollinger Band Deviation
input int InpBBPeriod = 20; // Bollinger Band Period
// Trading Hours
input group "=== Trading Hours ==="
input bool InpUseTradeHours = false; // Use Trading Hours
input int InpStartHour = 8; // Start Hour (Server Time)
input int InpEndHour = 20; // End Hour (Server Time)
input bool InpFridayClose = true; // Close All on Friday
input int InpFridayCloseHour = 20; // Friday Close Hour
// Dashboard
input group "=== Dashboard Settings ==="
input bool InpShowDashboard = true; // Show Dashboard
input int InpDashboardX = 20; // Dashboard X Position
input int InpDashboardY = 50; // Dashboard Y Position
input color InpDashboardColor = clrBlack; // Dashboard Text Color
input color InpDashboardBgColor = clrYellowGreen; // Dashboard Background Color
input int InpDashboardFontSize = 9; // Dashboard Font Size
// Logging
input group "=== Logging Settings ==="
input ENUM_LOG_LEVEL InpLogLevel = LOG_INFO; // Log Level
input bool InpSaveLog = true; // Save Log to File
input bool InpEmailAlerts = false; // Send Email Alerts
input bool InpPushAlerts = false; // Send Push Notifications
//+------------------------------------------------------------------+
//| Global Variables |
//+------------------------------------------------------------------+
// Core components
CUtilities* g_utils;
CRiskManager* g_risk;
CTechnicalAnalysis* g_tech;
CExternalTradeManager* g_external;
CTradeManager* g_trade;
CDashboard* g_dashboard;
// State tracking
datetime g_last_bar_time = 0;
bool g_initialized = false;
int g_tick_count = 0;
double g_session_profit = 0;
datetime g_session_start = 0;
double g_starting_balance = 0;
// Market conditions
ENUM_MARKET_CONDITION g_current_market = MARKET_RANGING;
double g_current_volatility = 0;
double g_current_spread = 0;
bool g_trade_allowed = true;
// Performance tracking
int g_trades_today = 0;
int g_wins_today = 0;
int g_losses_today = 0;
datetime g_last_trade_time = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("========================================");
Print("=== ERMT v6.8 Initializing ===");
Print("========================================");
// Validate inputs
if(!ValidateInputs())
{
Print("Invalid input parameters");
return INIT_PARAMETERS_INCORRECT;
}
// Create component instances
g_utils = new CUtilities();
g_risk = new CRiskManager();
g_tech = new CTechnicalAnalysis();
g_external = new CExternalTradeManager();
g_trade = new CTradeManager();
g_dashboard = new CDashboard();
// Initialize utilities first
if(!g_utils.Initialize(InpLogLevel))
{
Print("Failed to initialize utilities");
Cleanup();
return INIT_FAILED;
}
g_utils.EnableFileLogging(InpSaveLog);
// Initialize risk manager
RiskParameters risk_params;
risk_params.max_risk_per_trade = InpMaxRiskPerTrade;
risk_params.max_daily_loss = InpMaxDailyLoss;
risk_params.max_drawdown = InpMaxDrawdown;
risk_params.max_positions = InpMaxPositions;
risk_params.min_risk_reward = InpRiskRewardMin;
risk_params.use_money_management = true;
risk_params.scale_with_equity = true;
risk_params.risk_multiplier = 1.0;
if(!g_risk.Initialize(g_utils, risk_params))
{
Print("Failed to initialize risk manager");
Cleanup();
return INIT_FAILED;
}
g_risk.SetMagicNumber(InpMagicNumber);
// Initialize technical analysis
if(!g_tech.Initialize(g_utils, InpATRPeriod, InpRSIPeriod, InpMAPeriod))
{
Print("Failed to initialize technical analysis");
Cleanup();
return INIT_FAILED;
}
g_tech.SetBollingerParams(InpBBPeriod, InpBBDeviation);
// Initialize external trade manager
if(!g_external.Initialize(g_utils, InpMagicNumber))
{
Print("Failed to initialize external trade manager");
Cleanup();
return INIT_FAILED;
}
g_external.SetManagementMode(InpExternalMode);
g_external.SetExternalRiskLimit(InpExternalRiskLimit);
// Initialize trade manager
if(!g_trade.Initialize(g_utils, g_risk, g_tech, g_external, InpMagicNumber))
{
Print("Failed to initialize trade manager");
Cleanup();
return INIT_FAILED;
}
// Configure trade manager
g_trade.SetSizingMethod(InpSizingMethod);
g_trade.SetFixedLotSize(InpFixedLotSize);
g_trade.SetATRMultipliers(InpATRMultiplierSL, InpATRMultiplierTP);
g_trade.SetTrailingMethod(InpTrailingMethod);
g_trade.SetTrailingParams(InpTrailStart, InpTrailStep, InpTrailDistance);
g_trade.SetBreakevenEnabled(InpMoveToBreakeven);
g_trade.SetSlippage(InpSlippage);
g_trade.SetComment(InpComment);
// Initialize dashboard
if(InpShowDashboard)
{
if(!g_dashboard.Initialize(InpDashboardX, InpDashboardY))
{
g_utils.Log("Failed to initialize dashboard", LOG_WARNING);
// Non-critical, continue
}
else
{
g_dashboard.SetColors(InpDashboardColor, clrRed, clrLime);
g_dashboard.SetFontSize(InpDashboardFontSize);
g_dashboard.SetBackgroundColor(InpDashboardBgColor);
}
}
// Session initialization
g_session_start = TimeCurrent();
g_starting_balance = AccountInfoDouble(ACCOUNT_BALANCE);
g_last_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
g_initialized = true;
// Perform initial market scan to populate market conditions
UpdateMarketConditions();
// Log configuration
LogConfiguration();
// Initial market scan
UpdateMarketConditions();
// Detect any existing external trades
if(InpManageExternal)
{
g_external.DetectExternalTrades();
int external_count = g_external.GetExternalTradeCount();
if(external_count > 0)
{
g_utils.Log(StringFormat("Found %d external trades to manage", external_count), LOG_INFO);
}
}
g_utils.Log("ERMT v6.8 initialization complete", LOG_INFO);
Print("=== Initialization Complete ===");
// Set timer for periodic tasks (every 5 seconds)
EventSetTimer(5);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
string reason_text = GetDeInitReasonText(reason);
g_utils.Log(StringFormat("EA Deinitializing. Reason: %s", reason_text), LOG_INFO);
// Generate final report
if(g_trade != NULL)
{
PerformanceMetrics metrics;
g_trade.GetPerformanceMetrics(metrics);
string report = g_utils.GenerateReportEnhanced(metrics,
g_external.GetExternalTradeCount(),
g_external.GetExternalProfit());
g_utils.Log(report, LOG_INFO);
// Save final report to file
g_utils.SaveToFile(StringFormat("ERMT_FinalReport_%s.txt",
TimeToString(TimeCurrent(), TIME_DATE)), report);
}
// Clean up
Cleanup();
Comment("");
Print("=== ERMT v6.8 Shutdown Complete ===");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(!g_initialized) return;
// Check if trading is allowed
if(!CheckTradingConditions())
{
g_trade_allowed = false;
return;
}
g_trade_allowed = true;
g_tick_count++;
g_utils.StartTimer();
// Check for new bar
bool new_bar = false;
datetime current_bar = iTime(_Symbol, PERIOD_CURRENT, 0);
if(current_bar != g_last_bar_time)
{
g_last_bar_time = current_bar;
new_bar = true;
// New bar processing
OnNewBar();
}
// Skip if configured to trade only on new bar
if(InpTradeOnNewBar && !new_bar) return;
// Core processing
ProcessExternalTrades();
ProcessManagedTrades();
// Check for new signals on new bar
if(new_bar && g_trade_allowed)
{
CheckEntrySignals();
}
// Update dashboard on every tick (if shown)
if(InpShowDashboard)
{
UpdateDashboard();
}
// Performance tracking
double elapsed = g_utils.GetElapsedTime();
if(elapsed > 100) // Log if processing takes > 100ms
{
g_utils.Log(StringFormat("Slow tick processing: %.1f ms", elapsed), LOG_WARNING);
}
}
//+------------------------------------------------------------------+
//| Timer Event |
//+------------------------------------------------------------------+
void OnTimer()
{
if(!g_initialized) return;
// Periodic maintenance tasks
PeriodicTasks();
// Check Friday close
if(InpFridayClose && CheckFridayClose())
{
CloseAllPositions("Friday close");
}
// Monitor system health
CheckSystemHealth();
}
//+------------------------------------------------------------------+
//| Trade Event |
//+------------------------------------------------------------------+
void OnTrade()
{
if(!g_initialized) return;
// Update session profit
double current_balance = AccountInfoDouble(ACCOUNT_BALANCE);
g_session_profit = current_balance - g_starting_balance;
// Track daily trades
MqlDateTime current_time;
TimeToStruct(TimeCurrent(), current_time);
MqlDateTime last_trade_time;
TimeToStruct(g_last_trade_time, last_trade_time);
if(current_time.day != last_trade_time.day)
{
// Reset daily counters
g_trades_today = 0;
g_wins_today = 0;
g_losses_today = 0;
}
g_last_trade_time = TimeCurrent();
// Log trade event
g_utils.Log("Trade event detected", LOG_DEBUG);
}
//+------------------------------------------------------------------+
//| New Bar Processing |
//+------------------------------------------------------------------+
void OnNewBar()
{
// Update market analysis
UpdateMarketConditions();
// Check daily reset
MqlDateTime current;
TimeToStruct(TimeCurrent(), current);
MqlDateTime session_start;
TimeToStruct(g_session_start, session_start);
if(current.day != session_start.day)
{
// New trading day
g_risk.ResetDailyCounters();
g_trades_today = 0;
g_wins_today = 0;
g_losses_today = 0;
g_utils.Log("New trading day started", LOG_INFO);
}
// Log periodic status
if(g_tick_count % 100 == 0)
{
LogStatus();
}
}
//+------------------------------------------------------------------+
//| Update Market Conditions |
//+------------------------------------------------------------------+
void UpdateMarketConditions()
{
// Analyze current market state
ENUM_SIGNAL_TYPE signal = g_tech.AnalyzeMarket();
// Update volatility
g_current_volatility = g_utils.GetATR(InpATRPeriod);
// Update spread
g_current_spread = g_utils.CalculateSpread(_Symbol);
// Determine market condition
double trend_strength = g_tech.GetTrendStrength();
double volatility_ratio = g_tech.GetVolatilityRatio();
if(trend_strength > 0.7)
{
g_current_market = (signal == SIGNAL_BUY) ? MARKET_TRENDING_UP : MARKET_TRENDING_DOWN;
}
else if(trend_strength < 0.3)
{
g_current_market = MARKET_RANGING;
}
else if(volatility_ratio > 1.5)
{
g_current_market = MARKET_VOLATILE;
}
else if(g_tech.IsBreakout())
{
g_current_market = MARKET_BREAKOUT;
}
else if(g_tech.CheckReversal())
{
g_current_market = MARKET_REVERSAL;
}
else
{
g_current_market = MARKET_RANGING;
}
g_utils.Log(StringFormat("Market: %s, Trend: %.2f, Vol: %.5f, Spread: %.1f",
MarketConditionToString(g_current_market),
trend_strength, g_current_volatility, g_current_spread), LOG_DEBUG);
}
//+------------------------------------------------------------------+
//| Process External Trades |
//+------------------------------------------------------------------+
void ProcessExternalTrades()
{
if(!InpManageExternal) return;
// Detect new external trades
g_external.DetectExternalTrades();
// Process existing external trades
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(g_external.IsTicketExternal(ticket))
{
// Apply management based on mode
g_external.ManageExternalTrade(ticket);
// Apply trailing if enabled and profitable
if(InpApplyTrailingExternal && InpTrailingMethod != TRAIL_NONE)
{
if(PositionGetDouble(POSITION_PROFIT) > 0)
{
double profit_points = PositionGetDouble(POSITION_PROFIT) /
PositionGetDouble(POSITION_VOLUME);
if(profit_points >= InpTrailStart)
{
g_external.ApplyTrailingToExternal(ticket, InpTrailDistance);
}
}
}
// Check for breakeven
if(InpMoveToBreakeven)
{
double profit_points = PositionGetDouble(POSITION_PROFIT) /
PositionGetDouble(POSITION_VOLUME);
if(profit_points >= InpBreakevenTrigger)
{
g_external.MoveExternalToBreakeven(ticket);
}
}
}
}
// Monitor and clean up
g_external.MonitorExternalTrades();
}
//+------------------------------------------------------------------+
//| Process Managed Trades |
//+------------------------------------------------------------------+
void ProcessManagedTrades()
{
TradeInfo managed_trades[];
int trade_count = g_trade.GetManagedTrades(managed_trades);
for(int i = 0; i < trade_count; i++)
{
// Check risk rules
if(!g_risk.ValidateAndAdjustRisk(managed_trades[i]))
{
g_utils.Log(StringFormat("Risk violation for trade %d",
managed_trades[i].ticket), LOG_WARNING);
// Process close request if flagged
if(managed_trades[i].close_requested)
{
g_trade.CloseTrade(managed_trades[i].ticket, managed_trades[i].close_reason);
continue;
}
// Process partial close if flagged
if(managed_trades[i].partial_close_volume > 0)
{
g_trade.PartialClose(managed_trades[i].ticket,
managed_trades[i].partial_close_volume,
managed_trades[i].partial_close_reason);
}
}
// Apply trailing stop
if(InpTrailingMethod != TRAIL_NONE && managed_trades[i].profit > 0)
{
g_trade.ApplyTrailingStop(managed_trades[i].ticket);
}
// Check for breakeven
if(InpMoveToBreakeven)
{
g_trade.CheckBreakeven(managed_trades[i].ticket);
}
// Monitor for exit signals
ENUM_SIGNAL_TYPE exit_signal = g_tech.CheckExitSignal(managed_trades[i]);
if(exit_signal != SIGNAL_NONE)
{
// Check if we should close on opposite signal
if(InpCloseOnOpposite)
{
if((managed_trades[i].type == ORDER_TYPE_BUY && exit_signal == SIGNAL_SELL) ||
(managed_trades[i].type == ORDER_TYPE_SELL && exit_signal == SIGNAL_BUY))
{
g_trade.CloseTrade(managed_trades[i].ticket, "Opposite signal");
}
}
}
}
}
//+------------------------------------------------------------------+
//| Check for Entry Signals |
//+------------------------------------------------------------------+
void CheckEntrySignals()
{
// Check if we can open new positions
if(!g_risk.CanOpenNewPosition())
{
g_utils.Log("Cannot open new position - risk limits", LOG_DEBUG);
return;
}
// Get market signal
ENUM_SIGNAL_TYPE signal = g_tech.AnalyzeMarket();
if(signal == SIGNAL_NONE) return;
// Check for hedging restrictions
if(!InpAllowHedging)
{
// Check if we have opposite positions
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
{
ENUM_ORDER_TYPE pos_type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE);
if((signal == SIGNAL_BUY && pos_type == ORDER_TYPE_SELL) ||
(signal == SIGNAL_SELL && pos_type == ORDER_TYPE_BUY))
{
g_utils.Log("Signal rejected - hedging not allowed", LOG_DEBUG);
return;
}
}
}
}
// Prepare trade request
MqlTradeRequest request = {};
request.symbol = _Symbol;
request.type = (signal == SIGNAL_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
request.comment = InpComment;
request.magic = InpMagicNumber;
// Calculate position size
double atr = g_utils.GetATR(InpATRPeriod);
double stop_distance = atr * InpATRMultiplierSL;
double lot_size = g_risk.CalculatePositionSize(_Symbol, stop_distance, InpSizingMethod);
if(lot_size == 0)
{
g_utils.Log("Position size calculation returned 0", LOG_WARNING);
return;
}
request.volume = lot_size;
// Calculate stops
double entry_price = (signal == SIGNAL_BUY) ?
SymbolInfoDouble(_Symbol, SYMBOL_ASK) :
SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = (signal == SIGNAL_BUY) ?
entry_price - stop_distance :
entry_price + stop_distance;
double tp = 0;
if(InpTPMethod == TP_FIXED_RR)
{
double tp_distance = stop_distance * InpTPRatio;
tp = (signal == SIGNAL_BUY) ?
entry_price + tp_distance :
entry_price - tp_distance;
}
else if(InpTPMethod == TP_ATR_BASED)
{
double tp_distance = atr * InpATRMultiplierTP;
tp = (signal == SIGNAL_BUY) ?
entry_price + tp_distance :
entry_price - tp_distance;
}
else if(InpTPMethod == TP_TECHNICAL_LEVEL)
{
tp = g_tech.GetNearestLevel(entry_price, signal == SIGNAL_BUY);
}
request.price = entry_price;
request.sl = g_utils.NormalizePrice(sl, _Symbol);
request.tp = g_utils.NormalizePrice(tp, _Symbol);
// Final validation with risk manager
if(!g_risk.ValidateNewPosition(_Symbol, lot_size, stop_distance))
{
g_utils.Log("Trade rejected by risk manager", LOG_INFO);
return;
}
// Execute trade
ulong ticket = g_trade.OpenTrade(request);
if(ticket > 0)
{
g_trades_today++;
string message = StringFormat("Trade opened: #%d %s %s %.2f @ %.5f SL=%.5f TP=%.5f",
ticket,
(signal == SIGNAL_BUY) ? "BUY" : "SELL",
_Symbol, lot_size, entry_price, sl, tp);
g_utils.Log(message, LOG_INFO);
// Send alerts if enabled
if(InpEmailAlerts) SendMail("ERMT Trade", message);
if(InpPushAlerts) SendNotification(message);
}
}
//+------------------------------------------------------------------+
//| Periodic Maintenance Tasks |
//+------------------------------------------------------------------+
void PeriodicTasks()
{
// Update performance metrics
PerformanceMetrics metrics;
g_trade.GetPerformanceMetrics(metrics);
// Update risk manager with performance
g_risk.UpdatePerformanceMetrics(metrics.win_rate,
metrics.average_win,
metrics.average_loss);
// Log periodic report
static int report_counter = 0;
report_counter++;
if(report_counter >= 120) // Every 10 minutes (5 sec timer * 120)
{
report_counter = 0;
g_utils.LogPerformance(metrics);
}
// Check daily loss limit
if(g_risk.IsDailyLossLimitReached())
{
g_utils.Log("Daily loss limit reached - stopping trading", LOG_WARNING);
g_trade_allowed = false;
// Close all positions if critical
if(g_risk.GetDailyLoss() > g_risk.GetCurrentDrawdown() * 1.5)
{
CloseAllPositions("Daily loss limit exceeded");
}
}
// Clean up old data
g_trade.CleanupHistory();
// Save performance snapshot
static int save_counter = 0;
save_counter++;
if(save_counter >= 720) // Every hour
{
save_counter = 0;
SavePerformanceSnapshot(metrics);
}
}
//+------------------------------------------------------------------+
//| Update Dashboard Display |
//+------------------------------------------------------------------+
void UpdateDashboard()
{
if(g_dashboard == NULL) return;
// Get current metrics
PerformanceMetrics metrics;
g_trade.GetPerformanceMetrics(metrics);
// Prepare dashboard data
DashboardData data;
data.balance = AccountInfoDouble(ACCOUNT_BALANCE);
data.equity = AccountInfoDouble(ACCOUNT_EQUITY);
data.free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
data.profit = metrics.total_profit;
data.positions = g_trade.GetOpenTradeCount();
data.win_rate = metrics.win_rate;
data.profit_factor = metrics.profit_factor;
data.drawdown = metrics.current_drawdown;
data.daily_profit = g_session_profit;
data.external_trades = g_external.GetExternalTradeCount();
data.external_profit = g_external.GetExternalProfit();
data.risk_status = g_risk.GetCurrentRiskLevel();
data.market_condition = MarketConditionToString(g_current_market);
// Additional info
data.spread = g_current_spread;
data.daily_trades = g_trades_today;
// Update dashboard
g_dashboard.Update(data);
// Show comment if dashboard not available
if(!InpShowDashboard)
{
string comment = StringFormat(
"ERMT v6.8 | Balance: %.2f | Equity: %.2f | DD: %.2f%% | Trades: %d | P/L: %.2f",
data.balance, data.equity, data.drawdown, data.positions, data.profit
);
Comment(comment);
}
}
//+------------------------------------------------------------------+
//| Helper Functions |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Validate Input Parameters |
//+------------------------------------------------------------------+
bool ValidateInputs()
{
if(InpMaxRiskPerTrade <= 0 || InpMaxRiskPerTrade > 10)
{
Print("Invalid MaxRiskPerTrade: must be between 0 and 10");
return false;
}
if(InpMaxDailyLoss <= 0 || InpMaxDailyLoss > 20)
{
Print("Invalid MaxDailyLoss: must be between 0 and 20");
return false;
}
if(InpMaxDrawdown <= 0 || InpMaxDrawdown > 50)
{
Print("Invalid MaxDrawdown: must be between 0 and 50");
return false;
}
if(InpMaxPositions <= 0 || InpMaxPositions > 10)
{
Print("Invalid MaxPositions: must be between 1 and 10");
return false;
}
if(InpRiskRewardMin < 0.5 || InpRiskRewardMin > 10)
{
Print("Invalid RiskRewardMin: must be between 0.5 and 10");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check Trading Conditions |
//+------------------------------------------------------------------+
bool CheckTradingConditions()
{
// Check if auto trading is enabled
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
return false;
// Check if EA trading is enabled
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
return false;
// Check if market is open
if(!g_utils.IsMarketOpen())
return false;
// Check trading hours
if(InpUseTradeHours)
{
MqlDateTime current;
TimeToStruct(TimeCurrent(), current);
if(current.hour < InpStartHour || current.hour >= InpEndHour)
return false;
}
// Check spread
double max_spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * 3;
if(g_current_spread > max_spread)
{
g_utils.Log(StringFormat("Spread too high: %.1f > %.1f",
g_current_spread, max_spread), LOG_DEBUG);
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check Friday Close |
//+------------------------------------------------------------------+
bool CheckFridayClose()
{
MqlDateTime current;
TimeToStruct(TimeCurrent(), current);
if(current.day_of_week == 5 && current.hour >= InpFridayCloseHour)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Close All Positions |
//+------------------------------------------------------------------+
void CloseAllPositions(string reason)
{
g_utils.Log(StringFormat("Closing all positions: %s", reason), LOG_WARNING);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
{
g_trade.CloseTrade(ticket, reason);
}
}
}
//+------------------------------------------------------------------+
//| Check System Health |
//+------------------------------------------------------------------+
void CheckSystemHealth()
{
// Check connection
if(!TerminalInfoInteger(TERMINAL_CONNECTED))
{
g_utils.Log("Terminal disconnected", LOG_ERROR);
return;
}
// Check memory usage
int memory_used = TerminalInfoInteger(TERMINAL_MEMORY_USED);
int memory_available = TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE);
if(memory_available < 100) // Less than 100MB available
{
g_utils.Log(StringFormat("Low memory warning: %d MB available", memory_available), LOG_WARNING);
}
// Check CPU usage (simplified)
if(g_tick_count > 0 && g_utils.GetElapsedTime() > 500)
{
g_utils.Log("High CPU usage detected", LOG_WARNING);
}
}
//+------------------------------------------------------------------+
//| Log Configuration |
//+------------------------------------------------------------------+
void LogConfiguration()
{
g_utils.Log("=== ERMT v6.8 Configuration ===", LOG_INFO);
g_utils.Log(StringFormat("Symbol: %s", _Symbol), LOG_INFO);
g_utils.Log(StringFormat("Timeframe: %s", g_utils.TimeframeToString(Period())), LOG_INFO);
g_utils.Log(StringFormat("Magic Number: %d", InpMagicNumber), LOG_INFO);
g_utils.Log(StringFormat("Risk per trade: %.2f%%", InpMaxRiskPerTrade), LOG_INFO);
g_utils.Log(StringFormat("Max daily loss: %.2f%%", InpMaxDailyLoss), LOG_INFO);
g_utils.Log(StringFormat("Max drawdown: %.2f%%", InpMaxDrawdown), LOG_INFO);
g_utils.Log(StringFormat("Max positions: %d", InpMaxPositions), LOG_INFO);
g_utils.Log(StringFormat("Sizing method: %d", InpSizingMethod), LOG_INFO);
g_utils.Log(StringFormat("Manage external: %s", InpManageExternal ? "Yes" : "No"), LOG_INFO);
g_utils.Log(StringFormat("Starting balance: %.2f", g_starting_balance), LOG_INFO);
g_utils.Log("================================", LOG_INFO);
}
//+------------------------------------------------------------------+
//| Log Status |
//+------------------------------------------------------------------+
void LogStatus()
{
PerformanceMetrics metrics;
g_trade.GetPerformanceMetrics(metrics);
g_utils.Log(StringFormat(
"Status: Bal=%.2f Eq=%.2f Pos=%d/%d Risk=%.2f%% DD=%.2f%% P/L=%.2f",
AccountInfoDouble(ACCOUNT_BALANCE),
AccountInfoDouble(ACCOUNT_EQUITY),
g_trade.GetOpenTradeCount(),
InpMaxPositions,
g_risk.GetCurrentRiskLevel(),
g_risk.GetCurrentDrawdown(),
g_session_profit
), LOG_INFO);
}
//+------------------------------------------------------------------+
//| Save Performance Snapshot |
//+------------------------------------------------------------------+
void SavePerformanceSnapshot(const PerformanceMetrics &metrics)
{
string filename = StringFormat("ERMT_Snapshot_%s.csv",
TimeToString(TimeCurrent(), TIME_DATE));
// Prepare CSV content
string content = StringFormat(
"%s,%.2f,%.2f,%.2f,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%.2f\n",
TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES),
AccountInfoDouble(ACCOUNT_BALANCE),
AccountInfoDouble(ACCOUNT_EQUITY),
metrics.total_profit,
metrics.total_trades,
metrics.winning_trades,
metrics.losing_trades,
metrics.win_rate,
metrics.profit_factor,
metrics.max_drawdown,
metrics.sharpe_ratio,
g_risk.GetCurrentRiskLevel()
);
// Append to file
int handle = FileOpen(filename, FILE_READ|FILE_WRITE|FILE_CSV);
if(handle != INVALID_HANDLE)
{
FileSeek(handle, 0, SEEK_END);
FileWriteString(handle, content);
FileClose(handle);
}
}
//+------------------------------------------------------------------+
//| Market Condition to String |
//+------------------------------------------------------------------+
string MarketConditionToString(ENUM_MARKET_CONDITION condition)
{
switch(condition)
{
case MARKET_TRENDING_UP: return "Trending Up";
case MARKET_TRENDING_DOWN: return "Trending Down";
case MARKET_RANGING: return "Ranging";
case MARKET_VOLATILE: return "Volatile";
case MARKET_QUIET: return "Quiet";
case MARKET_BREAKOUT: return "Breakout";
case MARKET_REVERSAL: return "Reversal";
default: return "Unknown";
}
}
//+------------------------------------------------------------------+
//| Get Deinitialization Reason Text |
//+------------------------------------------------------------------+
string GetDeInitReasonText(int reason)
{
switch(reason)
{
case REASON_PROGRAM: return "Program terminated";
case REASON_REMOVE: return "Removed from chart";
case REASON_RECOMPILE: return "Recompiled";
case REASON_CHARTCHANGE: return "Chart changed";
case REASON_CHARTCLOSE: return "Chart closed";
case REASON_PARAMETERS: return "Parameters changed";
case REASON_ACCOUNT: return "Account changed";
case REASON_TEMPLATE: return "Template applied";
case REASON_INITFAILED: return "Initialization failed";
case REASON_CLOSE: return "Terminal closed";
default: return StringFormat("Unknown (%d)", reason);
}
}
//+------------------------------------------------------------------+
//| Cleanup Function |
//+------------------------------------------------------------------+
void Cleanup()
{
if(g_dashboard != NULL)
{
delete g_dashboard;
g_dashboard = NULL;
}
if(g_trade != NULL)
{
delete g_trade;
g_trade = NULL;
}
if(g_external != NULL)
{
delete g_external;
g_external = NULL;
}
if(g_tech != NULL)
{
delete g_tech;
g_tech = NULL;
}
if(g_risk != NULL)
{
delete g_risk;
g_risk = NULL;
}
if(g_utils != NULL)
{
g_utils.CloseExternalLog();
delete g_utils;
g_utils = NULL;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+