forked from nique_372/MQLArticles
342 lines
12 KiB
MQL5
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
|