//+------------------------------------------------------------------+ //| Base.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_BASE_MQH #define AIDATAGENBYLEO_GENERIC_DATA_BASE_BASE_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "..\\..\\..\\MQLArticles\\Utils\\Basic.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ struct AiDataByLeoDataParamsParser { //--- Variables // Parametros string parameters[]; // Parametros //--- AiDataByLeoDataParamsParser(int total_parameteres, const string& config, ushort param_sep = '|') { //--- if(total_parameteres <= 0) return; //--- // En caso solo haya 2 lineas pero hay parametros ya que de feura de rango if(StringSplit(config, param_sep, parameters) != total_parameteres) { FastLog(FUNCION_ACTUAL, ERROR_TEXT, "Los parametros no tienen el mismo tamaño"); Remover(); return; } //--- for(int i = 0; i < total_parameteres; i++) { const int k = parameters[i].Find("="); if(k >= 0) parameters[i] = StringSubstr(parameters[i], k + 1); else // Fatal { FastLog(FUNCION_ACTUAL, FATAL_ERROR_TEXT, "No se encontro el = "); Remover(); } } } //--- Leer // Todo tipo de numero real o entero template __forceinline T ReadNumber(const int index) { return (T)parameters[index]; } // Timeframe de manera facil soporta M1, ....., H1....... D1, W1, para current se puede usar cualquier letra Current etc ENUM_TIMEFRAMES ReadTimeframe(const int index) { //--- const uint len = parameters[index].Length(); const ushort first = parameters[index][0]; //--- if(first == 'M') { if(len == 2) { const int n = (parameters[index][1] - 48); return (n < 1 || n > 6) ? _Period : ENUM_TIMEFRAMES(n); } else if(len == 3) { if(parameters[index][1] == 'N') // MN return PERIOD_MN1; const int n = ((parameters[index][1] - '0') * 10 + (parameters[index][2] - '0')); return (n == 10 || n == 12 || n == 15 || n == 20 || n == 30) ? ENUM_TIMEFRAMES(n) : _Period; } } else if(first == 'H') { const int n = ((len == 2) ? parameters[index][1] - '0' : (parameters[index][1] - '0') * 10 + (parameters[index][2] - '0')); // Bitmask: 0001000101011110 = 0x115E // Bits: [12][8][6][4][3][2][1] = válidos // Aqui lo que hamos es desplazar a la derecha y el primer bit debe de ser 1.. si se da u numero que no es.. // entonces el desplazamieot daria ene l bit 1 0 por lo que esto daria error return (n < 13 && bool((0x115E >> n) & 1)) ? ENUM_TIMEFRAMES(16384 + n) : _Period; } else if(first == 'D') return PERIOD_D1; else if(first == 'W') return PERIOD_W1; //--- Cualquier otro caso Current return _Period; } // Booleanos __forceinline bool ReadBool(const int index) { const string val = parameters[index]; return (int(val) == 1 || val == "true" || val == "True" || val == "TRUE"); } // Read string.. sin espacios 100% seguro __forceinline string ReadStr(const int index) const { StringTrimLeft(parameters[index]); StringTrimRight(parameters[index]); return parameters[index]; } //--- // Read number array // " [10, 20, 30]" template int ReadNumberArray(const int index, T& out[], const ushort& sep, int reserve = 0) const { //--- int pos = 0; const int lenght = StringLen(parameters[index]); ArrayResize(out, 0, reserve); //--- while(parameters[index][pos] != '[') { if(++pos > lenght) { // No se encontro return 0; } } int start = pos + 1; //--- while(parameters[index][pos] != ']') { if(++pos > lenght) { // No se encontro return 0; } } int end = pos-1; //--- string arr[]; const int t = StringSplit(StringSubstrRange(parameters[index], start, end), sep, arr); if(t == -1) { return 0; } else { ArrayResize(out, t, reserve); for(int i = 0; i < t; i++) { out[i] = T(arr[i]); } //--- return t; } } // Read String array int ReadStringArray(const int index, string& out[], const ushort& sep, int reserve = 0) const { //--- int pos = 0; const int lenght = StringLen(parameters[index]); ArrayResize(out, 0, reserve); //--- while(parameters[index][pos] != '[') { if(++pos > lenght) { // No se encontro return 0; } } int start = pos + 1; //--- while(parameters[index][pos] != ']') { if(++pos > lenght) { // No se encontro return 0; } } int end =pos -1; //--- const int t = StringSplit(StringSubstrRange(parameters[index], start, end), sep, out); if(t == -1) { return 0; } else return t; } }; //--- AiDataByLeoDataParamsParser EMPTY_AIDATABYLEO_DATA_PARSER(0, EMPTY_STRING); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // Nota importante por defecto se heredara de CAllClassEventsBasic, teniendo como eventos los basicos // Si por alguna razon se requirere otros eventos como noticias etc.. entonces usetd puede definir AIDATA_LEO_FEATURE_FIRST // Y como valor ponerle la clase "intermedia" para eventos de noticias (todas deberan de herad siempre de CAllClassEventsBasic) // #define AIDATA_LEO_FEATURE_FIRST //--- #ifdef AIDATA_LEO_FEATURE_FIRST class CAiDataLeoFeature : public AIDATA_LEO_FEATURE_FIRST #else class CAiDataLeoFeature : public CAllClassEventsBasic #endif { protected: //--- Del modelo string m_name; // Nombre del feature string m_prefix; // Prefijo const bool m_support_idx; // Soporta Idx? bool m_init; // Bandera de inicialzacion const int m_parameters_size; // Numero de parametros int m_idx_arr_size; // Tamaño de indices a generar int m_idx_arr[]; // Array con los indices a generar int m_idx_max; // Maximo valor idx vector m_v; // Vector cache vector m_extra_v; // Vector de tamaño extra const bool m_use_on_new_bar_m1; // Use OnNewBarM1 private: //--- Especificos para matrix ulong m_start_col; ulong m_start_row; ulong m_end_row; protected: //--- virtual bool OnInitEvent(AiDataByLeoDataParamsParser& config) = 0; public: //--- CAiDataLeoFeature(const int params_num, const string& name, const bool support_idx, const bool use_m1); ~CAiDataLeoFeature() {} //--- Incializacion bool Initialize(const string& parameters, int& idx_arr[]); bool Initialize(const string& parameters, const int idx); //--- Extra void SetExtra(ulong start_col, ulong start_row, ulong end_row); __forceinline ulong MtxStartCol() const { return m_start_col; } __forceinline ulong MtxStartRow() const { return m_start_row; } __forceinline ulong MtxEndRow() const { return m_end_row; } //--- // Antencion amabas funciones tienen la misma firma esto debido a que se quiere aprovechar dos cossas // Por un lado en OnNewBar para concpetos ICT, y por otro lado GetValue para indicadores... virtual void OnNewBarM1(const datetime curr_time, const double bid, const double ask) {} //--- Funcion principal virtual vector GetValue(const datetime curr_time, const double bid, const double ask) { return m_v; } // Obtener vector //--- Prefix void Prefix(const string& new_value) { m_prefix = new_value; } //--- string Summary() const; //--- Getters // Names __forceinline string RealName() const { return m_name; } __forceinline string FullName() const { return (m_name + m_prefix); } __forceinline string Prefix() const { return m_prefix; } // Extra __forceinline bool SupportIdx() const { return m_support_idx; } __forceinline int ParametersTotal() const { return m_parameters_size; } __forceinline bool UseOnNewBarM1() const { return m_use_on_new_bar_m1; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CAiDataLeoFeature::CAiDataLeoFeature(const int params_num, const string& name, const bool support_idx, const bool use_m1) : m_init(false), m_parameters_size(params_num), m_name(name), m_support_idx(support_idx), m_prefix(NULL), m_use_on_new_bar_m1(use_m1) { m_idx_arr_size = ArrayResize(m_idx_arr, 0); } //+------------------------------------------------------------------+ bool CAiDataLeoFeature::Initialize(const string ¶meters, int& idx_arr[]) { //--- if(m_init) { LogWarning("Clase ya inciada", FUNCION_ACTUAL); return false; } //--- if(m_parameters_size > 0) { AiDataByLeoDataParamsParser config(m_parameters_size, parameters); m_init = OnInitEvent(config); } else { m_init = OnInitEvent(EMPTY_AIDATABYLEO_DATA_PARSER); } //--- m_idx_arr_size = ArrayCopy(m_idx_arr, idx_arr); m_v.Resize(ulong(m_idx_arr_size)); // El tamaño de idx arr m_idx_max = m_idx_arr[ArrayMaximum(m_idx_arr)]; //--- return m_init; } //+------------------------------------------------------------------+ bool CAiDataLeoFeature::Initialize(const string ¶meters, const int idx) { //--- if(m_init) { LogWarning("Clase ya inciada", FUNCION_ACTUAL); return false; } //--- if(m_parameters_size > 0) { AiDataByLeoDataParamsParser config(m_parameters_size, parameters); m_init = OnInitEvent(config); } else { m_init = OnInitEvent(EMPTY_AIDATABYLEO_DATA_PARSER); } //--- m_idx_arr[ArrayResize(m_idx_arr, (m_idx_arr_size = 1)) - 1] = idx; m_v.Resize(ulong(m_idx_arr_size)); // El tamaño de idx arr m_idx_max = m_idx_arr[0]; //--- return m_init; } //+------------------------------------------------------------------+ void CAiDataLeoFeature::SetExtra(ulong start_col, ulong start_row, ulong end_row) { m_start_col = start_col; m_start_row = start_row; m_end_row = end_row; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string CAiDataLeoFeature::Summary(void) const { //--- string str = ""; for(int i = 0; i < m_idx_arr_size; i++) { str += string(m_idx_arr[i]) + ", "; } StringSetLength(str, str.Length() - 2); //--- return StringFormat("[%s][%s](..)\n[Col=%I64u][Rows: %I64u -> %I64u] Indexes:\n[%s]", m_name, m_prefix, m_start_col, m_start_row, m_end_row, str); } //+------------------------------------------------------------------+ #endif // AIDATAGENBYLEO_GENERIC_DATA_BASE_BASE_MQH