forked from nique_372/AiDataGenByLeo
401 lines
25 KiB
MQL5
401 lines
25 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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 <typename T>
|
|
__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 <typename T>
|
|
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
|