1775 satır
115 KiB
MQL5
1775 satır
115 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Main.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 MQLARTICLES_UTILS_SETFILES_MAIN_MQH
|
|
#define MQLARTICLES_UTILS_SETFILES_MAIN_MQH
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\\Basic.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
enum ENUM_SETFILE_LINE_TYPE
|
|
{
|
|
SETFILE_LINE_TYPE_NOINPUT = 1,
|
|
SETFILE_LINE_TYPE_INPUT = 0
|
|
};
|
|
|
|
//---
|
|
string g_setfile_dyn_arr[5];
|
|
|
|
//---
|
|
struct SetFileParam
|
|
{
|
|
string name;
|
|
string value;
|
|
string start;
|
|
string step;
|
|
string stop;
|
|
|
|
//---
|
|
SetFileParam()
|
|
: value(NULL), start(NULL), step(NULL), stop(NULL)
|
|
{
|
|
}
|
|
|
|
//---
|
|
// si start == NULL signfiica que es invalido para optimizar
|
|
__forceinline string Format() { return start != NULL ? StringFormat("%s=%s||%s||%s||%s||N", name, value, start, step, stop) : (name + "=" + value); }
|
|
};
|
|
|
|
//---
|
|
struct pack(4) SetFileLine
|
|
{
|
|
ENUM_SETFILE_LINE_TYPE type;
|
|
int id;
|
|
};
|
|
|
|
//---
|
|
SetFileParam EMPTY_SETFILE_PARAM;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CSetFile : public CLoggerBase
|
|
{
|
|
private:
|
|
//---
|
|
CHashMap<string, int>* m_hashmap_params;
|
|
bool m_init;
|
|
|
|
//--- Lines
|
|
SetFileLine m_lines[];
|
|
int m_lines_size;
|
|
|
|
//--- Inputs
|
|
int m_params_size;
|
|
SetFileParam m_params[];
|
|
|
|
//--- Strings
|
|
int m_no_params_size;
|
|
string m_no_params[];
|
|
|
|
//--- Data
|
|
string m_expert_name;
|
|
datetime m_saved_time;
|
|
|
|
//---
|
|
void ChangeSavedTime(const datetime new_time);
|
|
|
|
|
|
public:
|
|
CSetFile(void);
|
|
~CSetFile(void);
|
|
|
|
//---
|
|
bool Init(const string& expert_name);
|
|
bool InitByFile(const string& file_name, int extra_file_flags, uint reserve);
|
|
bool InitBySrc(const string& src, ushort separator, uint reserve);
|
|
|
|
//---
|
|
bool Save(const string& file_name, int extra_file_flags);
|
|
|
|
//---
|
|
void Clean();
|
|
|
|
//---
|
|
void GetAsString(string &out) const;
|
|
int GetAsStringArray(string& out[]) const;
|
|
|
|
//---
|
|
void Summary() const;
|
|
void Imprimir() const;
|
|
void ImprimirLinesArray() const { ArrayPrint(m_lines, 2, "|"); }
|
|
void ImprimirParamsArray() const { ArrayPrint(m_params, 2, "|"); }
|
|
void ImprimirNoParamsArray() const { ArrayPrint(m_no_params, 2, "|"); }
|
|
|
|
//--- Getters \Setters
|
|
__forceinline int ParamsSize() const { return m_params_size; }
|
|
__forceinline SetFileParam GetParam(const int idx) const { return m_params[idx]; }
|
|
__forceinline SetFileParam GetParam(const string str) const;
|
|
__forceinline int GetParamIdx(const string str) const;
|
|
|
|
|
|
__forceinline int NoParamsSize() const { return m_no_params_size; }
|
|
__forceinline string GetNoParmas(const int idx) const { return m_no_params[idx]; }
|
|
|
|
__forceinline int LinesSize() const { return m_lines_size; }
|
|
__forceinline SetFileLine GetLine(const int idx) const { return m_lines[idx]; }
|
|
|
|
// Expert name
|
|
__forceinline string ExpertName() const { return m_expert_name; }
|
|
void ExpertName(const string& v) { m_expert_name = v; }
|
|
|
|
// Saved time
|
|
__forceinline datetime SavedTime() const { return m_saved_time; }
|
|
|
|
//--- Funciones para remover un alinea (idx indice en m_lines)
|
|
bool RemoveLine(const int idx);
|
|
|
|
//--- Funciones para trabajar con los parametros
|
|
//- Agrega un parametro (al final) (por defecto start, etc es null osea que noe s optimizable si se espeicfia los 3 valores entonces si es optimzable)
|
|
bool AddParamLineString(const string& name, const string& value);
|
|
|
|
// Number
|
|
template <typename TInteger>
|
|
bool AddParamLineNumber(const string& name, const TInteger value, const TInteger start, const TInteger step, const TInteger stop);
|
|
|
|
// Real
|
|
template <typename TNumber>
|
|
bool AddParamLineReal(const string& name, const TNumber value, int8_t presicion, const TNumber start, const TNumber step, const TNumber stop);
|
|
|
|
// Bool
|
|
bool AddParamLineBool(const string& name, const bool value);
|
|
|
|
// Enum
|
|
template <typename TEnum>
|
|
bool AddParamLineEnum(const string& name, const TEnum value, const TEnum start, const TEnum stop);
|
|
|
|
// Datetime
|
|
bool AddParamLineDatetime(const string& name, const datetime value, const datetime start, const long step_sec, const datetime stop);
|
|
|
|
// Color
|
|
bool AddParamLineColor(const string& name, const color value);
|
|
|
|
|
|
// Idx = indice del FILE
|
|
//- Inserta
|
|
bool InsertParamLineString(const int idx, const string& name, const string& value);
|
|
|
|
template <typename TInteger>
|
|
bool InsertParamLineNumber(const int idx, const string& name, const TInteger value, const TInteger start, const TInteger step, const TInteger stop);
|
|
|
|
template <typename TNumber>
|
|
bool InsertParamLineReal(const int idx, const string& name, const TNumber value, int8_t presicion, const TNumber start, const TNumber step, const TNumber stop);
|
|
|
|
bool InsertParamLineBool(const int idx, const string& name, const bool value);
|
|
|
|
template <typename TEnum>
|
|
bool InsertParamLineEnum(const int idx, const string& name, const TEnum value, const TEnum start, const TEnum stop);
|
|
|
|
bool InsertParamLineDatetime(const int idx, const string& name, const datetime value, const datetime start, const long step_sec, const datetime stop);
|
|
|
|
bool InsertParamLineColor(const int idx, const string& name, const color value);
|
|
|
|
|
|
//- Modificar
|
|
// Nombre de parametro
|
|
bool ModifyParamName(const string param_name, const string& new_name);
|
|
bool ModifyParamName(const int idx, const string& new_name);
|
|
|
|
// Valor de parametro (value)
|
|
template <typename TInteger> // Todo tipo de numero integer uinteger | datetime | color
|
|
bool ModifyParamValueNumber(const string param_name, const TInteger v);
|
|
template <typename TNumber> // Double float
|
|
bool ModifyParamValueRealNumber(const string param_name, const TNumber v, int8_t presicion);
|
|
bool ModifyParamValueBoolean(const string param_name, const bool v);
|
|
bool ModifyParamValueString(const string param_name, const string v);
|
|
template <typename TEnum> // Double float
|
|
bool ModifyParamValueEnum(const string param_name, const TEnum v);
|
|
bool ModifyParamValueDatetime(const string param_name, const datetime v);
|
|
bool ModifyParamValueColor(const string param_name, const color v);
|
|
|
|
|
|
// ModifyParamOptNumber
|
|
template <typename TInteger>
|
|
bool ModifyParamOptNumberStart(const string param_name, const TInteger start);
|
|
template <typename TInteger>
|
|
bool ModifyParamOptNumberStep(const string param_name, const TInteger step);
|
|
template <typename TInteger>
|
|
bool ModifyParamOptNumberStop(const string param_name, const TInteger stop);
|
|
|
|
// ModifyParamOptRealNumber
|
|
template <typename TNumber>
|
|
bool ModifyParamOptRealNumberStart(const string param_name, const TNumber start, int8_t presicion);
|
|
template <typename TNumber>
|
|
bool ModifyParamOptRealNumberStep(const string param_name, const TNumber step, int8_t presicion);
|
|
template <typename TNumber>
|
|
bool ModifyParamOptRealNumberStop(const string param_name, const TNumber stop, int8_t presicion);
|
|
|
|
|
|
// Modify opt datetime
|
|
bool ModifyParamOptDatetimeStart(const string param_name, const datetime start);
|
|
bool ModifyParamOptDatetimeStep(const string param_name, const long step_sec);
|
|
bool ModifyParamOptDatetimeStop(const string param_name, const datetime stop);
|
|
|
|
|
|
// ModifyParamOptEnum
|
|
template <typename TEnum>
|
|
bool ModifyParamOptEnumStart(const string param_name, const TEnum start);
|
|
template <typename TEnum>
|
|
bool ModifyParamOptEnumStop(const string param_name, const TEnum stop);
|
|
|
|
//- Verificar exisitencia
|
|
bool ParamExist(const string& param_name) { return m_hashmap_params.ContainsKey(param_name); }
|
|
|
|
|
|
//- Lectura
|
|
string ReadParamValueString(const string param_name) const;
|
|
|
|
template <typename TInteger>
|
|
TInteger ReadParamValueInteger(const string param_name) const;
|
|
|
|
template <typename TNumber>
|
|
TNumber ReadParamValueReal(const string param_name) const;
|
|
|
|
datetime ReadParamValueDatetime(const string param_name) const;
|
|
color ReadParamValueColor(const string param_name) const;
|
|
bool ReadParamValueBool(const string param_name) const;
|
|
|
|
//--- Funciones para trabajar con no parametyros
|
|
//- Añade al final
|
|
void AddNoParamsLine(const string& line);
|
|
|
|
// Mencionar que idx es el indice en el FILE
|
|
//- Inserta
|
|
void InsertNoParamLine(const int idx, const string& line);
|
|
|
|
//- Modifica
|
|
void ModifyNoParamLine(const int idx, const string& new_line);
|
|
|
|
//---
|
|
bool IsValidIdxLine(const int idx) { return idx >= 0 && idx < m_lines_size; }
|
|
|
|
//---
|
|
CHashMap<string, int>* HashMapPointer() { return m_hashmap_params; }
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CSetFile::CSetFile(void)
|
|
{
|
|
m_hashmap_params = new CHashMap<string, int>();
|
|
Clean(); // Inicilizacion
|
|
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
CSetFile::~CSetFile()
|
|
{
|
|
if(CheckPointer(m_hashmap_params) == POINTER_DYNAMIC)
|
|
delete m_hashmap_params;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::Clean(void)
|
|
{
|
|
m_hashmap_params.Clear();
|
|
m_lines_size = ArrayResize(m_lines, 0);
|
|
m_params_size = ArrayResize(m_params, 0);
|
|
m_no_params_size = ArrayResize(m_no_params, 0);
|
|
m_expert_name = NULL;
|
|
m_saved_time = 0;
|
|
m_init = false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Funciones de carga Load |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::Init(const string &expert_name)
|
|
{
|
|
//---
|
|
if(m_init)
|
|
{
|
|
LogWarning("Limpiando dado que se inicia denuevo", FUNCION_ACTUAL);
|
|
Clean();
|
|
}
|
|
|
|
//---
|
|
m_expert_name = expert_name;
|
|
m_saved_time = TimeLocal();
|
|
m_init = true;
|
|
|
|
//---
|
|
m_no_params_size = ArrayResize(m_no_params, 4);
|
|
m_no_params[0] = StringFormat("; saved on %s", TimeToString(m_saved_time, TIME_DATE | TIME_MINUTES | TIME_SECONDS));
|
|
m_no_params[1] = StringFormat("; this file contains input parameters for testing/optimizing %s expert advisor", m_expert_name);
|
|
m_no_params[2] = "; to use it in the strategy tester, click Load in the context menu of the Inputs tab";
|
|
m_no_params[3] = ";";
|
|
|
|
//---
|
|
m_lines_size = ArrayResize(m_lines, 4);
|
|
m_lines[0].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[0].id = 0;
|
|
m_lines[1].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[1].id = 1;
|
|
m_lines[2].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[2].id = 2;
|
|
m_lines[3].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[3].id = 3;
|
|
|
|
//---
|
|
return true;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::InitBySrc(const string &src, ushort separator, uint reserve)
|
|
{
|
|
//---
|
|
if(m_init)
|
|
{
|
|
LogWarning("Limpiando dado que se inicia denuevo", FUNCION_ACTUAL);
|
|
Clean();
|
|
}
|
|
|
|
//---
|
|
string arr[];
|
|
const int size = StringSplit(src, separator, arr);
|
|
if(size == -1)
|
|
{
|
|
LogError("Fallo al hacer split", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
int ilec = 0;
|
|
|
|
//--- Reservamos para no params
|
|
reserve = fmax(3, reserve); // Como minimo un valor de 2
|
|
int cn = ArrayResize(m_no_params, reserve);
|
|
|
|
//---
|
|
int rl = ArrayResize(m_lines, reserve);
|
|
|
|
|
|
//--- Extramoes el tiempo de guardado
|
|
string line = arr[ilec++];
|
|
int len = StringLen(line);
|
|
int pos = 0;
|
|
while(line[pos] < '0' || line[pos] > '9') // Solo iterar mientras el caracter pos no sea un nuemro
|
|
{
|
|
pos++;
|
|
if(pos >= len)
|
|
{
|
|
LogError("En la primera linea debe de ubicarse un nuermo (fecha de creacion)", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
m_saved_time = StringToTime(StringSubstr(line, pos)); // Desde el inicio del numero hasta el fin del string
|
|
|
|
// Add
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[m_lines_size++].id = m_no_params_size;
|
|
m_no_params[m_no_params_size++] = line;
|
|
|
|
//--- Extraemos el nombre del bot
|
|
line = arr[ilec++];
|
|
len = StringLen(line);
|
|
pos = 0;
|
|
|
|
// Primero buscaremos /
|
|
while(line[pos] != '/')
|
|
{
|
|
pos++;
|
|
if(pos >= len)
|
|
{
|
|
LogError("En la segunda linea del archivo se debe de ubicar el caracter / ", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Avanzamos hasta el siguiente espacio
|
|
while(line[pos] != ' ')
|
|
{
|
|
pos++;
|
|
if(pos >= len)
|
|
{
|
|
LogError("En la segunda linea del archivo se debe de ubicar el caracter / ", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
pos++; // Luego del espacio (inicio del nombre del bot)
|
|
|
|
// Comenzamos desde el fin hasta el 2do espacio
|
|
int c = 2;
|
|
int end = len - 1;
|
|
while(c > 0)
|
|
{
|
|
end--;
|
|
if(end < 0)
|
|
{
|
|
LogError("En la segunda linea del archivo deben de al menos haber dos espacios empezados desde atras ", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
if(line[end] == ' ')
|
|
c--;
|
|
}
|
|
|
|
m_expert_name = StringSubstrRange(line, pos, end);
|
|
|
|
// Add
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[m_lines_size++].id = m_no_params_size;
|
|
m_no_params[m_no_params_size++] = line;
|
|
|
|
|
|
//---
|
|
c = ArrayResize(m_params, reserve);
|
|
|
|
//--- Cargamos todos los parametros
|
|
while(ilec < size)
|
|
{
|
|
line = arr[ilec++];
|
|
if(line == NULL)
|
|
continue;
|
|
|
|
//---
|
|
if(line[0] == ';') // Comentarios | Sinput
|
|
{
|
|
//---
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[m_lines_size++].id = m_no_params_size;
|
|
|
|
//---
|
|
m_no_params[m_no_params_size++] = line;
|
|
if(m_no_params_size >= cn)
|
|
{
|
|
cn <<= 1;
|
|
ArrayResize(m_no_params, cn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//---
|
|
int vs = line.Find("=");
|
|
if(vs == -1)
|
|
{
|
|
LogWarning(StringFormat("Omitiendo linea corrupta:\n'%s'", line), FUNCION_ACTUAL);
|
|
continue;
|
|
}
|
|
|
|
//---
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines[m_lines_size++].id = m_params_size;
|
|
|
|
//---
|
|
m_params[m_params_size].name = StringSubstr(line, 0, vs);
|
|
if(!m_hashmap_params.Add(m_params[m_params_size].name, m_params_size))
|
|
{
|
|
LogError(StringFormat("Fallo al agregar el parametro =%s al hashmap", m_params[m_params_size].name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
vs++;
|
|
|
|
//---
|
|
const int t = StringSplitStr(StringSubstr(line, vs), "||", g_setfile_dyn_arr, 5);
|
|
if(t < 1)
|
|
{
|
|
LogCriticalError("El split debe dar como minimo 1 cadena de resultado", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
m_params[m_params_size].value = g_setfile_dyn_arr[0];
|
|
|
|
//---
|
|
if(t == 5 && g_setfile_dyn_arr[4].Find("N") >= 0) // Optimizable
|
|
{
|
|
m_params[m_params_size].start = g_setfile_dyn_arr[1];
|
|
m_params[m_params_size].step = g_setfile_dyn_arr[2];
|
|
m_params[m_params_size].stop = g_setfile_dyn_arr[3];
|
|
}
|
|
|
|
//---
|
|
m_params_size++;
|
|
|
|
//---
|
|
if(m_params_size >= c)
|
|
{
|
|
c <<= 1;
|
|
ArrayResize(m_params, c);
|
|
}
|
|
}
|
|
|
|
//---
|
|
if(m_lines_size >= rl)
|
|
{
|
|
rl <<= 1;
|
|
ArrayResize(m_lines, rl);
|
|
}
|
|
}
|
|
|
|
//--- Truncamos
|
|
ArrayResize(m_params, m_params_size);
|
|
ArrayResize(m_no_params, m_no_params_size);
|
|
ArrayResize(m_lines, m_lines_size);
|
|
|
|
//---
|
|
m_init = true;
|
|
|
|
//--- Exito
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::InitByFile(const string &file_name, int extra_file_flags, uint reserve)
|
|
{
|
|
//---
|
|
if(m_init)
|
|
{
|
|
LogWarning("Limpiando dado que se inicia denuevo", FUNCION_ACTUAL);
|
|
Clean();
|
|
}
|
|
|
|
//---
|
|
ResetLastError();
|
|
const int fh = FileOpen(file_name, FILE_READ | FILE_TXT | extra_file_flags);
|
|
if(fh == INVALID_HANDLE)
|
|
{
|
|
LogError(StringFormat("Fallo al abrir el archivo '%s', ultimo error = %d", file_name, GetLastError()), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
|
|
//--- Reservamos para no params
|
|
reserve = fmax(3, reserve); // Como minimo un valor de 2
|
|
int cn = ArrayResize(m_no_params, reserve);
|
|
|
|
//---
|
|
int rl = ArrayResize(m_lines, reserve);
|
|
|
|
|
|
//--- Extramoes el tiempo de guardado
|
|
string line = FileReadString(fh);
|
|
int len = StringLen(line);
|
|
int pos = 0;
|
|
while(line[pos] < '0' || line[pos] > '9') // Solo iterar mientras el caracter pos no sea un nuemro
|
|
{
|
|
pos++;
|
|
if(pos >= len)
|
|
{
|
|
LogError("En la primera linea debe de ubicarse un nuermo (fecha de creacion)", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
m_saved_time = StringToTime(StringSubstr(line, pos)); // Desde el inicio del numero hasta el fin del string
|
|
|
|
// Add
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[m_lines_size++].id = m_no_params_size;
|
|
m_no_params[m_no_params_size++] = line;
|
|
|
|
//--- Extraemos el nombre del bot
|
|
line = FileReadString(fh);
|
|
len = StringLen(line);
|
|
pos = 0;
|
|
|
|
// Primero buscaremos /
|
|
while(line[pos] != '/')
|
|
{
|
|
pos++;
|
|
if(pos >= len)
|
|
{
|
|
LogError("En la segunda linea del archivo se debe de ubicar el caracter / ", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Avanzamos hasta el siguiente espacio
|
|
while(line[pos] != ' ')
|
|
{
|
|
pos++;
|
|
if(pos >= len)
|
|
{
|
|
LogError("En la segunda linea del archivo se debe de ubicar el caracter / ", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
pos++; // Luego del espacio (inicio del nombre del bot)
|
|
|
|
// Comenzamos desde el fin hasta el 2do espacio
|
|
int c = 2;
|
|
int end = len - 1;
|
|
while(c > 0)
|
|
{
|
|
end--;
|
|
if(end < 0)
|
|
{
|
|
LogError("En la segunda linea del archivo deben de al menos haber dos espacios empezados desde atras ", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
if(line[end] == ' ')
|
|
c--;
|
|
}
|
|
|
|
m_expert_name = StringSubstrRange(line, pos, end);
|
|
|
|
// Add
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[m_lines_size++].id = m_no_params_size;
|
|
m_no_params[m_no_params_size++] = line;
|
|
|
|
|
|
//---
|
|
c = ArrayResize(m_params, reserve);
|
|
|
|
//--- Cargamos todos los parametros
|
|
while(!FileIsEnding(fh))
|
|
{
|
|
line = FileReadString(fh);
|
|
if(line == NULL)
|
|
continue;
|
|
|
|
//---
|
|
if(line[0] == ';') // Comentarios | Sinput
|
|
{
|
|
//---
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[m_lines_size++].id = m_no_params_size;
|
|
|
|
//---
|
|
m_no_params[m_no_params_size++] = line;
|
|
if(m_no_params_size >= cn)
|
|
{
|
|
cn <<= 1;
|
|
ArrayResize(m_no_params, cn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//---
|
|
int vs = line.Find("=");
|
|
if(vs == -1)
|
|
{
|
|
LogWarning(StringFormat("Omitiendo linea corrupta:\n'%s'", line), FUNCION_ACTUAL);
|
|
continue;
|
|
}
|
|
|
|
|
|
//---
|
|
m_lines[m_lines_size].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines[m_lines_size++].id = m_params_size;
|
|
|
|
//---
|
|
m_params[m_params_size].name = StringSubstr(line, 0, vs);
|
|
if(!m_hashmap_params.Add(m_params[m_params_size].name, m_params_size))
|
|
{
|
|
LogError(StringFormat("Fallo al agregar el parametro =%s al hashmap", m_params[m_params_size].name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
vs++;
|
|
|
|
//---
|
|
const int t = StringSplitStr(StringSubstr(line, vs), "||", g_setfile_dyn_arr, 5);
|
|
if(t < 1)
|
|
{
|
|
LogCriticalError("El split debe dar como minimo 1 cadena de resultado", FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
m_params[m_params_size].value = g_setfile_dyn_arr[0];
|
|
|
|
//---
|
|
if(t == 5 && g_setfile_dyn_arr[4].Find("N") >= 0) // Optimizable
|
|
{
|
|
m_params[m_params_size].start = g_setfile_dyn_arr[1];
|
|
m_params[m_params_size].step = g_setfile_dyn_arr[2];
|
|
m_params[m_params_size].stop = g_setfile_dyn_arr[3];
|
|
}
|
|
|
|
//---
|
|
m_params_size++;
|
|
|
|
//---
|
|
if(m_params_size >= c)
|
|
{
|
|
c <<= 1;
|
|
ArrayResize(m_params, c);
|
|
}
|
|
}
|
|
|
|
//---
|
|
if(m_lines_size >= rl)
|
|
{
|
|
rl <<= 1;
|
|
ArrayResize(m_lines, rl);
|
|
}
|
|
}
|
|
|
|
//--- Truncamos
|
|
ArrayResize(m_params, m_params_size);
|
|
ArrayResize(m_no_params, m_no_params_size);
|
|
ArrayResize(m_lines, m_lines_size);
|
|
|
|
//--- Cerramos
|
|
FileClose(fh);
|
|
|
|
//---
|
|
m_init = true;
|
|
|
|
//--- Exito
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::Save(const string &file_name, int extra_file_flags)
|
|
{
|
|
//---
|
|
ResetLastError();
|
|
const int fh = FileOpen(file_name, FILE_WRITE | FILE_TXT | extra_file_flags);
|
|
if(fh == INVALID_HANDLE)
|
|
{
|
|
LogError(StringFormat("Fallo al abrir el archivo = %s, ultimo error = %d", file_name, GetLastError()), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
ChangeSavedTime(TimeLocal());
|
|
|
|
//---
|
|
for(int i = 0; i < m_lines_size; i++)
|
|
{
|
|
if(m_lines[i].type == SETFILE_LINE_TYPE_INPUT)
|
|
{
|
|
FileWrite(fh, m_params[m_lines[i].id].Format());
|
|
}
|
|
else
|
|
{
|
|
FileWrite(fh, m_no_params[m_lines[i].id]);
|
|
}
|
|
}
|
|
|
|
//---
|
|
FileClose(fh);
|
|
|
|
//---
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::GetAsString(string &out) const
|
|
{
|
|
//ArrayPrint(m_lines);
|
|
for(int i = 0; i < m_lines_size; i++)
|
|
{
|
|
if(m_lines[i].type == SETFILE_LINE_TYPE_INPUT)
|
|
{
|
|
//Print(m_lines[i].id);
|
|
out += m_params[m_lines[i].id].Format() + "\n";
|
|
}
|
|
else
|
|
{
|
|
out += m_no_params[m_lines[i].id] + "\n";
|
|
}
|
|
}
|
|
if(m_lines_size > 0)
|
|
out.Truncate(out.Length() - 1);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CSetFile::GetAsStringArray(string &out[]) const
|
|
{
|
|
int s = ArrayResize(out, m_lines_size);
|
|
for(int i = 0; i < m_lines_size; i++)
|
|
{
|
|
if(m_lines[i].type == SETFILE_LINE_TYPE_INPUT)
|
|
{
|
|
out[i] = m_params[m_lines[i].id].Format();
|
|
}
|
|
else
|
|
{
|
|
out[i] = m_no_params[m_lines[i].id];
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::Summary(void) const
|
|
{
|
|
Print("---- Expert name: ", m_expert_name);
|
|
Print(" Saved time: ", m_saved_time);
|
|
Print(" Total lines: ", m_lines_size);
|
|
Print(" Total params: ", m_params_size);
|
|
Print(" Total no params: ", m_no_params_size);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::Imprimir(void) const
|
|
{
|
|
string str = "";
|
|
GetAsString(str);
|
|
Print(str);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline SetFileParam CSetFile::GetParam(const string str) const
|
|
{
|
|
//---
|
|
static int real_idx;
|
|
((CSetFile*)&this).m_hashmap_params.TryGetValue(str, real_idx);
|
|
return m_params[real_idx]; // Sin comprobacion en caso de error INVALID
|
|
// La idea es que si el parametro es invalido (no existe) y se llame a esta funcion entonces de error
|
|
// En caso de las demas funcoines se retonan un bool (por algo) para saber si se modifico o no
|
|
// En cambio aqui retonamos directamente un valor
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
__forceinline int CSetFile::GetParamIdx(const string str) const
|
|
{
|
|
//---
|
|
int real_idx = INVALID_INDEX;
|
|
((CSetFile*)&this).m_hashmap_params.TryGetValue(str, real_idx);
|
|
return real_idx;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Modificar el nombre del parametro |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamName(const int idx, const string &new_name)
|
|
{
|
|
//---
|
|
const int real_idx = m_lines[idx].id;
|
|
|
|
//---
|
|
if(!m_hashmap_params.Remove(m_params[real_idx].name))
|
|
{
|
|
LogError(StringFormat("No se pudo remover del hashmap, param name = %s", m_params[real_idx].name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
m_params[real_idx].name = new_name;
|
|
|
|
//---
|
|
if(m_hashmap_params.Add(new_name, real_idx))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("No se pudo agregatr el parametro con nombre = %s, al hashamp", new_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamName(const string param_name, const string &new_name)
|
|
{
|
|
//---
|
|
static int real_idx;
|
|
|
|
//---
|
|
if(!m_hashmap_params.TryGetValue(param_name, real_idx))
|
|
{
|
|
LogError(StringFormat("El parametro = %s, no existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
if(!m_hashmap_params.Remove(m_params[real_idx].name))
|
|
{
|
|
LogError(StringFormat("No se pudo remover del hashmap, param name = %s", m_params[real_idx].name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
m_params[real_idx].name = new_name;
|
|
|
|
//---
|
|
if(m_hashmap_params.Add(new_name, real_idx))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("No se pudo agregatr el parametro con nombre = %s, al hashamp", new_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Modify value |
|
|
//+------------------------------------------------------------------+
|
|
template <typename TInteger>
|
|
bool CSetFile::ModifyParamValueNumber(const string param_name, const TInteger v)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].value = string(v);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TNumber>
|
|
bool CSetFile::ModifyParamValueRealNumber(const string param_name, const TNumber v, int8_t presicion)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].value = DoubleToString(v, presicion);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamValueBoolean(const string param_name, const bool v)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].value = v ? "true" : "false";
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamValueString(const string param_name, const string v)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].value = v;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TEnum>
|
|
bool CSetFile::ModifyParamValueEnum(const string param_name, const TEnum v)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].value = string((int)v);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamValueDatetime(const string param_name, const datetime v)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].value = string(long(v));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamValueColor(const string param_name, const color v)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].value = string((int)v);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Modify datetime |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamOptDatetimeStart(const string param_name, const datetime start)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].start = string(long(start));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamOptDatetimeStep(const string param_name, const long step_sec)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].step = string(step_sec);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ModifyParamOptDatetimeStop(const string param_name, const datetime stop)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].stop = string(long(stop));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Modificar Number Opt |
|
|
//+------------------------------------------------------------------+
|
|
template <typename TInteger>
|
|
bool CSetFile::ModifyParamOptNumberStart(const string param_name, const TInteger start)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].start = string(start);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TInteger>
|
|
bool CSetFile::ModifyParamOptNumberStep(const string param_name, const TInteger step)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].step = string(step);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TInteger>
|
|
bool CSetFile::ModifyParamOptNumberStop(const string param_name, const TInteger stop)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].stop = string(stop);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Modificar Real Number Opt |
|
|
//+------------------------------------------------------------------+
|
|
template <typename TNumber>
|
|
bool CSetFile::ModifyParamOptRealNumberStart(const string param_name, const TNumber start, int8_t presicion)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].start = DoubleToString(start, presicion);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TNumber>
|
|
bool CSetFile::ModifyParamOptRealNumberStep(const string param_name, const TNumber step, int8_t presicion)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].step = DoubleToString(step, presicion);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TNumber>
|
|
bool CSetFile::ModifyParamOptRealNumberStop(const string param_name, const TNumber stop, int8_t presicion)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].stop = DoubleToString(stop, presicion);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Enum |
|
|
//+------------------------------------------------------------------+
|
|
template <typename TEnum>
|
|
bool CSetFile::ModifyParamOptEnumStart(const string param_name, const TEnum start)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].start = string((int)start);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TEnum>
|
|
bool CSetFile::ModifyParamOptEnumStop(const string param_name, const TEnum stop)
|
|
{
|
|
static int idx;
|
|
if(m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
m_params[idx].stop = string((int)stop);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Funcion general para remover una linea |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::RemoveLine(const int idx)
|
|
{
|
|
//---
|
|
const int ri = m_lines[idx].id;
|
|
const ENUM_SETFILE_LINE_TYPE type = m_lines[idx].type;
|
|
for(int i = idx; i < m_lines_size - 1; i++)
|
|
{
|
|
m_lines[i] = m_lines[i + 1];
|
|
}
|
|
ArrayResize(m_lines, (--m_lines_size));
|
|
//---
|
|
/*
|
|
S = Parametro REAl Pararm (params)
|
|
N = No paramero (no_params)
|
|
LTYPE= Tipo de linea, como valores toma 2 = [S, N]
|
|
|
|
# Ejemplo de array
|
|
m_lines m_params m_no_params
|
|
LTYPE PARAMIDX NOPARAMIDX
|
|
S 0 -
|
|
S 1 -
|
|
S 2 -
|
|
S 3 -
|
|
S 4 -
|
|
|
|
# Eliminamos linea 0
|
|
m_lines m_params m_no_params
|
|
LTYPE PARAMIDX NOPARAMIDX
|
|
S 1 -
|
|
S 2 -
|
|
S 3 -
|
|
S 4 -
|
|
|
|
# Aqui habria que reducir paramidx en los restantes?¿
|
|
Ahora mismo pasaria esto:
|
|
Hariamos un swap entre elemtno eliminamo y utlimo
|
|
asi que se camiba de posicon 4->0
|
|
asi que el indice sero apunta al 4
|
|
|
|
m_lines m_params m_no_params
|
|
LTYPE PARAMIDX NOPARAMIDX
|
|
S 1 -
|
|
S 2 -
|
|
S 3 -
|
|
S 0 -
|
|
|
|
# Vale enotnces deberimaos de ubicar y reponde "Donde se ubica el linea con real index = last" ?
|
|
# Una vez tengamos su indice poor ejemplo en nuestro ejemplo seria el indice 4 entonces modificamos m_lines[4].id = ri
|
|
*/
|
|
|
|
//---
|
|
if(type == SETFILE_LINE_TYPE_INPUT)
|
|
{
|
|
//---
|
|
if(!m_hashmap_params.Remove(m_params[ri].name))
|
|
{
|
|
LogError(StringFormat("Fallo al eliminar el parametro '%s' del hashmap", m_params[ri].name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
const int last = (--m_params_size);
|
|
if(ri != last) // Solo si no es igual no es 0 como minimo hayt 1 elemneo
|
|
{
|
|
m_params[ri] = m_params[last];
|
|
|
|
if(!m_hashmap_params.TrySetValue(m_params[ri].name, ri))
|
|
{
|
|
LogError(StringFormat("Error al modificar el valor de %s a idx = %d", m_params[ri].name, ri), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//---
|
|
// Ahora su RI de ester parametro cambia ya no apunta a
|
|
for(int i = 0; i < m_lines_size; i++)
|
|
{
|
|
if(m_lines[i].type == SETFILE_LINE_TYPE_INPUT && m_lines[i].id == last) //
|
|
{
|
|
m_lines[i].id = ri;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---
|
|
ArrayResize(m_params, m_params_size);
|
|
}
|
|
else
|
|
{
|
|
int last = --m_no_params_size;
|
|
if(ri != last)
|
|
{
|
|
m_no_params[ri] = m_no_params[last];
|
|
for(int i = 0; i < m_lines_size; i++) // Redirigir la linea que apuntaba a last
|
|
{
|
|
if(m_lines[i].type == SETFILE_LINE_TYPE_NOINPUT && m_lines[i].id == last)
|
|
{
|
|
m_lines[i].id = ri;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ArrayResize(m_no_params, m_no_params_size);
|
|
}
|
|
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Funciones para trabnajar con lineas no param |
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::AddNoParamsLine(const string &line)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_no_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
ArrayResize(m_no_params, m_no_params_size + 1);
|
|
m_no_params[m_no_params_size++] = line;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::InsertNoParamLine(const int idx, const string &line)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_NOINPUT;
|
|
m_lines[idx].id = m_no_params_size;
|
|
m_lines_size++;
|
|
|
|
ArrayResize(m_no_params, m_no_params_size + 1);
|
|
m_no_params[m_no_params_size++] = line;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::ModifyNoParamLine(const int idx, const string &new_line)
|
|
{
|
|
// NO hay check de idx
|
|
m_no_params[m_lines[idx].id] = new_line;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Añadir parametros al final |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::AddParamLineString(const string &name, const string &value)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_INPUT;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size++].value = value;
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TInteger>
|
|
bool CSetFile::AddParamLineNumber(const string &name, const TInteger value, const TInteger start, const TInteger step, const TInteger stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_INPUT;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = string(value);
|
|
m_params[m_params_size].start = string(start);
|
|
m_params[m_params_size].step = string(step);
|
|
m_params[m_params_size++].stop = string(stop);
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TNumber>
|
|
bool CSetFile::AddParamLineReal(const string &name, const TNumber value, int8_t presicion, const TNumber start, const TNumber step, const TNumber stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_INPUT;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = DoubleToString(value, presicion);
|
|
m_params[m_params_size].start = DoubleToString(start, presicion);
|
|
m_params[m_params_size].step = DoubleToString(step, presicion);
|
|
m_params[m_params_size++].stop = DoubleToString(stop, presicion);
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::AddParamLineBool(const string &name, const bool value)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_INPUT;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = value ? "true" : "false";
|
|
m_params[m_params_size].start = "false";
|
|
m_params[m_params_size].step = "0";
|
|
m_params[m_params_size++].stop = "true";
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TEnum>
|
|
bool CSetFile::AddParamLineEnum(const string &name, const TEnum value, const TEnum start, const TEnum stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_INPUT;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = string((int)value);
|
|
m_params[m_params_size].start = string((int)start);
|
|
m_params[m_params_size].step = "0";
|
|
m_params[m_params_size++].stop = string((int)stop);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::AddParamLineDatetime(const string &name, const datetime value, const datetime start, const long step_sec, const datetime stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_INPUT;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = string(long(value));
|
|
m_params[m_params_size].start = string(long(start));
|
|
m_params[m_params_size].step = string(step_sec);
|
|
m_params[m_params_size++].stop = string(long(stop));
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::AddParamLineColor(const string &name, const color value)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
m_lines[m_lines_size].id = m_params_size;
|
|
m_lines[m_lines_size++].type = SETFILE_LINE_TYPE_INPUT;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size++].value = string((int)value);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::InsertParamLineString(const int idx, const string &name, const string &value)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].id = m_params_size;
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines_size++;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size++].value = value;
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template <typename TInteger>
|
|
bool CSetFile::InsertParamLineNumber(const int idx, const string &name, const TInteger value, const TInteger start, const TInteger step, const TInteger stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].id = m_params_size;
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines_size++;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = string(value);
|
|
m_params[m_params_size].start = string(start);
|
|
m_params[m_params_size].step = string(step);
|
|
m_params[m_params_size++].stop = string(stop);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template <typename TNumber>
|
|
bool CSetFile::InsertParamLineReal(const int idx, const string &name, const TNumber value, int8_t presicion, const TNumber start, const TNumber step, const TNumber stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].id = m_params_size;
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines_size++;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = DoubleToString(value, presicion);
|
|
m_params[m_params_size].start = DoubleToString(start, presicion);
|
|
m_params[m_params_size].step = DoubleToString(step, presicion);
|
|
m_params[m_params_size++].stop = DoubleToString(stop, presicion);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::InsertParamLineBool(const int idx, const string &name, const bool value)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].id = m_params_size;
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines_size++;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = value ? "true" : "false";
|
|
m_params[m_params_size].start = "false";
|
|
m_params[m_params_size].step = "0";
|
|
m_params[m_params_size++].stop = "true";
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
template <typename TEnum>
|
|
bool CSetFile::InsertParamLineEnum(const int idx, const string &name, const TEnum value, const TEnum start, const TEnum stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].id = m_params_size;
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines_size++;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = string((int)value);
|
|
m_params[m_params_size].start = string((int)start);
|
|
m_params[m_params_size].step = "0";
|
|
m_params[m_params_size++].stop = string((int)stop);
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::InsertParamLineDatetime(const int idx, const string &name, const datetime value, const datetime start, const long step_sec, const datetime stop)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].id = m_params_size;
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines_size++;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size].value = string(long(value));
|
|
m_params[m_params_size].start = string(long(start));
|
|
m_params[m_params_size].step = string(step_sec);
|
|
m_params[m_params_size++].stop = string(long(stop));
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::InsertParamLineColor(const int idx, const string &name, const color value)
|
|
{
|
|
ArrayResize(m_lines, m_lines_size + 1);
|
|
for(int i = m_lines_size; i > idx; i--)
|
|
m_lines[i] = m_lines[i - 1];
|
|
m_lines[idx].id = m_params_size;
|
|
m_lines[idx].type = SETFILE_LINE_TYPE_INPUT;
|
|
m_lines_size++;
|
|
if(!m_hashmap_params.Add(name, m_params_size))
|
|
{
|
|
LogError(StringFormat("No se puede agregar el parametro con el nombre = %s", name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
ArrayResize(m_params, m_params_size + 1);
|
|
m_params[m_params_size].name = name;
|
|
m_params[m_params_size++].value = string((int)value);
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Read value |
|
|
//+------------------------------------------------------------------+
|
|
string CSetFile::ReadParamValueString(const string param_name) const
|
|
{
|
|
static int idx;
|
|
if(!((CSetFile*)&this).m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return NULL;
|
|
}
|
|
return m_params[idx].value;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TInteger>
|
|
TInteger CSetFile::ReadParamValueInteger(const string param_name) const
|
|
{
|
|
static int idx;
|
|
if(!((CSetFile*)&this).m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return (TInteger)0;
|
|
}
|
|
return TInteger(m_params[idx].value);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
template <typename TNumber>
|
|
TNumber CSetFile::ReadParamValueReal(const string param_name) const
|
|
{
|
|
static int idx;
|
|
if(!((CSetFile*)&this).m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return (TNumber)0.0;
|
|
}
|
|
return TNumber(m_params[idx].value);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
datetime CSetFile::ReadParamValueDatetime(const string param_name) const
|
|
{
|
|
static int idx;
|
|
if(!((CSetFile*)&this).m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return 0;
|
|
}
|
|
return datetime(long(m_params[idx].value));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
color CSetFile::ReadParamValueColor(const string param_name) const
|
|
{
|
|
static int idx;
|
|
if(!((CSetFile*)&this).m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return clrNONE;
|
|
}
|
|
return color(int(m_params[idx].value));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
bool CSetFile::ReadParamValueBool(const string param_name) const
|
|
{
|
|
static int idx;
|
|
if(!((CSetFile*)&this).m_hashmap_params.TryGetValue(param_name, idx))
|
|
{
|
|
LogError(StringFormat("El parametro '%s' No existe", param_name), FUNCION_ACTUAL);
|
|
return false;
|
|
}
|
|
return m_params[idx].value == "true";
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CSetFile::ChangeSavedTime(const datetime new_time)
|
|
{
|
|
if(m_lines_size < 1)
|
|
{
|
|
LogCriticalError("SetFile vacio", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
|
|
//---
|
|
const int ri = m_lines[0].id;
|
|
|
|
//---
|
|
int len = StringLen(m_no_params[ri]);
|
|
int pos = 0;
|
|
while(m_no_params[ri][pos] < '0' || m_no_params[ri][pos] > '9') // Solo iterar mientras el caracter pos no sea un nuemro
|
|
{
|
|
pos++;
|
|
if(pos >= len)
|
|
{
|
|
LogError("En la primera linea debe de ubicarse un nuermo (fecha de creacion)", FUNCION_ACTUAL);
|
|
return;
|
|
}
|
|
}
|
|
// Truincamos el nombre del string hasta el pos (la idea es eliminar el time)
|
|
m_no_params[ri].Truncate(pos);
|
|
m_no_params[ri] += TimeToString(new_time, TIME_MINUTES | TIME_DATE | TIME_SECONDS);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
#endif // MQLARTICLES_UTILS_SETFILES_MAIN_MQH
|