//+------------------------------------------------------------------+ //| RunEA.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 WORKFLOWSBYLEO_STEPS_RUNEA_MQH #define WORKFLOWSBYLEO_STEPS_RUNEA_MQH //+------------------------------------------------------------------+ //| Include | //+------------------------------------------------------------------+ #include #include #include "..\\Final\\Orquestador.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CWorkStepGenericRunEa : public CWorkflowStep { private: MqlParam m_ea_params[]; const long m_current_chart_id; ENUM_TIMEFRAMES m_timeframe; string m_symbol; uint8_t m_flags; int m_timeout_segundos; int m_ms_sincronizar; string m_expert_name; public: CWorkStepGenericRunEa(void) : CWorkflowStep("RunEA", "Generic", false, 0), m_current_chart_id(ChartID()) {} ~CWorkStepGenericRunEa(void) {} //--- bool Init(const CYmlNode& parameters) override final; int Run() override final; }; //--- WORKFLOWS_FACTORY_DEFINE_CREATOR(CWorkStepGenericRunEa, GenericRunEa, "RunEA", "Generic") //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define WORFFLOWSTEP_GENERIC_RUNEA_IDX_EXPERT (0) #define WORFFLOWSTEP_GENERIC_RUNEA_IDX_SIMOLO (1) #define WORFFLOWSTEP_GENERIC_RUNEA_IDX_TIMEFRAME (2) //--- bool CWorkStepGenericRunEa::Init(const CYmlNode ¶meters) { //--- Parametros fijos CYmlNode fixed = parameters["fixed"]; if(fixed.Size() < 2) { LogError("Como minimo se requiere 1 parametro, en el se ubica el nombre del expert relativo a MQL5\\", FUNCION_ACTUAL); return false; } // Reserve ArrayResize(m_ea_params, 1); // EA Name if(!m_wf.AssingMqlParam(m_ea_params[0], fixed["name"], TYPE_STRING)) { LogError("No se pudo asignar el nombre del ea", FUNCION_ACTUAL); return false; } m_expert_name = FileRemoveExtensionNoRef(GetPureFileName(m_ea_params[0].string_value)); // Symbol m_symbol = m_wf.TranslateStr(fixed["symbol"], "_Symbol"); if(m_symbol == "_Symbol") m_symbol = _Symbol; // Timeframe m_timeframe = m_wf.TranslateEnum(fixed["timeframe"], "_Period"); //Print(EnumToString(m_timeframe)); // Flags m_flags = EXPERT::FlagsPermisosStrToFlags(m_wf.TranslateStr(fixed["run_flags"], ""), '|'); //Print(m_flags); // MS sincronizacion m_ms_sincronizar = m_wf.TranslateNumber(fixed["ms_sincronizacion"], "1000"); // Timeout m_timeout_segundos = m_wf.TranslateNumber(fixed["timeout_segundos"], "0"); if(m_timeout_segundos == 0) { LogError("Timeout no valido, debe de ser mayor a 0", FUNCION_ACTUAL); return false; } //--- Parametros dinamicos Array int k = 1; CYmlNode ea_parameters_node = parameters["ea_params"]; ArrayResize(m_ea_params, (1 + ea_parameters_node.Size())); CYmlIteratorArray it = ea_parameters_node.BeginArr(); // Print(ArraySize(m_ea_params) - 1); //--- // los 3 primeros parametros while(it.IsValid()) { //--- CYmlNode parametro = it.Val(); //--- Objeto (implicito) if(parametro.IsObject()) { //--- // Movemos al key // (no use next tokens por que quiero moverme posiciones) // si uso next token me muevo hacia el siguinete obj (se salta todo el obj) if(!parametro.MoveNextPositionsThis(1)) // [OBJ] -> [KEY base] (End se conserva) { LogError("Se intento mover al siguiente key pero no se pudo revise la sintazxis del yml", FUNCION_ACTUAL); return false; } // Saltamos a val // false dado que perdimos el contexto en if(!parametro.MoveToNextToken()) // [KEYBASE][KEYINFO] a [ARR] { // Print(parametro.m_idx); // Print(parametro.m_end); //Print(EnumToString(parametro.GetType())); LogError("Se intento mover al siguiente valor pero no se pudo revise la sintazxis del yml", FUNCION_ACTUAL); return false; } } // else: arr //--- Asignamos // [TYPE, VALOR] //Print(parametro.Size()); if(!m_wf.AssingMqlParam(m_ea_params[k++], parametro.At(1), parametro.At(0).ToString())) // 1 = valor | 0 = tipo { ArrayResize(m_ea_params, 0); // En caso de ejeuccino dara fallo LogError(StringFormat("Fallo al asingnar el valor al parametro, posible = %s tipo invalido", EnumToString(parametro.GetType())), FUNCION_ACTUAL); return false; } // Print(EnumToString(m_ea_params[k - 1].type)); //--- it.Next(); } //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CWorkStepGenericRunEa::Run(void) { //--- const long chart_id = OpenChartAndDevoler(m_current_chart_id, m_symbol, m_timeframe, m_ms_sincronizar); //--- if(chart_id == -1) { LogError("No se pudo abrir un grafico", FUNCION_ACTUAL); return 1; } //--- Lanza el EA if(!EXPERT::Run(chart_id, m_ea_params, m_flags)) { LogError("Fallo al ejecutar ea", FUNCION_ACTUAL); ArrayPrint(m_ea_params); //Print(TYPE_STRING); ::ChartClose(chart_id); return 1; } //--- int c = 0; bool is_t = false; while(ChartGetString(chart_id, CHART_EXPERT_NAME) == m_expert_name) { Sleep(500); if((++c >> 1) >= m_timeout_segundos) { is_t = true; break; } } //--- ::ChartClose(chart_id); //--- if(is_t) { LogError(StringFormat("Ejecucion del EA %s, supero el timeout", m_expert_name), FUNCION_ACTUAL); } //--- return is_t; } //+------------------------------------------------------------------+ #endif // WORKFLOWSBYLEO_STEPS_RUNEA_MQH