forked from nique_372/TSNStd
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 TSNSTD_SRC_MBEN_MULTIBEN_MQH
| |
#define TSNSTD_SRC_MBEN_MULTIBEN_MQH
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
#include "..\\Logger\\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 // TSNSTD_SRC_MBEN_MULTIBEN_MQH
|