//+------------------------------------------------------------------+ //| 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* 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 bool AddParamLineNumber(const string& name, const TInteger value, const TInteger start, const TInteger step, const TInteger stop); // Real template 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 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 bool InsertParamLineNumber(const int idx, const string& name, const TInteger value, const TInteger start, const TInteger step, const TInteger stop); template 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 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 // Todo tipo de numero integer uinteger | datetime | color bool ModifyParamValueNumber(const string param_name, const TInteger v); template // 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 // 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 bool ModifyParamOptNumberStart(const string param_name, const TInteger start); template bool ModifyParamOptNumberStep(const string param_name, const TInteger step); template bool ModifyParamOptNumberStop(const string param_name, const TInteger stop); // ModifyParamOptRealNumber template bool ModifyParamOptRealNumberStart(const string param_name, const TNumber start, int8_t presicion); template bool ModifyParamOptRealNumberStep(const string param_name, const TNumber step, int8_t presicion); template 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 bool ModifyParamOptEnumStart(const string param_name, const TEnum start); template 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 TInteger ReadParamValueInteger(const string param_name) const; template 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* HashMapPointer() { return m_hashmap_params; } }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CSetFile::CSetFile(void) { m_hashmap_params = new CHashMap(); 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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