2026-03-24 10:39:45 -05:00
//+------------------------------------------------------------------+
//| TrainingLauncher.mq5 |
//| 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 version " 1.00 "
# property strict
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
# include "Def.mqh"
# include <TSN\\ExtraCodes\\Func.mqh>
//+------------------------------------------------------------------+
2026-03-26 09:51:33 -05:00
//| Inputs |
//+------------------------------------------------------------------+
input string InpFileNameArgs = " " ; // Path al archivo donde se ubica datos extra para el py
input int InpFileCommonFlag = 0 ; // El path de archivo args essta en common flag
input string InpArgsConfigJson = " " ; // Path al archivo de configuracion para el py json
input string InpArgsResJson = " " ; // Path el archivo donde se pondran los resultados
input string InpArgsLockBin = " " ; // Path al arcvhio binario
input string InpArgsBaseTerminalPath = " " ; // Path del terminal base (common o files)
2026-03-24 10:39:45 -05:00
// 1 hora (3600 * 1000) en ms
input uint InpPyTimeoutMs = 3600000 ;
2026-03-28 10:58:12 -05:00
input string InpFileNameBat = " " ; // Path al bat (solo para eje py)
2026-03-24 10:39:45 -05:00
2026-03-28 10:58:12 -05:00
//+------------------------------------------------------------------+
2026-03-28 11:09:56 -05:00
//| Global variables |
2026-03-28 10:58:12 -05:00
//+------------------------------------------------------------------+
2026-03-28 10:22:11 -05:00
//---
# resource "py.bat" as const string py_bat
2026-03-24 10:39:45 -05:00
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit ( )
{
2026-03-26 09:51:33 -05:00
//---
FastLog ( FUNCION_ACTUAL , INFO_TEXT , " Iniciando launcher de py " ) ;
2026-03-28 10:22:11 -05:00
//--- Apertura en lecutra del file
2026-03-24 10:39:45 -05:00
: : ResetLastError ( ) ;
const int fh = : : FileOpen ( InpFileNameArgs , FILE_READ | FILE_TXT | InpFileCommonFlag ) ;
if ( fh = = INVALID_HANDLE )
{
FastLog ( FUNCION_ACTUAL , FATAL_ERROR_TEXT , : : StringFormat ( " Fallo al abrir el archivo args = %s, ultimo error = %d " , InpFileNameArgs , : : GetLastError ( ) ) ) ;
ResFinal ( AIDATATASKRUNNNER_TRAINIG_OUT_ERR_EXE_PY ) ;
2026-03-26 09:51:33 -05:00
return Finalize ( INIT_PARAMETERS_INCORRECT ) ;
2026-03-24 10:39:45 -05:00
}
2026-03-28 10:22:11 -05:00
//--- Lecutra de file
2026-03-26 11:23:24 -05:00
const string log_file = : : FileReadString ( fh ) ;
2026-03-24 10:39:45 -05:00
const string path_file_py = : : FileReadString ( fh ) ;
const string extension = : : FileReadString ( fh ) ;
2026-03-28 08:35:32 -05:00
const string interpreter = : : FileReadString ( fh ) ;
2026-03-28 10:22:11 -05:00
const string pythonpath = : : FileReadString ( fh ) ;
2026-03-24 10:39:45 -05:00
: : FileClose ( fh ) ;
2026-03-28 10:22:11 -05:00
//--- Args
2026-03-24 10:39:45 -05:00
const string args = " --config \" " + ( InpArgsBaseTerminalPath + InpArgsConfigJson ) + " \" "
2026-03-28 10:22:11 -05:00
+ " --results_json \" " + ( InpArgsBaseTerminalPath + InpArgsResJson ) + " \" "
+ " --lock_bin \" " + ( InpArgsBaseTerminalPath + InpArgsLockBin ) + " \" "
2026-03-26 11:23:44 -05:00
+ ( ( log_file .Length ( ) > 4 ) ? ( " --log_file \" " + ( InpArgsBaseTerminalPath + log_file ) + " \" " ) : " " ) ; // el lenght mayor a .log
2026-03-28 10:58:12 -05:00
Print ( args ) ;
2026-03-28 10:22:11 -05:00
//--- Consutrccion del cmd
2026-03-28 08:35:32 -05:00
string cmd ;
if ( extension = = " py " )
2026-03-28 10:22:11 -05:00
{
string bat_content = py_bat ;
2026-03-28 10:58:12 -05:00
StringReplace ( bat_content , " {PYTHONPATH_LINE} " , ( pythonpath .Length ( ) > 1 ) ? ( " set PYTHONPATH= " + pythonpath ) : " " ) ;
2026-03-28 10:22:11 -05:00
StringReplace ( bat_content , " {INTERPRETER} " , interpreter ) ;
StringReplace ( bat_content , " {PY_FILE} " , path_file_py ) ;
StringReplace ( bat_content , " {ARGS} " , args ) ;
//--- Bat filename
2026-03-28 10:58:12 -05:00
const string bat_full = InpArgsBaseTerminalPath + InpFileNameBat ;
// Convert to uchar
uchar buf [ ] ;
StringToCharArray ( bat_content , buf , 0 , StringLen ( bat_content ) , CP_ACP ) ; // ANSI para cmd.exe
// Open
const HANDLE hFile = CreateFileW ( bat_full , GENERIC_WRITE , 0 , 0 , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , 0 ) ;
if ( hFile = = -1 )
2026-03-28 10:22:11 -05:00
{
2026-03-28 10:58:12 -05:00
FastLog ( FUNCION_ACTUAL , FATAL_ERROR_TEXT , : : StringFormat ( " Fallo CreateFileW bat, error = %d " , kernel32 : : GetLastError ( ) ) ) ;
2026-03-28 10:22:11 -05:00
ResFinal ( AIDATATASKRUNNNER_TRAINIG_OUT_ERR_EXE_PY ) ;
return Finalize ( ) ;
}
2026-03-28 10:58:12 -05:00
// Write
uint written ;
WriteFile ( hFile , buf , ArraySize ( buf ) , written , 0 ) ; // tal cual dado que StringLen solo opcioas los caracter vlaidos quitanel el nulo \0
CloseHandle ( hFile ) ;
//---
2026-03-28 10:22:11 -05:00
// Lanzamos el bat
cmd = " cmd.exe /C \" \" " + bat_full + " \" \" " ;
}
2026-03-28 08:35:32 -05:00
else
cmd = " \" " + path_file_py + " \" " + args ;
2026-03-28 10:22:11 -05:00
//--- Print
2026-03-26 09:51:33 -05:00
Print ( cmd ) ;
2026-03-24 10:39:45 -05:00
//--- Lanzamos el proceso
PROCESS_INFORMATION pi ;
STARTUPINFOW si ;
: : ZeroMemory ( si ) ;
si . cb = sizeof ( si ) ;
const int created = CreateProcessW ( NULL , cmd , NULL , NULL , false , 0 , NULL , NULL , si , pi ) ;
if ( created = = 0 )
{
2026-03-26 09:51:33 -05:00
FastLog ( FUNCION_ACTUAL , FATAL_ERROR_TEXT , : : StringFormat ( " Fallo CreateProcessW, ultimo error = %d " , kernel32 : : GetLastError ( ) ) ) ;
2026-03-24 10:39:45 -05:00
ResFinal ( AIDATATASKRUNNNER_TRAINIG_OUT_ERR_EXE_PY ) ;
2026-03-26 09:51:33 -05:00
return Finalize ( ) ;
2026-03-24 10:39:45 -05:00
}
//--- Esperamos
const uint wait = WaitForSingleObject ( pi . hProcess , InpPyTimeoutMs ) ;
2026-04-09 20:49:16 -05:00
if ( wait = = WAIT_TIMEOUT_VAL )
TerminateProcess ( pi . hProcess , 1 ) ;
2026-03-24 10:39:45 -05:00
uint exit_code = 1 ;
GetExitCodeProcess ( pi . hProcess , exit_code ) ;
CloseHandle ( pi . hProcess ) ;
CloseHandle ( pi . hThread ) ;
2026-04-09 20:49:16 -05:00
2026-03-24 10:39:45 -05:00
//--- Vericamos como quedo el resultado
if ( wait = = WAIT_TIMEOUT_VAL )
{
2026-04-09 20:49:16 -05:00
FastLog ( FUNCION_ACTUAL , FATAL_ERROR_TEXT , " Timeout el py tardó demasiado " ) ;
2026-03-24 10:39:45 -05:00
ResFinal ( AIDATATASKRUNNNER_TRAINIG_OUT_TIMEOUT ) ;
2026-03-26 09:51:33 -05:00
return Finalize ( ) ;
2026-03-24 10:39:45 -05:00
}
//---
2026-03-26 11:52:16 -05:00
if ( exit_code ! = AIDATATASKRUNNNER_TRAINIG_OUT_EXITO )
2026-03-24 10:39:45 -05:00
{
FastLog ( FUNCION_ACTUAL , FATAL_ERROR_TEXT , : : StringFormat ( " Py terminó con exit_code = %u " , exit_code ) ) ;
ResFinal ( exit_code ) ;
2026-03-26 09:51:33 -05:00
return Finalize ( ) ;
2026-03-24 10:39:45 -05:00
}
2026-03-26 11:52:16 -05:00
//--- Exito total res code 0
// Liberamos el pool
ResFinal ( AIDATATASKRUNNNER_TRAINIG_OUT_EXITO ) ;
2026-03-24 10:39:45 -05:00
//---
2026-03-26 09:51:33 -05:00
return ( Finalize ( ) ) ; // Sale solo
2026-03-24 10:39:45 -05:00
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit ( const int reason )
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick ( )
{
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ResFinal ( int finish_code )
{
//--- Creacion del json
: : ResetLastError ( ) ;
const int fh = : : FileOpen ( InpArgsResJson , FILE_WRITE | FILE_TXT | InpFileCommonFlag , 0 ) ;
if ( fh ! = INVALID_HANDLE )
{
: : FileWriteString ( fh , : : StringFormat ( " { \" finish \" :%d} " , finish_code ) ) ;
: : FileClose ( fh ) ;
}
else
{
FastLog ( FUNCION_ACTUAL , FATAL_ERROR_TEXT , : : StringFormat ( " Fallo al escribir res.json, ultimo error = %d " , : : GetLastError ( ) ) ) ;
}
//--- Creasion del bin
: : ResetLastError ( ) ;
const int fh2 = : : FileOpen ( InpArgsLockBin , FILE_WRITE | FILE_BIN | InpFileCommonFlag , 0 ) ;
if ( fh2 ! = INVALID_HANDLE )
: : FileClose ( fh2 ) ;
else
{
FastLog ( FUNCION_ACTUAL , FATAL_ERROR_TEXT , : : StringFormat ( " Fallo al escribir lock.bin, ultimo error = %d " , : : GetLastError ( ) ) ) ;
}
}
2026-03-26 09:51:33 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-03-26 11:23:24 -05:00
int Finalize ( const int res = INIT_FAILED )
2026-03-26 09:51:33 -05:00
{
: : ChartClose ( ChartID ( ) ) ;
return res ;
}
2026-03-24 10:39:45 -05:00
//+------------------------------------------------------------------+