//+------------------------------------------------------------------+ //| Complex.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 AIDATAGENBYLEO_GENERIC_DATA_BASE_COMPLEX_MQH #define AIDATAGENBYLEO_GENERIC_DATA_BASE_COMPLEX_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "..\\Factory\\Main.mqh" //--- //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // Solo para repartir el estado global namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CAiLeoMulyiFeatureGen : public CLoggerBase { private: // Parser yaml principal ENUM_AIDATA_GEN_TYPE m_type; //--- string m_name; string m_header; bool m_init; //--- ulong m_cols; ulong m_rows; //--- string m_symbol; double m_bid; double m_ask; //--- int m_idx_m1[]; int m_idx_m1_size; //--- CAiDataLeoFeature* m_features[]; int m_features_size; //--- void SetHeader(); bool InternaBuild(CYmlNode& root); public: CAiLeoMulyiFeatureGen(); ~CAiLeoMulyiFeatureGen(); //--- void Clean(); //--- Iniciar bool Init(CYmlNode& root); bool Compile(CYmlNode& root, string& out); //--- Obtener datos void ObtenerDataEnMatrix(matrix& mtx, const datetime curr_time); // Obtiene un matrix void ObtenerDataEnVector(vector& vct, const datetime curr_time); // Obtiene un vector void ObtenerVectorAsMatrix(matrix& mtx, const datetime curr_time); // Obtiene un vector solo que como matrix //--- Summary void Summary() const; //--- // CUIDADO puede dar errores.. // El headerva separado por , siempre debera de tener el mismo tamaño que COLS.. esa es la idea // En caso no lo tenga la clase se abstiene a hacer comprobaciones... asi que // Las modificaiones que se hagan al header.. ud debera de tener cuidado __forceinline string Header() const { return m_header; } void Header(const string& v) { m_header = v; } //--- void OnNewBarM1(const datetime curr_time); //--- static void GetDataCts(vector& res, const int &indexs[], const int indexs_size, const vector& v); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CAiLeoMulyiFeatureGen::CAiLeoMulyiFeatureGen() : m_init(false), m_symbol(_Symbol), m_header(NULL) { m_features_size = ArrayResize(m_features, 0); m_idx_m1_size = ArrayResize(m_idx_m1, 0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CAiLeoMulyiFeatureGen::~CAiLeoMulyiFeatureGen(void) { Clean(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CAiLeoMulyiFeatureGen::Clean(void) { //--- m_cols = 0; m_rows = 0; m_type = WRONG_VALUE; m_name = NULL; m_init = false; m_header = NULL; //--- Eliminamos los puntos for(int i = 0; i < m_features_size; i++) { if(CheckPointer(m_features[i]) == POINTER_DYNAMIC) delete m_features[i]; } m_features_size = ArrayResize(m_features, 0); //--- m_idx_m1_size = ArrayResize(m_idx_m1, 0); } //+------------------------------------------------------------------+ //| Funciones de inicilizacion | //| 1. Funcion de incilizacion normal por src | //| 2. Funcion de iniclziacion por file AIDATABYLEO_FILE_EXT | //+------------------------------------------------------------------+ bool CAiLeoMulyiFeatureGen::Init(CYmlNode& root) { //--- Verificamos si esta iniciado if(m_init) { LogWarning("Se esta limpiadno la clase, dado que ya esta iniciada", FUNCION_ACTUAL); Clean(); } //--- Parseamos if(!InternaBuild(root)) return false; //--- Seteamos el nombre (en el parse ya se setea el resto) m_init = true; // Se inicio correctamente //--- Construiimos... ArrayResize(m_idx_m1, m_features_size); // Inicialmente el mismo tamaño.. for(int i = 0; i < m_features_size; i++) { if(m_features[i].m_use_on_new_bar_m1) { m_idx_m1[m_idx_m1_size++] = i; } } //--- SetHeader(); //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CAiLeoMulyiFeatureGen::OnNewBarM1(const datetime curr_time) { //--- m_bid = SymbolInfoDouble(m_symbol, SYMBOL_BID); m_ask = SymbolInfoDouble(m_symbol, SYMBOL_ASK); //--- for(int i = 0; i < m_idx_m1_size; i++) { m_features[m_idx_m1[i]].OnNewBarM1(curr_time, m_bid, m_ask); } } //+------------------------------------------------------------------+ //| Funciones para generar data | //| Nota: | //| - Recomiendo saber de ante mano cual llamar | //+------------------------------------------------------------------+ void CAiLeoMulyiFeatureGen::ObtenerDataEnMatrix(matrix &mtx, const datetime curr_time) { //--- m_bid = SymbolInfoDouble(m_symbol, SYMBOL_BID); m_ask = SymbolInfoDouble(m_symbol, SYMBOL_ASK); //--- mtx.Resize(m_rows, m_cols); ulong start_r = 0; ulong end_r = 0; ulong col = 0; ulong k = 0; //--- for(int i = 0; i < m_features_size; i++) { CAiDataLeoFeature* f = m_features[i]; col = f.MtxStartCol(); start_r = f.MtxStartRow(); end_r = f.MtxEndRow(); f.CalcValue(curr_time, m_bid, m_ask); k = 0; //--- for(ulong r = start_r; r <= end_r; r++) { mtx[r][col] = f.m_v[k++]; } } } //+------------------------------------------------------------------+ void CAiLeoMulyiFeatureGen::ObtenerDataEnVector(vector &vct, const datetime curr_time) { //--- m_bid = SymbolInfoDouble(m_symbol, SYMBOL_BID); m_ask = SymbolInfoDouble(m_symbol, SYMBOL_ASK); //--- vct.Resize(m_cols); for(ulong i = 0; i < m_cols; i++) { m_features[i].CalcValue(curr_time, m_bid, m_ask); vct[i] = m_features[i].m_v[0]; // Valor 0 } } //+------------------------------------------------------------------+ void CAiLeoMulyiFeatureGen::ObtenerVectorAsMatrix(matrix &mtx, const datetime curr_time) { //--- m_bid = SymbolInfoDouble(m_symbol, SYMBOL_BID); m_ask = SymbolInfoDouble(m_symbol, SYMBOL_ASK); //--- mtx.Resize(m_rows, m_cols); // ROWS = 1 for(ulong i = 0; i < m_cols; i++) { m_features[i].CalcValue(curr_time, m_bid, m_ask); mtx[i][0] = m_features[i].m_v[0]; // Valor 0 } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CAiLeoMulyiFeatureGen::Summary(void) const { PrintFormat("---| Summary of = %s", m_name); PrintFormat(" Type = %s", EnumToString(m_type)); PrintFormat(" Cols = %I64u", m_cols); PrintFormat(" Rows = %I64u", m_rows); Print(" --------- "); for(int i = 0; i < m_features_size; i++) { Print(m_features[i].Summary() + "\n"); } Print("--- Fin"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CAiLeoMulyiFeatureGen::SetHeader(void) { //--- m_header = ""; //--- if(m_type == AIDATALEO_GEN_VECTOR) { //--- Vector usa nombres reales for(ulong i = 0; i < m_cols; i++) { m_header += m_features[i].FullName(); if(i < m_cols - 1) m_header += AILEO_COMPLEX_HEADER_SEP; } } else { //--- Matrix usa nombres genericos for(ulong i = 0; i < m_cols; i++) { m_header += AILEO_COMPLEX_GENERIC_COL_NAME + string(i); if(i < m_cols - 1) m_header += AILEO_COMPLEX_HEADER_SEP; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CAiLeoMulyiFeatureGen::Compile(CYmlNode &root, string &out) { //--- out = ""; m_init = true; //-- Base m_name = root["name"].ToString("MyFeatureGenerator"); m_cols = (int)root["config"]["cols"].ToInt(0); //--- CYmlNode output = root["output"]; m_type = CEnumRegAiLeo::GetValNoRef(output["type"].ToString(), WRONG_VALUE); /// usar cenumreg... if(m_type == WRONG_VALUE) { LogError("Tipo de output invalido", FUNCION_ACTUAL); return false; } //--- m_rows = (int)output["rows"].ToInt(1); //--- if(!output["contexts"].IsArray()) return false; //--- CYmlIteratorArray it = output["contexts"].BeginArr(); //--- int last_idx_arr_size = 0; int fi = 0; int rfi = 0; //--- Array if(m_type == AIDATALEO_GEN_VECTOR) { //--- rfi = int(m_cols); //--- while(it.IsValid()) { CYmlNode obj = it.Val(); //--- Por cada parametro... CYmlIteratorArray ita = obj["data"].BeginArr(); while(ita.IsValid()) { CYmlNode curr_obj = ita.Val(); //--- obtenemos ptr const string name = curr_obj["class"].ToString(); if(!CAiDataGenFeatureFactory::s_hash_str_to_creator.Contains(name)) { LogError(StringFormat("No existe class = '%s'", name), FUNCION_ACTUAL); return false; } //--- const string pref = curr_obj["prefix"].ToString(""); //--- out += name + pref + ","; fi++; //--- ita.Next(); } //--- it.Next(); } } else // Matrix { //--- rfi = int(m_cols * m_rows); ulong col = 0; ulong row = 0; //--- out += AILEO_COMPLEX_GENERIC_COL_NAME + "0,"; while(it.IsValid()) { CYmlNode obj = it.Val(); //--- const int type = CEnumRegAiLeo::GetValNoRef(obj["mode"].ToString(""), -1); switch(type) { case AILEO_MTX_TYPE_NORMAL: // normal [1,2,3] (misma features pero los indices para generar un vector) case AILEO_MTX_TYPE_CUSTOM: // custom [1,2,3] (diferentens features) { last_idx_arr_size = obj["idx"].Size(); break; } case AILEO_MTX_TYPE_GENERATE: // [1,2,3] (misma feature pero con varios indices) { int temp[]; const int t = obj["idx"].ToArray(temp); // start,step,stop if(t != 3) { LogError("Generate debe de tener exactamente 3 elementos", FUNCION_ACTUAL); return false; } const int num = (temp[2] - temp[0]) / temp[1]; if(num < 1) { LogError("Numero de combinacion en generate menor a 1", FUNCION_ACTUAL); return false; } //--- last_idx_arr_size = num; break; } default: LogError("Modo invalido", FUNCION_ACTUAL); return false; } //--- CYmlIteratorArray ita = obj["data"].BeginArr(); while(ita.IsValid()) { //--- CYmlNode curr_obj = ita.Val(); //--- obtenemos ptr const string name = curr_obj["class"].ToString(); if(!CAiDataGenFeatureFactory::s_hash_str_to_creator.Contains(name)) { LogError(StringFormat("No existe class = '%s'", name), FUNCION_ACTUAL); return false; } //--- if(type == AILEO_MTX_TYPE_CUSTOM) // Custom valores.. { row++; // Siguiente elemento.. } else // Vector completo.. { //--- // 0 1 2 const ulong row_end = row + (last_idx_arr_size - 1); if(row_end >= m_rows) { LogError("Una fila de datos ha superado el tamaño de fila para este col, divida esta col en varias..", FUNCION_ACTUAL); return false; } row = row_end + 1; // Siguiente elemento.. } //--- if(row >= m_rows) { row = 0; col++; out += AILEO_COMPLEX_GENERIC_COL_NAME + string(col) + ","; } //--- fi++; //--- ita.Next(); } //--- it.Next(); } } //--- Verificamos auqnue quizas no sea necesario dado qeu dara un array out range si se pasa de lo previsto... const uint len = out.Length(); if(fi != rfi || !len) { LogError("El numero de features creadas no conicide.., o no hay features", FUNCION_ACTUAL); return false; } StringSetLength(out, len - 1); // //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CAiLeoMulyiFeatureGen::InternaBuild(CYmlNode& root) { //-- Base m_name = root["name"].ToString("MyFeatureGenerator"); m_cols = (int)root["config"]["cols"].ToInt(0); //--- CYmlNode output = root["output"]; m_type = CEnumRegAiLeo::GetValNoRef(output["type"].ToString(), WRONG_VALUE); /// usar cenumreg... if(m_type == WRONG_VALUE) { LogError("Tipo de output invalido", FUNCION_ACTUAL); return false; } //--- m_rows = (int)output["rows"].ToInt(1); //--- if(!output["contexts"].IsArray()) return false; //--- CYmlIteratorArray it = output["contexts"].BeginArr(); //--- int last_idx_arr[]; int last_idx_arr_size = 0; int fi = 0; //--- Array if(m_type == AIDATALEO_GEN_VECTOR) { m_features_size = ArrayResize(m_features, (int)m_cols); //--- while(it.IsValid()) { CYmlNode obj = it.Val(); //--- int p = 0; const int type = CEnumRegAiLeo::GetValNoRef(obj["mode"].ToString(""), -1); switch(type) { case AILEO_VECTOR_TYPE_NORMAL: // normal { ArrayResize(last_idx_arr, 1); last_idx_arr[0] = (int)obj["idx"].ToInt(0); break; } case AILEO_VECTOR_TYPE_CUSTOM: { last_idx_arr_size = obj["idx"].ToArray(last_idx_arr); break; } default: LogError("Modo invalido", FUNCION_ACTUAL); return false; } //--- Por cada parametro... CYmlIteratorArray ita = obj["data"].BeginArr(); while(ita.IsValid()) { CYmlNode curr_obj = ita.Val(); //--- obtenemos ptr const string name = curr_obj["class"].ToString(); CAiDataLeoFeature* ptr = CAiDataGenFeatureFactory::GetFeature(name); if(ptr == NULL) { LogError(StringFormat("Se obtuvo un puntero NULL, para la feature con nombre = '%s'", name), FUNCION_ACTUAL); return false; } //--- const bool support_idx = ptr.m_support_idx; const int idx = (type == AILEO_VECTOR_TYPE_CUSTOM) ? (last_idx_arr[p++]) : (last_idx_arr[0]); //--- if(!support_idx) { if(idx > 1) // Error { LogError(StringFormat("La feature con nombre = %s, no soporta indices > 1", name), FUNCION_ACTUAL); delete ptr; // Lo eliminamos return false; } } //--- Inicilizar if(!ptr.Initialize(curr_obj["params"], idx)) { delete ptr; LogError(StringFormat("Fallo al inicio la feature = %s", name), FUNCION_ACTUAL); return false; } //--- const string pref = curr_obj["prefix"].ToString(""); ptr.Prefix(pref); //--- m_features[fi++] = ptr; //--- ita.Next(); } //--- it.Next(); } } else // Matrix { m_features_size = ArrayResize(m_features, int(m_cols * m_rows)); ulong col = 0; ulong row = 0; //--- while(it.IsValid()) { CYmlNode obj = it.Val(); //--- int p = 0; const int type = CEnumRegAiLeo::GetValNoRef(obj["mode"].ToString(""), -1); switch(type) { case AILEO_MTX_TYPE_NORMAL: // normal [1,2,3] (misma features pero los indices para generar un vector) case AILEO_MTX_TYPE_CUSTOM: // custom [1,2,3] (diferentens features) { last_idx_arr_size = obj["idx"].ToArray(last_idx_arr); break; } case AILEO_MTX_TYPE_GENERATE: // [1,2,3] (misma feature pero con varios indices) { int temp[]; const int t = obj["idx"].ToArray(temp); // start,step,stop if(t != 3) { LogError("Generate debe de tener exactamente 3 elementos", FUNCION_ACTUAL); return false; } const int num = (temp[2] - temp[0]) / temp[1]; if(num < 1) { LogError("Numero de combinacion en generate menor a 1", FUNCION_ACTUAL); return false; } //--- last_idx_arr_size = ArrayResize(last_idx_arr, num); int x = temp[0]; int k = 0; last_idx_arr[k++] = x; //--- while(x < temp[2]) { x += temp[1]; last_idx_arr[k++] = x; } break; } default: LogError("Modo invalido", FUNCION_ACTUAL); return false; } //--- CYmlIteratorArray ita = obj["data"].BeginArr(); while(ita.IsValid()) { //--- CYmlNode curr_obj = ita.Val(); //--- obtenemos ptr const string name = curr_obj["class"].ToString(); CAiDataLeoFeature* ptr = CAiDataGenFeatureFactory::GetFeature(name); if(ptr == NULL) { LogError(StringFormat("Se obtuvo un puntero NULL, para la feature con nombre = '%s'", name), FUNCION_ACTUAL); return false; } //--- const bool support_idx = ptr.m_support_idx; //--- if(type == AILEO_MTX_TYPE_CUSTOM) // Custom valores.. { const int idx = last_idx_arr[p++]; //---- if(!support_idx) { if(idx > 1) // Error { LogError(StringFormat("La feature con nombre = %s, no soporta indices > 1", name), FUNCION_ACTUAL); delete ptr; // Lo eliminamos return false; } } //---- if(!ptr.Initialize(curr_obj["params"], idx)) { delete ptr; LogError(StringFormat("Fallo al inicio la feature = %s", name), FUNCION_ACTUAL); return false; } //--- ptr.SetExtra(col, row, row); // Solo 1 dato aqui row++; // Siguiente elemento.. } else // Vector completo.. { if(!support_idx) { for(int k = 0; k < last_idx_arr_size; k++) { if(last_idx_arr[k] > 1) { LogError(StringFormat("La feature con nombre = %s, no soporta indices > 1, pos = %d, val = %d", name, k, last_idx_arr[k]), FUNCION_ACTUAL); delete ptr; // Lo eliminamos return false; } } } //--- if(!ptr.Initialize(curr_obj["params"], last_idx_arr)) // Le pasamos el array esta vez generara un vector { delete ptr; LogError(StringFormat("Fallo al inicio la feature = %s", name), FUNCION_ACTUAL); return false; } //--- // 0 1 2 const ulong row_end = row + (last_idx_arr_size - 1); if(row_end >= m_rows) { LogError("Una fila de datos ha superado el tamaño de fila para este col, divida esta col en varias..", FUNCION_ACTUAL); return false; } ptr.SetExtra(col, row, row_end); // row = row_end + 1; // Siguiente elemento.. } //--- if(row >= m_rows) { row = 0; col++; } //--- const string pref = curr_obj["prefix"].ToString(""); ptr.Prefix(pref); //--- m_features[fi++] = ptr; //--- ita.Next(); } //--- it.Next(); } } //--- Verificamos auqnue quizas no sea necesario dado qeu dara un array out range si se pasa de lo previsto... if(fi != m_features_size) { LogError("El numero de features creadas no conicide..", FUNCION_ACTUAL); return false; } //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ static void CAiLeoMulyiFeatureGen::GetDataCts(vector& res, const int &indexs[], const int indexs_size, const vector& v) { //--- res.Resize(indexs_size); //--- for(int i = 0; i < indexs_size; i++) { res[i] = v[indexs[i]]; } } } //+------------------------------------------------------------------+ #endif // AIDATAGENBYLEO_GENERIC_DATA_BASE_COMPLEX_MQH //+------------------------------------------------------------------+