2026-04-13 07:53:05 -05:00
//+------------------------------------------------------------------+
2026-04-07 09:56:10 -05:00
//| Main.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 AIDATATASKRUNNER_BACKEND_WORKFLOWS_MAIN_MQH
# define AIDATATASKRUNNER_BACKEND_WORKFLOWS_MAIN_MQH
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
# define WORKFLOW_CALLBACK_PADRE CLoggerBase
# include "Flows\\AllFlows.mqh"
# include "Protocol\\Def.mqh"
2026-04-09 06:52:40 -05:00
2026-04-09 15:46:33 -05:00
//+------------------------------------------------------------------+
//| Definicion de la clase base de callback |
//+------------------------------------------------------------------+
class CWfCallBack : public IWorkflowCallback
{
private :
//---
long m_chart_id_p ;
CWorkflow * m_flow ;
string m_path_file_temp ;
bool m_common_flag ;
string m_prev_file_yml ;
2026-04-13 17:42:23 -05:00
uint m_start_t ;
2026-04-09 15:46:33 -05:00
//---
void OnWfInit ( ) ;
void OnNewWf ( const string & sparam ) ;
//---
void Kill ( ) ;
public :
CWfCallBack ( void ) { }
~ CWfCallBack ( void ) { }
//---
void Set ( long v , CWorkflow * f , const string & fn , bool comon ) ;
//---
inline uint8_t FlagsCall ( ) const override final { return WORKFLOWBYLEO_CALLBACK_ALL_FLAGS ; }
bool OnWorkflowStart ( ) override final ;
void OnWorkflowEnd ( int code , int step_index ) override final ;
void OnWorkflowStep ( int code , int step_index ) override final ;
//---
void ChartEvent ( const int32_t id , const long & lparam , const double & dparam , const string & sparam ) ;
} ;
2026-04-07 09:56:10 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-08 07:03:04 -05:00
void CWfCallBack : : Set ( long v , CWorkflow * f , const string & fn , bool comon )
2026-04-07 09:56:10 -05:00
{
m_chart_id_p = v ;
2026-04-08 07:03:04 -05:00
m_path_file_temp = fn ;
2026-04-07 09:56:10 -05:00
m_flow = f ;
2026-04-08 20:35:41 -05:00
m_common_flag = comon ;
2026-04-09 15:46:33 -05:00
//--- Variables de yml generales
CDict * dict = m_flow . Env ( ) ;
dict .Set ( " chart_id " , v ) ;
dict .Set ( " common_flag " , comon ) ;
2026-04-07 09:56:10 -05:00
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-08 20:35:41 -05:00
void CWfCallBack : : Kill ( )
2026-04-07 09:56:10 -05:00
{
2026-04-08 20:35:41 -05:00
// La idea con esto es quitar al asesor.. dado que no se pudo inciar
ExpertRemove ( ) ;
: : ChartClose ( ) ; // Kill se cierra a si mismo
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-04-09 15:46:33 -05:00
// Solo se llama una vez
2026-04-08 20:35:41 -05:00
void CWfCallBack : : OnWfInit ( void )
{
//--- aqui los datos que leeremos (copiado del panel)
/*
FileWrite ( fh , AIDATATASKRUNER_PATH_TEMPLATES ) ; // Path templates
FileWrite ( fh , AIDATATASKRUNER_PATH_TASK ) ; // Path task
FileWrite ( fh , AIDATATASKRUNER_BASE_FOLDER ) ; // Base folder
* /
//---
2026-04-08 07:03:04 -05:00
: : ResetLastError ( ) ;
2026-04-09 21:47:51 -05:00
const int vc = ( m_common_flag ? FILE_COMMON : 0 ) ;
const int fh = FileOpen ( m_path_file_temp , FILE_READ | FILE_TXT | vc ) ;
2026-04-08 07:03:04 -05:00
if ( fh = = INVALID_HANDLE )
{
2026-04-08 20:35:41 -05:00
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_EVENT_ERR_INIT , 0 , 0 ,
StringFormat ( " Fallo al abrir el archivo = %s, ultimo error: %d " , m_path_file_temp , : : GetLastError ( ) ) ) )
{
LogError ( " No se pudo enviar evento de fallo al iniciar " , FUNCION_ACTUAL ) ;
Kill ( ) ;
return ;
}
}
2026-04-09 15:46:33 -05:00
//--- Variabels del yml
CDict * variables = m_flow . Variables ( ) ;
2026-04-09 21:47:51 -05:00
variables . SetStr ( " aidata.templates_folder " , FileReadString ( fh ) ) ;
variables . SetStr ( " aidata.task_folder " , FileReadString ( fh ) ) ;
variables . SetStr ( " aidata.base_folder " , FileReadString ( fh ) ) ;
2026-04-13 07:53:05 -05:00
variables . SetStr ( " terminal.data_path " , TERMINAL_MT5_DATA_PAH ) ;
2026-04-10 21:36:53 -05:00
variables . SetStr ( " terminal.common_path " , TERMINAL_MT5_COMMON_PATH ) ;
2026-04-09 21:47:51 -05:00
variables .Set ( " aidata.common_flag " , m_common_flag ) ;
const string v = m_common_flag ? " FILE_COMMON " : " " ;
variables . SetStr ( " aidata.common_flag_val " , v ) ;
2026-04-09 15:46:33 -05:00
2026-04-08 20:35:41 -05:00
//---
FileClose ( fh ) ;
}
2026-04-13 07:53:05 -05:00
2026-04-08 20:35:41 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CWfCallBack : : OnNewWf ( const string & sparam )
{
2026-04-13 07:53:05 -05:00
//--- Iniclziacion solo si se cambio el nombre o el tamaño respecto al anterior
if ( m_prev_file_yml ! = sparam | | FileGetInteger ( sparam , FILE_SIZE , m_common_flag ) ! = FileGetInteger ( m_prev_file_yml , FILE_SIZE , m_common_flag ) )
2026-04-08 20:35:41 -05:00
{
if ( ! m_flow .Init ( sparam , m_common_flag ) )
{
const string val = StringFormat ( " Fallo al iniciar el wf, con el archivo = %s, ultimo err del parser = %s, revise los logs " , sparam , EnumToString ( m_flow . YmlParser ( ) . LastErr ( ) ) ) ;
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_ON_EVENT , AIDATATASKRUNER_RUNNER_WF_E_ON_END_CRITICAL , 0.00 , val ) )
{
LogError ( " No se pudo enviar el comando de fallo al iniciar el wf " , FUNCION_ACTUAL ) ;
}
return ;
}
m_prev_file_yml = sparam ;
}
//--- Iniciamos
// Solo ejecutamso el send critical SI no se inicio dado a razones de incio del wf
// En caso de que sea un err de wf callback onstart entonces eso ya lo tratamos en la otra funcion
if ( m_flow . First ( ) = = WORKFLOWBYLEO_ERR_FIRST_NO_INIT )
{
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_ON_EVENT , AIDATATASKRUNER_RUNNER_WF_E_ON_END_CRITICAL , 0.00 , " Fallo al inciar el wf, revise los logs " ) )
{
LogError ( " No se pudo enviar el comando de fallo al evniar el primer comando en el wf " , FUNCION_ACTUAL ) ;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CWfCallBack : : ChartEvent ( const int id , const long & lparam , const double & dparam , const string & sparam )
{
//---
if ( id = = CHARTEVENT_CUSTOM + AIDATATASKRUNER_RUNNER_WF_EVENT_INIT )
{
// Evneto de inciilizacion general del runner (el panel le pasa datos como paths fijos etc)
OnWfInit ( ) ;
2026-04-08 07:03:04 -05:00
return ;
}
2026-04-08 20:35:41 -05:00
if ( id = = CHARTEVENT_CUSTOM + AIDATATASKRUNER_RUNNER_WF_EVENT_ON_NEW_WF )
{
// Evento de nuevo wf, el panel le dice "oye hay un nuevo wf" sparam contiene el nombre del wf
OnNewWf ( sparam ) ;
}
}
//+------------------------------------------------------------------+
//| Inicio del flow |
//+------------------------------------------------------------------+
bool CWfCallBack : : OnWorkflowStart ( void )
{
//--- Apertura del temporal
: : ResetLastError ( ) ;
const int fh = : : FileOpen ( m_path_file_temp , FILE_WRITE | FILE_TXT | ( m_common_flag ? FILE_COMMON : 0 ) ) ;
if ( fh = = INVALID_HANDLE )
{
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_ON_EVENT , AIDATATASKRUNER_RUNNER_WF_E_ON_END_CRITICAL , 0.00 ,
: : StringFormat ( " Cannont open temp file = %s, last err = %d " , m_path_file_temp , : : GetLastError ( ) ) ) )
{
LogError ( " No se pudo enviar el comando de fallo al abrir el archivo temporal " , FUNCION_ACTUAL ) ;
}
// Sleep(5000);//Esperamos a que lo reciba
return false ;
}
2026-04-08 07:03:04 -05:00
const int t = m_flow . StepCount ( ) ;
2026-04-07 09:56:10 -05:00
2026-04-08 07:03:04 -05:00
//--- Escritura en el teporal
FileWrite ( fh , m_flow . Name ( ) ) ; // Nombre del flow
FileWrite ( fh , t ) ; // Pasos
for ( int i = 0 ; i < t ; i + + )
{
//--- Escritura
FileWrite ( fh , ( m_flow . GetStep ( i ) . Name ( ) + " \\ " + m_flow . GetStep ( i ) . Namespace ( ) ) ) ; // Todos los flows
}
FileClose ( fh ) ; // Cierre
//--- Mandamos el finish
2026-04-07 09:56:10 -05:00
: : ResetLastError ( ) ;
2026-04-08 07:03:04 -05:00
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_ON_EVENT , AIDATATASKRUNER_RUNNER_WF_E_ON_START ,
0.00 , " " ) ) // sparam vacio (internatem se debera de abrir el archivo y leer)
2026-04-07 09:56:10 -05:00
{
2026-04-08 20:35:41 -05:00
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_ON_EVENT , AIDATATASKRUNER_RUNNER_WF_E_ON_END_CRITICAL , 0.00 , " Cannont send start command " ) )
{
LogError ( " No se pudo enviar el comando de fallo fatal al enviar comndo de inicio " , FUNCION_ACTUAL ) ;
}
// Sleep(5000);//Esperamos a que lo reciba
return false ;
2026-04-07 09:56:10 -05:00
}
2026-04-08 20:35:41 -05:00
2026-04-13 17:42:23 -05:00
//---
m_start_t = GetTickCount ( ) ;
2026-04-08 20:35:41 -05:00
//---
return true ; // Exito permitidmos continuar
2026-04-07 09:56:10 -05:00
}
//+------------------------------------------------------------------+
2026-04-08 20:35:41 -05:00
//| Paso del flow |
2026-04-07 09:56:10 -05:00
//+------------------------------------------------------------------+
2026-04-08 20:35:41 -05:00
void CWfCallBack : : OnWorkflowStep ( int code , int step_index )
2026-04-07 09:56:10 -05:00
{
//---
// stepindex | code
2026-04-13 17:42:23 -05:00
const uint diff = ( : : GetTickCount ( ) - m_start_t ) ;
const string v = StringFormat ( " %d%c%d%c%s " , step_index , AIDATATASKRUNER_RUNNER_WF_SEP , code , AIDATATASKRUNER_RUNNER_WF_SEP , ( diff < 1000 ? string ( diff ) + " ms " : DoubleToString ( diff / 1000.0 , 3 ) + " s " ) ) ;
2026-04-07 09:56:10 -05:00
//---
: : ResetLastError ( ) ;
2026-04-08 20:35:41 -05:00
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_ON_EVENT , AIDATATASKRUNER_RUNNER_WF_E_ON_STEP ,
2026-04-08 07:03:04 -05:00
0.00 , v ) )
2026-04-07 09:56:10 -05:00
{
2026-04-08 20:35:41 -05:00
LogError ( StringFormat ( " Fallo al enviar evento onstep, ultimo err = %d " , : : GetLastError ( ) ) , FUNCION_ACTUAL ) ;
2026-04-07 09:56:10 -05:00
}
2026-04-13 17:42:23 -05:00
//---
m_start_t = GetTickCount ( ) ;
2026-04-07 09:56:10 -05:00
}
//+------------------------------------------------------------------+
2026-04-08 20:35:41 -05:00
//| Final del flow |
2026-04-07 09:56:10 -05:00
//+------------------------------------------------------------------+
2026-04-08 20:35:41 -05:00
void CWfCallBack : : OnWorkflowEnd ( int code , int step_index )
2026-04-07 09:56:10 -05:00
{
//---
// stepindex | code
2026-04-13 17:42:23 -05:00
const uint diff = ( : : GetTickCount ( ) - m_start_t ) ;
const string v = StringFormat ( " %d%c%d%c%s " , step_index , AIDATATASKRUNER_RUNNER_WF_SEP , code , AIDATATASKRUNER_RUNNER_WF_SEP , ( diff < 1000 ? string ( diff ) + " ms " : DoubleToString ( diff / 1000.0 , 3 ) + " s " ) ) ;
2026-04-07 09:56:10 -05:00
//---
: : ResetLastError ( ) ;
2026-04-08 20:35:41 -05:00
if ( ! : : EventChartCustom ( m_chart_id_p , AIDATATASKRUNER_RUNNER_WF_ON_EVENT , AIDATATASKRUNER_RUNNER_WF_E_ON_END ,
2026-04-08 07:03:04 -05:00
0.00 , v ) )
2026-04-07 09:56:10 -05:00
{
2026-04-08 20:35:41 -05:00
LogError ( StringFormat ( " Fallo al enviar evento onend, ultimo err = %d " , : : GetLastError ( ) ) , FUNCION_ACTUAL ) ;
2026-04-07 09:56:10 -05:00
}
}
2026-04-08 20:35:41 -05:00
2026-04-07 09:56:10 -05:00
//+------------------------------------------------------------------+
2026-04-08 07:03:04 -05:00
# endif // AIDATATASKRUNNER_BACKEND_WORKFLOWS_MAIN_MQH
2026-04-08 20:35:41 -05:00
//+------------------------------------------------------------------+