AiDataTaskRuner/Backend/Workflows/Main.mqh

277 lines
11 KiB
MQL5
Raw Permalink Normal View History

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
//+------------------------------------------------------------------+