2026-03-10 15:27:47 -05:00 | | | //+------------------------------------------------------------------+
|
2026-03-09 16:35:08 -05:00 | | | //| ExtraFunctions.mqh |
|
| | | //| Copyright 2025, Niquel Mendoza. |
|
| | | //| https://www.mql5.com/es/users/nique_372 |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2025, Niquel Mendoza."
|
| | | #property link "https://www.mql5.com/es/users/nique_372"
|
| | | #property strict
|
| | |
|
| | | #ifndef MQLARTICLES_UTILS_EXTRAFUNCTIONS_MQH
|
| | | #define MQLARTICLES_UTILS_EXTRAFUNCTIONS_MQH
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #include "..\\..\\ExtraCodes\\MultiTester\\MTTester.mqh"
|
| | | #include "Basic.mqh"
|
2026-03-10 15:27:47 -05:00 | | | #include "File.mqh"
|
2026-03-09 16:35:08 -05:00 | | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void ExtractLogLinesAsArray(const datetime log_file_date, const datetime start_dt, const datetime end_dt, string& arr_lines[])
|
| | | {
|
| | | //--- Path al log de hoy
|
| | | static MqlDateTime dt;
|
| | | CTimeUtils::TimeToStructFast(log_file_date, dt);
|
2026-03-19 18:23:16 -05:00 | | | const string log_file_path = StringFormat("%s\\MQL5\\Logs\\%04d%02d%02d.log", TERMINAL_MT5_DATA_PAH, dt.year, dt.mon, dt.day);
|
2026-03-09 16:35:08 -05:00 | | |
|
| | | //--- Abrimos via WinAPI
|
| | | const HANDLE h = kernel32::CreateFileW(log_file_path,
|
| | | 0x80000000, // GENERIC_READ
|
| | | 0x00000001 | 0x00000002, // FILE_SHARE_READ | FILE_SHARE_WRITE
|
| | | NULL,
|
| | | 3, // OPEN_EXISTING
|
| | | 0x80, // FILE_ATTRIBUTE_NORMAL
|
| | | 0);
|
| | | if(h == -1)
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("No se pudo abrir el archivo, error=%d, file:\n%s", kernel32::GetLastError(), log_file_path));
|
| | | return;
|
| | | }
|
| | |
|
| | | //--- Tamanio
|
| | | long file_size = 0;
|
| | | if(!kernel32::GetFileSizeEx(h, file_size) || file_size <= 2)
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("Archivo vacio o fallo GetFileSizeEx | error=%d", kernel32::GetLastError()));
|
| | | kernel32::CloseHandle(h);
|
| | | return;
|
| | | }
|
| | |
|
| | | //--- Leemos
|
| | | const uint num_shorts = uint(file_size >> 1);
|
2026-03-19 18:23:16 -05:00 | | | ushort buffer[];
|
2026-03-09 16:35:08 -05:00 | | | ArrayResize(buffer, num_shorts);
|
2026-03-19 18:23:16 -05:00 | | | uint bytes_read = 0;
|
| | | OVERLAPPED ov = {};
|
2026-03-09 16:35:08 -05:00 | | | if(!kernel32::ReadFile(h, buffer, (uint)file_size, bytes_read, ov))
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("kernel32::ReadFile | error=%d", kernel32::GetLastError()));
|
| | | kernel32::CloseHandle(h);
|
| | | return;
|
| | | }
|
| | | kernel32::CloseHandle(h);
|
| | |
|
| | | //--- Convertimos saltando BOM
|
2026-03-19 18:23:16 -05:00 | | | const string content = ShortArrayToString(buffer, 1);
|
| | | string lines[];
|
| | | const int total_lines = StringSplit(content, '\n', lines);
|
2026-03-09 16:35:08 -05:00 | | | ArrayResize(arr_lines, total_lines); // Valor inicial
|
| | | int t = 0;
|
| | |
|
| | | //--- Segundos del dia para comparar
|
| | | static MqlDateTime s_dt;
|
| | | static MqlDateTime e_dt;
|
| | | CTimeUtils::TimeToStructFast(start_dt, s_dt);
|
| | | CTimeUtils::TimeToStructFast(end_dt, e_dt);
|
| | | const int start_secs = s_dt.hour * 3600 + s_dt.min * 60 + s_dt.sec;
|
| | | const int end_secs = e_dt.hour * 3600 + e_dt.min * 60 + e_dt.sec;
|
| | |
|
| | | //--- Iteramos y filtramos
|
| | | int found = 0;
|
| | | for(int i = 0; i < total_lines; i++)
|
| | | {
|
| | | if(StringLen(lines[i]) < 10) // No cumple a cer candidado
|
| | | continue;
|
| | |
|
| | | //--- Buscamos el timestamp dinamicamente por el primer ':'
|
| | | const int colon_pos = StringFind(lines[i], ":");
|
| | | if(colon_pos < 2) // Minimo se reuqiere el 2 por el (HH)
|
| | | continue;
|
| | |
|
| | | //--- Extraemos HH:MM:SS
|
2026-03-19 18:23:16 -05:00 | | | const string ts = StringSubstr(lines[i], colon_pos - 2, 8);
|
| | | const int hh = int(StringSubstr(ts, 0, 2));
|
| | | const int mm = int(StringSubstr(ts, 3, 2));
|
| | | const int ss = int(StringSubstr(ts, 6, 2));
|
| | | const int secs = hh * 3600 + mm * 60 + ss;
|
2026-03-09 16:35:08 -05:00 | | |
|
| | | //---
|
| | | if(secs >= start_secs && secs <= end_secs)
|
| | | {
|
| | | arr_lines[t++] = lines[i];
|
| | | }
|
| | | }
|
| | |
|
| | | //---
|
| | | ArrayResize(arr_lines, t);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void ExtractLogLinesAsStr(const datetime log_file_date, const datetime start_dt, const datetime end_dt, string& str, string sep = "\n")
|
| | | {
|
| | | //--- Path al log de hoy
|
| | | static MqlDateTime dt;
|
| | | CTimeUtils::TimeToStructFast(log_file_date, dt);
|
2026-03-19 18:23:16 -05:00 | | | const string log_file_path = StringFormat("%s\\MQL5\\Logs\\%04d%02d%02d.log", TERMINAL_MT5_DATA_PAH, dt.year, dt.mon, dt.day);
|
2026-03-09 16:35:08 -05:00 | | |
|
| | | //--- Abrimos via WinAPI
|
| | | const HANDLE h = kernel32::CreateFileW(log_file_path,
|
| | | 0x80000000, // GENERIC_READ
|
| | | 0x00000001 | 0x00000002, // FILE_SHARE_READ | FILE_SHARE_WRITE
|
| | | NULL,
|
| | | 3, // OPEN_EXISTING
|
| | | 0x80, // FILE_ATTRIBUTE_NORMAL
|
| | | 0);
|
| | | if(h == -1)
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("No se pudo abrir el archivo, error=%d, file:\n%s", kernel32::GetLastError(), log_file_path));
|
| | | return;
|
| | | }
|
| | |
|
| | | //--- Tamanio
|
| | | long file_size = 0;
|
| | | if(!kernel32::GetFileSizeEx(h, file_size) || file_size <= 2)
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("Archivo vacio o fallo GetFileSizeEx | error=%d", kernel32::GetLastError()));
|
| | | kernel32::CloseHandle(h);
|
| | | return;
|
| | | }
|
| | |
|
| | | //--- Leemos
|
| | | const uint num_shorts = uint(file_size >> 1);
|
2026-03-19 18:23:16 -05:00 | | | ushort buffer[];
|
2026-03-09 16:35:08 -05:00 | | | ArrayResize(buffer, num_shorts);
|
2026-03-19 18:23:16 -05:00 | | | uint bytes_read = 0;
|
| | | OVERLAPPED ov = {};
|
2026-03-09 16:35:08 -05:00 | | | if(!kernel32::ReadFile(h, buffer, (uint)file_size, bytes_read, ov))
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("kernel32::ReadFile | error=%d", kernel32::GetLastError()));
|
| | | kernel32::CloseHandle(h);
|
| | | return;
|
| | | }
|
| | | kernel32::CloseHandle(h);
|
| | |
|
| | | //--- Convertimos saltando BOM
|
2026-03-19 18:23:16 -05:00 | | | const string content = ShortArrayToString(buffer, 1);
|
| | | string lines[];
|
| | | const int total_lines = StringSplit(content, '\n', lines);
|
2026-03-09 16:35:08 -05:00 | | | str = "";
|
| | |
|
| | | //--- Segundos del dia para comparar
|
| | | static MqlDateTime s_dt;
|
| | | static MqlDateTime e_dt;
|
| | | CTimeUtils::TimeToStructFast(start_dt, s_dt);
|
| | | CTimeUtils::TimeToStructFast(end_dt, e_dt);
|
| | | const int start_secs = s_dt.hour * 3600 + s_dt.min * 60 + s_dt.sec;
|
2026-03-19 18:23:16 -05:00 | | | const int end_secs = e_dt.hour * 3600 + e_dt.min * 60 + e_dt.sec;
|
2026-03-09 16:35:08 -05:00 | | |
|
| | | //--- Iteramos y filtramos
|
| | | int found = 0;
|
| | | for(int i = 0; i < total_lines; i++)
|
| | | {
|
| | | if(StringLen(lines[i]) < 10) // No cumple a cer candidado
|
| | | continue;
|
| | |
|
| | | //--- Buscamos el timestamp dinamicamente por el primer ':'
|
| | | const int colon_pos = StringFind(lines[i], ":");
|
| | | if(colon_pos < 2) // Minimo se reuqiere el 2 por el (HH)
|
| | | continue;
|
| | |
|
| | | //--- Extraemos HH:MM:SS
|
2026-03-19 18:23:16 -05:00 | | | const string ts = StringSubstr(lines[i], colon_pos - 2, 8);
|
| | | const int hh = int(StringSubstr(ts, 0, 2));
|
| | | const int mm = int(StringSubstr(ts, 3, 2));
|
| | | const int ss = int(StringSubstr(ts, 6, 2));
|
| | | const int secs = hh * 3600 + mm * 60 + ss;
|
2026-03-09 16:35:08 -05:00 | | |
|
| | | //---
|
| | | if(secs >= start_secs && secs <= end_secs)
|
| | | {
|
| | | str += lines[i] + sep;
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
2026-03-19 18:23:16 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void ExtractLastLogLines(const datetime log_file_date, const int num_lines, string& str, string sep = "\n")
|
| | | {
|
| | | //---
|
| | | static MqlDateTime dt;
|
| | | CTimeUtils::TimeToStructFast(log_file_date, dt);
|
| | | const string log_file_path = StringFormat("%s\\MQL5\\Logs\\%04d%02d%02d.log", TERMINAL_MT5_DATA_PAH, dt.year, dt.mon, dt.day);
|
| | |
|
| | | //---
|
| | | const HANDLE h = kernel32::CreateFileW(log_file_path,
|
| | | 0x80000000,
|
| | | 0x00000001 | 0x00000002,
|
| | | NULL,
|
| | | 3,
|
| | | 0x80,
|
| | | 0);
|
| | | if(h == -1)
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("No se pudo abrir el archivo, error=%d, file:\n%s", kernel32::GetLastError(), log_file_path));
|
| | | return;
|
| | | }
|
2026-03-09 16:35:08 -05:00 | | |
|
2026-03-19 18:23:16 -05:00 | | | //---
|
| | | long file_size = 0;
|
| | | if(!kernel32::GetFileSizeEx(h, file_size) || file_size <= 2)
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("Archivo vacio o fallo GetFileSizeEx | error=%d", kernel32::GetLastError()));
|
| | | kernel32::CloseHandle(h);
|
| | | return;
|
| | | }
|
| | |
|
| | | //---
|
| | | const uint num_shorts = uint(file_size >> 1);
|
| | | ushort buffer[];
|
| | | ArrayResize(buffer, num_shorts);
|
| | | uint bytes_read = 0;
|
| | | OVERLAPPED ov = {};
|
| | | if(!kernel32::ReadFile(h, buffer, (uint)file_size, bytes_read, ov))
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, ERROR_TEXT, StringFormat("kernel32::ReadFile | error=%d", kernel32::GetLastError()));
|
| | | kernel32::CloseHandle(h);
|
| | | return;
|
| | | }
|
| | | kernel32::CloseHandle(h);
|
| | |
|
| | | //---
|
| | | const string content = ShortArrayToString(buffer, 1);
|
| | | string lines[];
|
| | | const int total_lines = StringSplit(content, '\n', lines);
|
| | |
|
| | | //---
|
| | | const int count = MathMin(num_lines, total_lines);
|
| | | const int start = MathMax(0, total_lines - count);
|
| | | str = "";
|
| | |
|
| | | //---
|
| | | for(int i = start; i < total_lines; i++)
|
| | | {
|
| | | if(StringLen(lines[i]) < 10)
|
| | | continue;
|
| | | str += lines[i] + sep;
|
| | | }
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
2026-03-10 15:27:47 -05:00 | | | //+------------------------------------------------------------------+
|
| | | void CloseAllChartsExceptChart(const long chart_no_close)
|
| | | {
|
| | | long chart_id = ::ChartFirst();
|
| | | while(chart_id != -1)
|
| | | {
|
| | | const long next = ::ChartNext(chart_id);
|
| | | if(chart_id != chart_no_close)
|
| | | ::ChartClose(chart_id);
|
| | | chart_id = next;
|
| | | }
|
| | | }
|
| | |
|
2026-03-09 16:35:08 -05:00 | | | //+------------------------------------------------------------------+
|
| | | #endif // MQLARTICLES_UTILS_EXTRAFUNCTIONS_MQH
|