228 Zeilen
8,4 KiB
MQL5
228 Zeilen
8,4 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void TerminalAutoTrading(bool enable)
|
|
{
|
|
//---
|
|
const bool e = (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED);
|
|
if(e == enable)
|
|
return;
|
|
|
|
//---
|
|
HANDLE hwnd = MTTESTER::GetTerminalHandle();
|
|
if(!hwnd)
|
|
return;
|
|
//---
|
|
user32::SetForegroundWindow(hwnd);
|
|
Sleep(50);
|
|
|
|
//---
|
|
user32::keybd_event(0x11, 0, 0, 0);
|
|
user32::keybd_event(0x45, 0, 0, 0);
|
|
user32::keybd_event(0x45, 0, 2, 0);
|
|
user32::keybd_event(0x11, 0, 2, 0);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
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);
|
|
const string log_file_path = StringFormat("%s\\MQL5\\Logs\\%04d%02d%02d.log", TerminalInfoString(TERMINAL_DATA_PATH), dt.year, dt.mon, dt.day);
|
|
|
|
//--- 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);
|
|
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);
|
|
|
|
//--- Convertimos saltando BOM
|
|
const string content = ShortArrayToString(buffer, 1);
|
|
string lines[];
|
|
const int total_lines = StringSplit(content, '\n', lines);
|
|
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
|
|
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;
|
|
|
|
//---
|
|
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);
|
|
const string log_file_path = StringFormat("%s\\MQL5\\Logs\\%04d%02d%02d.log", TerminalInfoString(TERMINAL_DATA_PATH), dt.year, dt.mon, dt.day);
|
|
|
|
//--- 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);
|
|
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);
|
|
|
|
//--- Convertimos saltando BOM
|
|
const string content = ShortArrayToString(buffer, 1);
|
|
string lines[];
|
|
const int total_lines = StringSplit(content, '\n', lines);
|
|
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;
|
|
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
|
|
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;
|
|
|
|
//---
|
|
if(secs >= start_secs && secs <= end_secs)
|
|
{
|
|
str += lines[i] + sep;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
#endif // MQLARTICLES_UTILS_EXTRAFUNCTIONS_MQH
|