277 lines
11 KiB
MQL5
277 lines
11 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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"
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 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;
|
|
uint m_start_t;
|
|
|
|
//---
|
|
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);
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CWfCallBack::Set(long v, CWorkflow *f, const string& fn, bool comon)
|
|
{
|
|
m_chart_id_p = v;
|
|
m_path_file_temp = fn;
|
|
m_flow = f;
|
|
m_common_flag = comon;
|
|
|
|
//--- Variables de yml generales
|
|
CDict* dict = m_flow.Env();
|
|
dict.Set("chart_id", v);
|
|
dict.Set("common_flag", comon);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CWfCallBack::Kill()
|
|
{
|
|
// La idea con esto es quitar al asesor.. dado que no se pudo inciar
|
|
ExpertRemove();
|
|
::ChartClose(); // Kill se cierra a si mismo
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
// Solo se llama una vez
|
|
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
|
|
*/
|
|
|
|
//---
|
|
::ResetLastError();
|
|
const int vc = (m_common_flag ? FILE_COMMON : 0);
|
|
const int fh = FileOpen(m_path_file_temp, FILE_READ | FILE_TXT | vc);
|
|
if(fh == INVALID_HANDLE)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
//--- Variabels del yml
|
|
CDict* variables = m_flow.Variables();
|
|
variables.SetStr("aidata.templates_folder", FileReadString(fh));
|
|
variables.SetStr("aidata.task_folder", FileReadString(fh));
|
|
variables.SetStr("aidata.base_folder", FileReadString(fh));
|
|
variables.SetStr("terminal.data_path", TERMINAL_MT5_DATA_PAH);
|
|
variables.SetStr("terminal.common_path", TERMINAL_MT5_COMMON_PATH);
|
|
variables.Set("aidata.common_flag", m_common_flag);
|
|
const string v = m_common_flag ? "FILE_COMMON" : "";
|
|
variables.SetStr("aidata.common_flag_val", v);
|
|
|
|
|
|
//---
|
|
FileClose(fh);
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CWfCallBack::OnNewWf(const string& sparam)
|
|
{
|
|
//--- 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))
|
|
{
|
|
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();
|
|
return;
|
|
}
|
|
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;
|
|
}
|
|
const int t = m_flow.StepCount();
|
|
|
|
//--- 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
|
|
::ResetLastError();
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
//---
|
|
m_start_t = GetTickCount();
|
|
|
|
//---
|
|
return true; // Exito permitidmos continuar
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Paso del flow |
|
|
//+------------------------------------------------------------------+
|
|
void CWfCallBack::OnWorkflowStep(int code, int step_index)
|
|
{
|
|
//---
|
|
// stepindex | code
|
|
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"));
|
|
|
|
//---
|
|
::ResetLastError();
|
|
if(!::EventChartCustom(m_chart_id_p, AIDATATASKRUNER_RUNNER_WF_ON_EVENT, AIDATATASKRUNER_RUNNER_WF_E_ON_STEP,
|
|
0.00, v))
|
|
{
|
|
LogError(StringFormat("Fallo al enviar evento onstep, ultimo err = %d", ::GetLastError()), FUNCION_ACTUAL);
|
|
}
|
|
|
|
//---
|
|
m_start_t = GetTickCount();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Final del flow |
|
|
//+------------------------------------------------------------------+
|
|
void CWfCallBack::OnWorkflowEnd(int code, int step_index)
|
|
{
|
|
//---
|
|
// stepindex | code
|
|
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"));
|
|
|
|
//---
|
|
::ResetLastError();
|
|
if(!::EventChartCustom(m_chart_id_p, AIDATATASKRUNER_RUNNER_WF_ON_EVENT, AIDATATASKRUNER_RUNNER_WF_E_ON_END,
|
|
0.00, v))
|
|
{
|
|
LogError(StringFormat("Fallo al enviar evento onend, ultimo err = %d", ::GetLastError()), FUNCION_ACTUAL);
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
#endif // AIDATATASKRUNNER_BACKEND_WORKFLOWS_MAIN_MQH
|
|
|
|
//+------------------------------------------------------------------+
|