//+------------------------------------------------------------------+ //| Utilities_v71.mqh | //| Enhanced Utilities Module v7.1 | //| Optimized Logging, Performance Tools, Helpers | //+------------------------------------------------------------------+ #ifndef UTILITIES_V71_MQH #define UTILITIES_V71_MQH #include "DataTypes_v71.mqh" #include #include //+------------------------------------------------------------------+ //| Performance Timer | //+------------------------------------------------------------------+ struct PerformanceTimer { string name; ulong start_time; ulong total_time; int call_count; double avg_time_ms; double max_time_ms; double min_time_ms; }; //+------------------------------------------------------------------+ //| Log Entry | //+------------------------------------------------------------------+ struct LogEntry { datetime timestamp; ENUM_LOG_LEVEL level; string source; string message; int error_code; }; //+------------------------------------------------------------------+ //| Utilities Class - Enhanced Version | //+------------------------------------------------------------------+ class CUtilitiesV71 { private: //--- Configuration ENUM_LOG_LEVEL m_log_level; bool m_is_testing; bool m_ultra_low_latency; string m_log_filename; string m_report_filename; //--- Performance monitoring PerformanceTimer m_timers[]; int m_timer_count; //--- Log buffer for low latency mode LogEntry m_log_buffer[]; int m_log_buffer_size; int m_log_write_index; bool m_buffered_logging; //--- File handles int m_log_handle; int m_report_handle; //--- Memory pool for string operations string m_string_pool[]; int m_string_pool_size; //--- Helper methods string GetLogPrefix(ENUM_LOG_LEVEL level); void WriteLogEntry(const LogEntry &entry); void FlushLogBuffer(); public: CUtilitiesV71(); ~CUtilitiesV71(); //--- Initialization bool Initialize(ENUM_LOG_LEVEL level); bool InitializeOptimized(ENUM_LOG_LEVEL level, bool ultra_low_latency); //--- Logging with minimal overhead void Log(ENUM_LOG_LEVEL level, string message); void LogOptimized(ENUM_LOG_LEVEL level, string message); void LogError(string function, int error_code); void LogTrade(const ManagedTradeV71 &trade, string action); void LogPerformance(string operation, double time_ms); //--- Performance monitoring void StartTimer(string name); void StopTimer(string name); double GetAverageTime(string name); void ReportTimings(); //--- Terminal and connection checks bool CheckTerminalConnection(); bool CheckAutoTradingEnabled(); bool IsTradingAllowed(); bool IsMarketClosed(string symbol); //--- Time utilities bool IsAsianSession(); bool IsEuropeanSession(); bool IsAmericanSession(); bool IsNewsTime(string symbol); int GetMarketSession(); //--- Mathematical utilities double NormalizeVolume(string symbol, double volume); double NormalizePricepredictable(string symbol, double price); double CalculateCommission(ulong ticket); double CalculateCommissionOptimized(ulong ticket); double GetSpreadCost(string symbol, double volume); //--- String utilities optimized string FormatCurrency(double value); string FormatPercentage(double value, int digits = 2); string FormatDuration(int seconds); string GetUninitReasonText(int reason); //--- File operations void GenerateReport(PerformanceMetricsV71 &performance, ManagedTradeV71 &trades[]); void SaveTradeHistory(const ManagedTradeV71 &trade); void SaveTradeHistoryOptimized(const ManagedTradeV71 &trade); bool LoadConfiguration(string filename); bool SaveConfiguration(string filename); //--- Data export void ExportToCSV(string filename, ManagedTradeV71 &trades[]); void ExportPerformanceMetrics(string filename, PerformanceMetricsV71 &metrics); void ExportRiskMetrics(string filename, SystemStateV71 &state); //--- System utilities void PrintSystemInfo(); int GetCPUCores(); long GetAvailableMemory(); double GetCPUUsage(); //--- Market data utilities double GetSymbolPointValue(string symbol); double GetSymbolTickValue(string symbol, double volume = 1.0); int GetSymbolDigits(string symbol); double ConvertToAccountCurrency(string symbol, double amount); //--- Array utilities (optimized) template void ArrayShuffle(T &array[]); template int ArrayFindMax(const T &array[]); template int ArrayFindMin(const T &array[]); template double ArrayMean(const T &array[]); template double ArrayStdDev(const T &array[]); //--- Notification utilities void SendNotification(string title, string message); void SendEmail(string subject, string body); void PlayAlert(string sound_file); //--- Cleanup void FlushLogs(); void CloseAllFiles(); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CUtilitiesV71::CUtilitiesV71() { m_log_level = LOG_INFO; m_is_testing = MQLInfoInteger(MQL_TESTER); m_ultra_low_latency = false; m_log_filename = "ERMT71_Log.txt"; m_report_filename = "ERMT71_Report.txt"; m_timer_count = 0; m_log_buffer_size = 1000; m_log_write_index = 0; m_buffered_logging = false; m_log_handle = INVALID_HANDLE; m_report_handle = INVALID_HANDLE; m_string_pool_size = 100; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CUtilitiesV71::~CUtilitiesV71() { FlushLogs(); CloseAllFiles(); } //+------------------------------------------------------------------+ //| Initialize with optimization | //+------------------------------------------------------------------+ bool CUtilitiesV71::InitializeOptimized(ENUM_LOG_LEVEL level, bool ultra_low_latency) { m_log_level = level; m_ultra_low_latency = ultra_low_latency; //--- Set up buffered logging for low latency if(m_ultra_low_latency) { m_buffered_logging = true; ArrayResize(m_log_buffer, m_log_buffer_size); ArrayResize(m_string_pool, m_string_pool_size); } //--- Initialize performance timers ArrayResize(m_timers, 20); //--- Open log file if not testing if(!m_is_testing && !m_ultra_low_latency) { m_log_handle = FileOpen(m_log_filename, FILE_WRITE|FILE_TXT|FILE_ANSI|FILE_SHARE_READ); } Log(LOG_INFO, "UtilitiesV71 initialized: UltraLowLatency=" + (string)m_ultra_low_latency); return true; } //+------------------------------------------------------------------+ //| Optimized logging for low latency | //+------------------------------------------------------------------+ void CUtilitiesV71::LogOptimized(ENUM_LOG_LEVEL level, string message) { if(level < m_log_level) return; if(m_buffered_logging) { //--- Add to buffer LogEntry entry; entry.timestamp = TimeCurrent(); entry.level = level; entry.source = "ERMT71"; entry.message = message; entry.error_code = 0; m_log_buffer[m_log_write_index] = entry; m_log_write_index = (m_log_write_index + 1) % m_log_buffer_size; //--- Flush buffer if critical if(level >= LOG_ERROR) FlushLogBuffer(); } else { Log(level, message); } } //+------------------------------------------------------------------+ //| Standard logging | //+------------------------------------------------------------------+ void CUtilitiesV71::Log(ENUM_LOG_LEVEL level, string message) { if(level < m_log_level) return; string log_entry = TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + " " + GetLogPrefix(level) + " " + message; //--- Print to terminal if(level >= LOG_WARNING) Print(log_entry); //--- Write to file if not testing if(!m_is_testing && m_log_handle != INVALID_HANDLE) { FileWrite(m_log_handle, log_entry); FileFlush(m_log_handle); } } //+------------------------------------------------------------------+ //| Get log level prefix | //+------------------------------------------------------------------+ string CUtilitiesV71::GetLogPrefix(ENUM_LOG_LEVEL level) { switch(level) { case LOG_DEBUG: return "[DEBUG]"; case LOG_INFO: return "[INFO ]"; case LOG_WARNING: return "[WARN ]"; case LOG_ERROR: return "[ERROR]"; case LOG_CRITICAL: return "[CRIT ]"; default: return "[?????]"; } } //+------------------------------------------------------------------+ //| Flush log buffer to file | //+------------------------------------------------------------------+ void CUtilitiesV71::FlushLogBuffer() { if(!m_buffered_logging || m_is_testing) return; //--- Open file if needed if(m_log_handle == INVALID_HANDLE) { m_log_handle = FileOpen(m_log_filename, FILE_WRITE|FILE_TXT|FILE_ANSI|FILE_SHARE_READ); if(m_log_handle == INVALID_HANDLE) return; } //--- Write all buffered entries for(int i = 0; i < m_log_buffer_size; i++) { if(m_log_buffer[i].timestamp > 0) { WriteLogEntry(m_log_buffer[i]); m_log_buffer[i].timestamp = 0; // Clear entry } } FileFlush(m_log_handle); } //+------------------------------------------------------------------+ //| Write single log entry | //+------------------------------------------------------------------+ void CUtilitiesV71::WriteLogEntry(const LogEntry &entry) { if(m_log_handle == INVALID_HANDLE) return; string log_line = TimeToString(entry.timestamp, TIME_DATE|TIME_SECONDS) + " " + GetLogPrefix(entry.level) + " [" + entry.source + "] " + entry.message; if(entry.error_code != 0) log_line += " (Error: " + IntegerToString(entry.error_code) + ")"; FileWrite(m_log_handle, log_line); } //+------------------------------------------------------------------+ //| Start performance timer | //+------------------------------------------------------------------+ void CUtilitiesV71::StartTimer(string name) { //--- Find existing timer int index = -1; for(int i = 0; i < m_timer_count; i++) { if(m_timers[i].name == name) { index = i; break; } } //--- Create new timer if not found if(index < 0) { if(m_timer_count >= ArraySize(m_timers)) ArrayResize(m_timers, m_timer_count + 10); index = m_timer_count; m_timers[index].name = name; m_timers[index].total_time = 0; m_timers[index].call_count = 0; m_timers[index].avg_time_ms = 0; m_timers[index].max_time_ms = 0; m_timers[index].min_time_ms = DBL_MAX; m_timer_count++; } //--- Start timing m_timers[index].start_time = GetMicrosecondCount(); } //+------------------------------------------------------------------+ //| Stop performance timer | //+------------------------------------------------------------------+ void CUtilitiesV71::StopTimer(string name) { //--- Find timer for(int i = 0; i < m_timer_count; i++) { if(m_timers[i].name == name) { //--- Calculate elapsed time ulong elapsed = GetMicrosecondCount() - m_timers[i].start_time; double elapsed_ms = elapsed / 1000.0; //--- Update statistics m_timers[i].total_time += elapsed; m_timers[i].call_count++; m_timers[i].avg_time_ms = (m_timers[i].total_time / 1000.0) / m_timers[i].call_count; if(elapsed_ms > m_timers[i].max_time_ms) m_timers[i].max_time_ms = elapsed_ms; if(elapsed_ms < m_timers[i].min_time_ms) m_timers[i].min_time_ms = elapsed_ms; break; } } } //+------------------------------------------------------------------+ //| Get average execution time | //+------------------------------------------------------------------+ double CUtilitiesV71::GetAverageTime(string name) { for(int i = 0; i < m_timer_count; i++) { if(m_timers[i].name == name) return m_timers[i].avg_time_ms; } return 0; } //+------------------------------------------------------------------+ //| Report all timings | //+------------------------------------------------------------------+ void CUtilitiesV71::ReportTimings() { Log(LOG_INFO, "=== Performance Report ==="); for(int i = 0; i < m_timer_count; i++) { string report = StringFormat("%s: Calls=%d, Avg=%.3fms, Min=%.3fms, Max=%.3fms", m_timers[i].name, m_timers[i].call_count, m_timers[i].avg_time_ms, m_timers[i].min_time_ms, m_timers[i].max_time_ms); Log(LOG_INFO, report); } } //+------------------------------------------------------------------+ //| Check terminal connection | //+------------------------------------------------------------------+ bool CUtilitiesV71::CheckTerminalConnection() { if(!TerminalInfoInteger(TERMINAL_CONNECTED)) { LogOptimized(LOG_WARNING, "Terminal not connected"); return false; } if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { LogOptimized(LOG_WARNING, "Trading not allowed in terminal"); return false; } return true; } //+------------------------------------------------------------------+ //| Check if auto trading is enabled | //+------------------------------------------------------------------+ bool CUtilitiesV71::CheckAutoTradingEnabled() { if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return false; if(!MQLInfoInteger(MQL_TRADE_ALLOWED)) return false; if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT)) return false; if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)) return false; return true; } //+------------------------------------------------------------------+ //| Calculate position commission optimized | //+------------------------------------------------------------------+ double CUtilitiesV71::CalculateCommissionOptimized(ulong ticket) { static ulong last_ticket = 0; static double last_commission = 0; //--- Cache hit if(ticket == last_ticket) return last_commission; double commission = 0; //--- Get deals for position if(HistorySelectByPosition(ticket)) { int deals = HistoryDealsTotal(); for(int i = 0; i < deals; i++) { ulong deal_ticket = HistoryDealGetTicket(i); if(deal_ticket > 0) { commission += HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION); } } } //--- Update cache last_ticket = ticket; last_commission = commission; return commission; } //+------------------------------------------------------------------+ //| Format currency with optimization | //+------------------------------------------------------------------+ string CUtilitiesV71::FormatCurrency(double value) { //--- Use string pool for common values if(value == 0) return "0.00"; string sign = (value < 0) ? "-" : ""; value = MathAbs(value); if(value >= 1000000) return sign + DoubleToString(value/1000000, 2) + "M"; else if(value >= 1000) return sign + DoubleToString(value/1000, 2) + "K"; else return sign + DoubleToString(value, 2); } //+------------------------------------------------------------------+ //| Get market session | //+------------------------------------------------------------------+ int CUtilitiesV71::GetMarketSession() { MqlDateTime time; TimeToStruct(TimeCurrent(), time); int hour = time.hour; //--- Asian session (Tokyo: 00:00 - 09:00 GMT) if(hour >= 0 && hour < 9) return 1; //--- European session (London: 08:00 - 17:00 GMT) if(hour >= 8 && hour < 17) return 2; //--- American session (New York: 13:00 - 22:00 GMT) if(hour >= 13 && hour < 22) return 3; return 0; } //+------------------------------------------------------------------+ //| Generate performance report | //+------------------------------------------------------------------+ void CUtilitiesV71::GenerateReport(PerformanceMetricsV71 &performance, ManagedTradeV71 &trades[]) { string report = "\n"; report += "════════════════════════════════════════════════════════════════\n"; report += " ERMT 7.1 PERFORMANCE REPORT \n"; report += "════════════════════════════════════════════════════════════════\n\n"; //--- Account Summary report += "ACCOUNT SUMMARY\n"; report += "───────────────\n"; report += "Starting Balance: " + FormatCurrency(AccountInfoDouble(ACCOUNT_BALANCE) - performance.net_profit) + "\n"; report += "Current Balance: " + FormatCurrency(AccountInfoDouble(ACCOUNT_BALANCE)) + "\n"; report += "Net Profit: " + FormatCurrency(performance.net_profit) + "\n"; report += "Return: " + FormatPercentage((performance.net_profit / (AccountInfoDouble(ACCOUNT_BALANCE) - performance.net_profit)) * 100) + "\n\n"; //--- Performance Metrics report += "PERFORMANCE METRICS\n"; report += "──────────────────\n"; report += "Total Trades: " + IntegerToString(performance.total_trades) + "\n"; report += "Win Rate: " + FormatPercentage(performance.win_rate) + "\n"; report += "Profit Factor: " + DoubleToString(performance.profit_factor, 2) + "\n"; report += "Sharpe Ratio: " + DoubleToString(performance.sharpe_ratio, 2) + "\n"; report += "Sortino Ratio: " + DoubleToString(performance.sortino_ratio, 2) + "\n"; report += "Information Ratio: " + DoubleToString(performance.information_ratio, 2) + "\n\n"; //--- Risk Metrics report += "RISK METRICS\n"; report += "────────────\n"; report += "Max Drawdown: " + FormatPercentage(performance.max_drawdown_percent) + "\n"; report += "VaR (95%): " + FormatPercentage(performance.var_95) + "\n"; report += "CVaR (95%): " + FormatPercentage(performance.cvar_95) + "\n"; report += "Recovery Factor: " + DoubleToString(performance.recovery_factor, 2) + "\n"; report += "Calmar Ratio: " + DoubleToString(performance.calmar_ratio, 2) + "\n\n"; //--- Advanced Metrics report += "ADVANCED METRICS\n"; report += "───────────────\n"; report += "Alpha: " + DoubleToString(performance.alpha, 4) + "\n"; report += "Beta: " + DoubleToString(performance.beta, 2) + "\n"; report += "Treynor Ratio: " + DoubleToString(performance.treynor_ratio, 2) + "\n"; report += "Omega Ratio: " + DoubleToString(performance.omega_ratio, 2) + "\n"; report += "Hit Rate: " + FormatPercentage(performance.hit_rate) + "\n"; report += "Avg Holding Time: " + FormatDuration((int)performance.avg_holding_time) + "\n\n"; //--- Trade Analysis report += "TRADE ANALYSIS\n"; report += "─────────────\n"; report += "Winning Trades: " + IntegerToString(performance.winning_trades) + "\n"; report += "Losing Trades: " + IntegerToString(performance.losing_trades) + "\n"; report += "Average Win: " + FormatCurrency(performance.avg_win) + "\n"; report += "Average Loss: " + FormatCurrency(performance.avg_loss) + "\n"; report += "Largest Win: " + FormatCurrency(performance.largest_win) + "\n"; report += "Largest Loss: " + FormatCurrency(performance.largest_loss) + "\n"; report += "Max Consec Wins: " + IntegerToString(performance.max_consecutive_wins) + "\n"; report += "Max Consec Losses: " + IntegerToString(performance.max_consecutive_losses) + "\n\n"; //--- Current Positions int trade_count = ArraySize(trades); if(trade_count > 0) { report += "CURRENT POSITIONS\n"; report += "────────────────\n"; report += "Symbol Type Volume Entry Current P/L Risk% R-Mult\n"; report += "─────────────────────────────────────────────────────────────────\n"; for(int i = 0; i < trade_count && i < 10; i++) { double current_price = (trades[i].type == POSITION_TYPE_BUY) ? SymbolInfoDouble(trades[i].symbol, SYMBOL_BID) : SymbolInfoDouble(trades[i].symbol, SYMBOL_ASK); report += StringFormat("%-8s %-5s %6.2f %7.5f %7.5f %-8s %5.1f %6.2f\n", trades[i].symbol, (trades[i].type == POSITION_TYPE_BUY) ? "BUY" : "SELL", trades[i].volume, trades[i].open_price, current_price, FormatCurrency(trades[i].profit), trades[i].risk_percent, trades[i].r_multiple); } report += "\n"; } //--- Performance timings if(m_timer_count > 0) { report += "PERFORMANCE TIMINGS\n"; report += "──────────────────\n"; for(int i = 0; i < m_timer_count && i < 5; i++) { report += StringFormat("%-20s: %6.3f ms (avg), %d calls\n", m_timers[i].name, m_timers[i].avg_time_ms, m_timers[i].call_count); } report += "\n"; } report += "════════════════════════════════════════════════════════════════\n"; report += "Report generated: " + TimeToString(TimeCurrent()) + "\n"; report += "════════════════════════════════════════════════════════════════\n"; //--- Output report if(m_is_testing) { Print(report); } else { //--- Save to file int handle = FileOpen(m_report_filename, FILE_WRITE|FILE_TXT|FILE_ANSI); if(handle != INVALID_HANDLE) { FileWrite(handle, report); FileClose(handle); Log(LOG_INFO, "Performance report saved to " + m_report_filename); } } } //+------------------------------------------------------------------+ //| Save trade history optimized | //+------------------------------------------------------------------+ void CUtilitiesV71::SaveTradeHistoryOptimized(const ManagedTradeV71 &trade) { if(m_is_testing) return; string filename = "TradeHistory_" + trade.symbol + ".csv"; //--- Check if file exists bool file_exists = FileIsExist(filename); int handle = FileOpen(filename, FILE_WRITE|FILE_CSV|FILE_ANSI|FILE_SHARE_READ, ','); if(handle == INVALID_HANDLE) return; //--- Write header if new file if(!file_exists) { FileWrite(handle, "Ticket", "Symbol", "Type", "OpenTime", "CloseTime", "OpenPrice", "ClosePrice", "Volume", "Profit", "Commission", "Swap", "RMultiple", "MAE", "MFE", "VaR", "MLConfidence", "ExecutionQuality", "EntryAlgo", "Comment"); } //--- Move to end FileSeek(handle, 0, SEEK_END); //--- Write trade data FileWrite(handle, trade.ticket, trade.symbol, (trade.type == POSITION_TYPE_BUY) ? "BUY" : "SELL", TimeToString(trade.open_time), TimeToString(TimeCurrent()), trade.open_price, (trade.type == POSITION_TYPE_BUY) ? SymbolInfoDouble(trade.symbol, SYMBOL_BID) : SymbolInfoDouble(trade.symbol, SYMBOL_ASK), trade.volume, trade.profit, trade.commission, trade.swap, trade.r_multiple, trade.mae, trade.mfe, trade.var_contribution, trade.ml_confidence, trade.execution_quality, trade.entry_algo, trade.comment); FileClose(handle); } //+------------------------------------------------------------------+ //| Format percentage | //+------------------------------------------------------------------+ string CUtilitiesV71::FormatPercentage(double value, int digits) { return DoubleToString(value, digits) + "%"; } //+------------------------------------------------------------------+ //| Format duration | //+------------------------------------------------------------------+ string CUtilitiesV71::FormatDuration(int seconds) { if(seconds < 60) return IntegerToString(seconds) + "s"; else if(seconds < 3600) return IntegerToString(seconds/60) + "m " + IntegerToString(seconds%60) + "s"; else if(seconds < 86400) return IntegerToString(seconds/3600) + "h " + IntegerToString((seconds%3600)/60) + "m"; else return IntegerToString(seconds/86400) + "d " + IntegerToString((seconds%86400)/3600) + "h"; } //+------------------------------------------------------------------+ //| Print system information | //+------------------------------------------------------------------+ void CUtilitiesV71::PrintSystemInfo() { Print("=== SYSTEM INFORMATION ==="); Print("Terminal Build: ", TerminalInfoInteger(TERMINAL_BUILD)); Print("CPU Cores: ", GetCPUCores()); Print("Available Memory: ", GetAvailableMemory() / (1024*1024), " MB"); Print("Screen DPI: ", TerminalInfoInteger(TERMINAL_SCREEN_DPI)); Print("Max Bars: ", TerminalInfoInteger(TERMINAL_MAXBARS)); Print("Code Page: ", TerminalInfoInteger(TERMINAL_CODEPAGE)); Print("Community Account: ", TerminalInfoInteger(TERMINAL_COMMUNITY_ACCOUNT) ? "Yes" : "No"); Print("Connected: ", TerminalInfoInteger(TERMINAL_CONNECTED) ? "Yes" : "No"); Print("Trade Allowed: ", TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) ? "Yes" : "No"); } //+------------------------------------------------------------------+ //| Get CPU cores | //+------------------------------------------------------------------+ int CUtilitiesV71::GetCPUCores() { return (int)TerminalInfoInteger(TERMINAL_CPU_CORES); } //+------------------------------------------------------------------+ //| Get available memory | //+------------------------------------------------------------------+ long CUtilitiesV71::GetAvailableMemory() { return TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE); } //+------------------------------------------------------------------+ //| Array mean calculation | //+------------------------------------------------------------------+ template double CUtilitiesV71::ArrayMean(const T &array[]) { int size = ArraySize(array); if(size == 0) return 0; double sum = 0; for(int i = 0; i < size; i++) sum += array[i]; return sum / size; } //+------------------------------------------------------------------+ //| Array standard deviation | //+------------------------------------------------------------------+ template double CUtilitiesV71::ArrayStdDev(const T &array[]) { int size = ArraySize(array); if(size <= 1) return 0; double mean = ArrayMean(array); double sum_sq = 0; for(int i = 0; i < size; i++) sum_sq += MathPow(array[i] - mean, 2); return MathSqrt(sum_sq / (size - 1)); } //+------------------------------------------------------------------+ //| Close all files | //+------------------------------------------------------------------+ void CUtilitiesV71::CloseAllFiles() { if(m_log_handle != INVALID_HANDLE) { FileClose(m_log_handle); m_log_handle = INVALID_HANDLE; } if(m_report_handle != INVALID_HANDLE) { FileClose(m_report_handle); m_report_handle = INVALID_HANDLE; } } //+------------------------------------------------------------------+ //| Flush all logs | //+------------------------------------------------------------------+ void CUtilitiesV71::FlushLogs() { if(m_buffered_logging) FlushLogBuffer(); if(m_log_handle != INVALID_HANDLE) FileFlush(m_log_handle); } //+------------------------------------------------------------------+ //| Standard initialization (compatibility) | //+------------------------------------------------------------------+ bool CUtilitiesV71::Initialize(ENUM_LOG_LEVEL level) { return InitializeOptimized(level, false); } #endif // UTILITIES_V71_MQH