mql5/Experts/Advisors/ERMT_6.8.mq5
darashikoh 74a75d3681 revert 06e7431edc
Revert to functional ERMT6.8 with modules detailed in main EA. Working file. Upgrades to ERMT6.9 fundamentally flawed due to EA missing references to all modules. Branched out for WiP
2025-09-02 09:20:47 +00:00

1113 lines
No EOL
38 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"
#include "Modules/Dashboard_SelfContained.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 = clrWhite; // Dashboard Text 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;
CDashboardSC* Dashboard = NULL; // That's it! No color variables needed
// 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);
}
}
// Session initialization
g_session_start = TimeCurrent();
g_starting_balance = AccountInfoDouble(ACCOUNT_BALANCE);
g_last_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
g_initialized = true;
// 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;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+