AiDataGenByLeo/GenericData/Base/Complex.mqh
Nique_372 c426d0bbfe
2026-07-07 18:39:17 -05:00

810 lines
46 KiB
MQL5

//+------------------------------------------------------------------+
//| 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<ENUM_AIDATA_GEN_TYPE>(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<int8_t>(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<ENUM_AIDATA_GEN_TYPE>(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<int8_t>(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<int8_t>(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
//+------------------------------------------------------------------+