MQLArticles/Utils/MBen/MultiBen.mqh
2026-08-28 17:55:58 -05:00

342 lines
12 KiB
MQL5

//+------------------------------------------------------------------+
//| MultiBen.mqh |
//| Copyright 2026, Niquel Mendoza |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Niquel Mendoza"
#property link "https://www.mql5.com"
#property strict
#ifndef MQLARTICLES_UTILS_MBEN_BASIC_MQH
#define MQLARTICLES_UTILS_MBEN_BASIC_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "..\\FA\\LoggerDef.mqh"
//#define MQLARTICLES_MBEN_ENABLE_FINAL_FLUSH
#ifdef MQLARTICLES_MBEN_ENABLE_FINAL_FLUSH
#include <TSN\\Tables\\Bits.mqh>
#include <TSN\\ExtraCodes\\Func.mqh>
#endif // MQLARTICLES_MBEN_ENABLE_FINAL_FLUSH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#resource "sql_init.sql" as const string g_mqlarticles_mben_sql_init
#resource "sql_insert.sql" as const string g_mqlarticles_mben_sql_insert
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#ifndef MQLARTICLES_MULTIBEN_DATA_SIZE
#define MQLARTICLES_MULTIBEN_DATA_SIZE 10
#endif // MQLARTICLES_MULTIBEN_DATA_SIZE
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CMultiBenchmark
{
public:
CMultiBenchmark(void) {}
~CMultiBenchmark(void) {}
//---- Data
struct TempData
{
string op;
string dataset;
int iter;
ulong total;
};
static TempData s_data[MQLARTICLES_MULTIBEN_DATA_SIZE];
static int s_pos;
//---
static void Add(
const string& op,
const string& dataset,
const int iter,
const ulong elapsed);
//---
// Luego de añadir todo lo finaliza y flushea a la .db
static void Finish(const string& name, const string& run_date, const string& lib_name);
//---
// Esto es especifico en caso se este revisando un .log
// Esto lo que hara es parsear recorrer linea por linea
// Y va ir flusheando datos a la .db
// siguienteod un formato especial
// el print empeiza con [MultiBen&
// Inicio: "[MultiBen& %[NameLib]""
// Datos: "@VALOR"
// Fin: "[MultiBen& $[Tag|DataSet||LibName|Iter]"
static void ParseLogFileTodayFlushDb(const string& name);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CMultiBenchmark::s_pos = 0;
CMultiBenchmark::TempData CMultiBenchmark::s_data[MQLARTICLES_MULTIBEN_DATA_SIZE];
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// elaped=tiempo tardado
// compeditor=nombre del competidor
// op=operacion (parse, etc)
// dataset=nombre del dataset
static void CMultiBenchmark::Add(
const string& op,
const string& dataset,
const int iter,
const ulong elapsed)
{
//--- ejecutamos
s_data[s_pos].op = op;
s_data[s_pos].dataset = dataset;
s_data[s_pos].iter = iter;
s_data[s_pos].total = elapsed;
s_pos++;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
static void CMultiBenchmark::Finish(const string& name, const string& run_date, const string& lib_name)
{
//---
// solo imprimimos
const int sql_handle = DatabaseOpen(name, DATABASE_OPEN_COMMON | DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE);
if(sql_handle == INVALID_HANDLE)
{
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al abrir la db [%s], last err = %d",
name, ::GetLastError()));
return;
}
//--- creamos si no existe
if(!DatabaseExecute(sql_handle, g_mqlarticles_mben_sql_init))
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al crear la tabla db, last err = %d", ::GetLastError()));
return;
}
//--- Iniciamos
::ResetLastError();
if(!DatabaseTransactionBegin(sql_handle))
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al inicar transacion datos al m_sql_handle: ", ::GetLastError()));
return;
}
//---
::ResetLastError();
const int stmt = DatabasePrepare(sql_handle, g_mqlarticles_mben_sql_insert);
if(stmt == INVALID_HANDLE)
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al ejeuctar un preprare de la base de datos, ultimo err = %d",
::GetLastError()));
return;
}
//---
for(int i = 0; i < s_pos; i++)
{
DatabaseReset(stmt);
DatabaseBind(stmt, 0, run_date);
DatabaseBind(stmt, 1, s_data[i].op);
DatabaseBind(stmt, 2, s_data[i].dataset);
DatabaseBind(stmt, 3, lib_name);
DatabaseBind(stmt, 4, s_data[i].iter);
DatabaseBind(stmt, 5, s_data[i].total);
DatabaseRead(stmt);
}
//---
DatabaseFinalize(stmt);
//---
::ResetLastError();
if(!DatabaseTransactionCommit(sql_handle))
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al enviar datos al m_sql_handle: ", ::GetLastError()));
return;
}
//---
DatabaseClose(sql_handle);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
static void CMultiBenchmark::ParseLogFileTodayFlushDb(const string& name)
{
// Bueno por ahora hagamos algo el .log del archivo se lo dan a la ia
// y le dicen:
/*
Hola, me ayudas con algo?
Te dare un .log de registros de una terminal de MT5 en la cual estuve cooriendo
benchamarks necesito que tomes ese .log y recolectes datos.
La idea es la sigueinte
1. Lee de arriba a abajo el .log, por cada linea haz esto:
{
En caso estes en un ciclo:
{
Haz los dos
A. {
1. Indentifica los mensajes que contenga el patron "[MultiBen&" inicialmente, si no existe ve al siguiente
bloque B
2. Luego busca el carcater % si aparece otro carcater ve a B
3. En caso encuentres %
- Significa un "final" de "ciclo", por lo que obtendras el string que esta dentro de los corchetes []
Y buscaras en tus registros ese mismo string (comparas contra lib_name)
En caso lo encuntres eso es un dato completo
lo apeneas al struct final (que harcodearas en MQL5)
Luego de esto lo guardas... y buscaras devuelta el patron "[MultiBen&" pero con % como inicio
}
B. {
1. verifica uqe la linea empieze con @, si no vuelve a la siguiente linea
luego captura el valor numerico.. y ve actulizo tus registros con el menor de todos (aveces por ciclo hay varios..
la idea es quedarse con el menor valor de todos)
}
}
Si no lo estas
{
1. Indentifica los mensajes que contenga el patron "[MultiBen&" inicialmente, ahora si no existe saltate al paso 4:
2. Luego busca el carcater $ si aparece otro carcater descarta esa linea
En caso encuentres
- Se inicia un ciclo por lo que recolectaras con un split ("|") esos 4 valores
los guardas tal como posiciones:
0: tag
1: dataset
2: lib_name
3: iteraciones
Ahora ya no se podra entrar a esta seccion
}
Eso es todo.. esto lo reptires hasta terminar con el archivo
En la segunda etapa emepzaras a crear el script para MT5,
Te dare como base esto:
{
const int sql_handle = DatabaseOpen(name, DATABASE_OPEN_COMMON | DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE);
if(sql_handle == INVALID_HANDLE)
{
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al abrir la db [%s], last err = %d",
name, ::GetLastError()));
return;
}
//--- creamos si no existe
if(!DatabaseExecute(sql_handle, g_mqlarticles_mben_sql_init))
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al crear la tabla db, last err = %d", ::GetLastError()));
return;
}
//--- Iniciamos
::ResetLastError();
if(!DatabaseTransactionBegin(sql_handle))
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al inicar transacion datos al m_sql_handle: ", ::GetLastError()));
return;
}
//---
::ResetLastError();
const int stmt = DatabasePrepare(sql_handle, g_mqlarticles_mben_sql_insert);
if(stmt == INVALID_HANDLE)
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al ejeuctar un preprare de la base de datos, ultimo err = %d",
::GetLastError()));
return;
}
//---
const string run_date = TimeToString(TimeLocal(),TIME_DATE);
for(int i = 0; i < s_pos; i++)
{
DatabaseReset(stmt);
DatabaseBind(stmt, 0, run_date);
DatabaseBind(stmt, 1, s_data[i].op);
DatabaseBind(stmt, 2, s_data[i].dataset);
DatabaseBind(stmt, 3, s_data[i].lib_name);
DatabaseBind(stmt, 4, s_data[i].iter);
DatabaseBind(stmt, 5, s_data[i].total);
DatabaseRead(stmt);
}
//---
DatabaseFinalize(stmt);
//---
::ResetLastError();
if(!DatabaseTransactionCommit(sql_handle))
{
DatabaseClose(sql_handle);
FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, StringFormat("Fallo al enviar datos al m_sql_handle: ", ::GetLastError()));
return;
}
//---
DatabaseClose(sql_handle);
}
Lo que tu cambiarsae sera justo la parte de los datos cuando se itera agrango a la base ahi en vez de s_data
pones la struct que hacodeaste (iteras sobre ella) y listo eso es todo por cierto:
g_mqlarticles_mben_sql_init = {
CREATE TABLE IF NOT EXISTS timing_results (
id INTEGER PRIMARY KEY AUTOINCREMENT,
run_date TEXT,
operation TEXT,
dataset TEXT,
library TEXT,
iteration INTEGER,
microseconds INTEGER,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE(run_date, library, operation, dataset, iteration)
);
}
g_mqlarticles_mben_sql_insert = {
INSERT INTO timing_results (run_date, operation, dataset, library, iteration, microseconds)
VALUES (?,?,?,?,?,?)
ON CONFLICT(run_date, library, operation, dataset, iteration)
DO UPDATE SET microseconds = excluded.microseconds
WHERE excluded.microseconds < timing_results.microseconds;
}
Vamos ayudame con eso.
*/
// En caso hayan hecho algo mal le emncionan que agtege ciertos explicitamente..
}
//---
}
//+------------------------------------------------------------------+
#endif // MQLARTICLES_UTILS_MBEN_BASIC_MQH