//+------------------------------------------------------------------+ //| util_ExportCandlesToCSV.mq5 | //| Copyright 2025, xxxxxxxx | //| | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #property link "" #property version "2.00" // Refactored into a class-based structure #property script_show_inputs #property description "Exports historical candle data for the current chart to a CSV file." #property description "The file is saved in the terminal's MQL5/Files/ folder." //--- Input Parameters --- input int InpCandlesToExport = 1000; // Number of most recent candles to export input string InpFileName = ""; // CSV file name. If empty, it will be auto-generated. input string InpDelimiter = ","; // Delimiter for the CSV file (e.g., comma or semicolon) //+------------------------------------------------------------------+ //| CCandleExporter Class | //| Encapsulates all logic for exporting candle data to a CSV file. | //+------------------------------------------------------------------+ class CCandleExporter { private: //--- Export settings int m_candles_to_export; string m_file_name; char m_delimiter; string m_symbol; ENUM_TIMEFRAMES m_period; //--- Internal state int m_file_handle; public: //--- Constructor CCandleExporter(int candles, string file_name, string delimiter); //--- Destructor ~CCandleExporter(void); //--- Main execution method bool Run(void); private: //--- Helper methods bool PrepareFileName(void); bool OpenFile(void); int CopyData(MqlRates &rates[]); bool WriteData(const MqlRates &rates[], int count); void CloseFile(void); }; //+------------------------------------------------------------------+ //| Constructor: Initializes the exporter with settings | //+------------------------------------------------------------------+ CCandleExporter::CCandleExporter(int candles, string file_name, string delimiter) { m_candles_to_export = (candles > 0) ? candles : 1; m_file_name = file_name; m_delimiter = (char)StringGetCharacter(delimiter, 0); m_symbol = _Symbol; m_period = _Period; m_file_handle = INVALID_HANDLE; } //+------------------------------------------------------------------+ //| Destructor: Ensures the file is always closed | //+------------------------------------------------------------------+ CCandleExporter::~CCandleExporter(void) { CloseFile(); } //+------------------------------------------------------------------+ //| Main execution method | //+------------------------------------------------------------------+ bool CCandleExporter::Run(void) { if(!PrepareFileName()) return false; if(!OpenFile()) return false; MqlRates rates[]; int copied_count = CopyData(rates); if(copied_count <= 0) { CloseFile(); return false; } if(!WriteData(rates, copied_count)) { CloseFile(); return false; } CloseFile(); PrintFormat("Successfully exported %d candles to '%s'.", copied_count, m_file_name); Print("You can find the file in the terminal's Data Folder under MQL5/Files/."); return true; } //+------------------------------------------------------------------+ //| Prepares and validates the file name | //+------------------------------------------------------------------+ bool CCandleExporter::PrepareFileName(void) { if(m_file_name == "") { m_file_name = StringFormat("%s_%s_Candles.csv", m_symbol, EnumToString(m_period)); } if(StringFind(m_file_name, ".csv", StringLen(m_file_name) - 4) == -1) { m_file_name += ".csv"; } PrintFormat("Starting export of %d candles for %s on %s...", m_candles_to_export, m_symbol, EnumToString(m_period)); PrintFormat("Target file: MQL5\\Files\\%s", m_file_name); return true; } //+------------------------------------------------------------------+ //| Opens the target file for writing | //+------------------------------------------------------------------+ bool CCandleExporter::OpenFile(void) { ResetLastError(); m_file_handle = FileOpen(m_file_name, FILE_WRITE | FILE_CSV | FILE_ANSI, m_delimiter); if(m_file_handle == INVALID_HANDLE) { PrintFormat("Error opening file '%s'. Error code: %d", m_file_name, GetLastError()); return false; } return true; } //+------------------------------------------------------------------+ //| Copies historical rate data from the terminal | //+------------------------------------------------------------------+ int CCandleExporter::CopyData(MqlRates &rates[]) { ArraySetAsSeries(rates, false); int copied_count = CopyRates(m_symbol, m_period, 0, m_candles_to_export, rates); if(copied_count <= 0) { PrintFormat("Error: Could not copy any candle data. Error code: %d", GetLastError()); return 0; } if(copied_count < m_candles_to_export) { PrintFormat("Warning: Could only copy %d candles, less than the requested %d.", copied_count, m_candles_to_export); } return copied_count; } //+------------------------------------------------------------------+ //| Writes the header and candle data to the opened CSV file | //+------------------------------------------------------------------+ bool CCandleExporter::WriteData(const MqlRates &rates[], int count) { FileWrite(m_file_handle, "time", "open", "high", "low", "close", "tick_volume", "real_volume", "spread"); for(int i = 0; i < count; i++) { string time_str = TimeToString(rates[i].time, TIME_DATE | TIME_MINUTES | TIME_SECONDS); FileWrite(m_file_handle, time_str, rates[i].open, rates[i].high, rates[i].low, rates[i].close, rates[i].tick_volume, rates[i].real_volume, rates[i].spread); } return true; } //+------------------------------------------------------------------+ //| Closes the file handle if it's open | //+------------------------------------------------------------------+ void CCandleExporter::CloseFile(void) { if(m_file_handle != INVALID_HANDLE) { FileClose(m_file_handle); m_file_handle = INVALID_HANDLE; } } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { CCandleExporter exporter(InpCandlesToExport, InpFileName, InpDelimiter); exporter.Run(); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+