2026-09-12 19:41:52 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| Fibonacci.mqh |
|
| | | //| Copyright 2025, Niquel Mendoza. |
|
| | | //| https://www.mql5.com |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2025, Niquel Mendoza."
|
| | | #property link "https://www.mql5.com"
|
| | | #property strict
|
| | |
|
| | | #ifndef MQLARTICLES_UTILS_FIBONACCI_MQH
|
| | | #define MQLARTICLES_UTILS_FIBONACCI_MQH
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #include "..\\Utils\\GraphicObjects.mqh"
|
| | | #include "FA\\Sort.mqh"
|
| | | #include <TSN\\GCol\\HashMap.mqh>
|
| | | #include <TSN\\GCol\\GenericHashes.mqh>
|
| | |
|
2026-09-13 08:47:52 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
2026-09-12 19:41:52 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | struct pack(8) FibboLevel
|
| | | {
|
| | | double level_price;
|
| | | double level_value;
|
| | | color level_color;
|
| | |
|
| | | FibboLevel()
|
| | | : level_color(clrBlack), level_price(0.00), level_value(0.00)
|
| | | {
|
| | |
|
| | | }
|
| | | FibboLevel(const FibboLevel& other)
|
| | | {
|
| | | this = other;
|
| | | }
|
| | |
|
| | | //---
|
| | | static __forceinline bool MayorLevel(const FibboLevel& f1, const FibboLevel& f2)
|
| | | {
|
| | | return f1.level_value > f2.level_value;
|
| | | }
|
| | | };
|
| | |
|
| | | enum ENUM_MODE_NEAREST_LEVEL_FIBBO
|
| | | {
|
| | | FIBBO_LEVEL_MAYOR_A_TARGE_PRICE = 0,
|
| | | FIBBO_LEVEL_MENOR_A_TARGE_PRICE,
|
| | | };
|
| | |
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | class CFibbo : public CLoggerBase
|
| | | {
|
| | | private:
|
| | | //--- Caracteristicas principales
|
| | | long m_chart_id;
|
| | | int m_subwin;
|
| | | bool m_create; //Indica si el fibbo ha sido creado
|
| | |
|
| | | //--- Caracteristicas del fibbo
|
| | | string m_obj_name;
|
| | | double m_price_2;
|
| | | double m_price_1;
|
| | | datetime m_init_fibbo;
|
| | |
|
| | | //---
|
| | | CHashMapFastP(double, int, _fibbo) m_hash_level_to_index;
|
| | |
|
| | | //---
|
| | | int m_total_fibbo_s;
|
| | | int m_total_fibbo_r;
|
| | | FibboLevel m_fibbo_levels[];
|
| | |
|
| | |
|
| | | //--- Add
|
| | | bool AddLevel(const FibboLevel &new_level);
|
| | |
|
| | | //---
|
| | | void CalculatePriceLevelsFibbo();
|
| | |
|
| | | public:
|
| | | CFibbo();
|
| | | ~CFibbo(void);
|
| | | //--- Creacion
|
| | | bool Create(const long chart_ID,
|
| | | const string name,
|
| | | const int sub_window,
|
| | | const color clr,
|
| | | const ENUM_LINE_STYLE style,
|
| | | const int width,
|
| | | const string tooltip,
|
| | | const bool back = false,
|
| | | const bool selection = false,
|
| | | const long z_order = 0);
|
| | |
|
| | |
|
| | | //--- Seteo - Modifiacion de nivel-niveeles
|
| | | bool SetLevels(const string& vals, const string& clrs, ENUM_LINE_STYLE styles, int widths, ushort separator_str);
|
| | | __forceinline uint8_t ModifyLevel(double level, color new_color = clrNONE, ENUM_LINE_STYLE new_style = WRONG_VALUE, int new_widt = -1);
|
| | | uint8_t ModifyLevel(int level_index, color new_color = clrNONE, ENUM_LINE_STYLE new_style = WRONG_VALUE, int new_widt = -1);
|
| | |
|
| | | //--- Funciones para trabajar con el objeto grafico
|
| | | void Move(datetime new_init, datetime new_end, double price1, double price2); // Momer el fibbo completamente
|
| | | __forceinline void UpdateTime2(datetime new_end); //Solo actulizar el fibbo a un nuevo time2
|
| | | bool Hide() const { return HIDE_OBJECT(m_obj_name, m_chart_id); }
|
| | | bool Show() const { return SHOW_OBJECT(m_obj_name, m_chart_id); }
|
| | |
|
| | | //--- Funciones para trabajar con niveles
|
| | | // Obtiene el precio de un nivel por su el valor del nivel
|
| | | __forceinline double GetLevelPrice(const double level_val);
|
| | |
|
| | | // Obtiene el precio de un nivel por su indice real
|
| | | __forceinline double GetLevelPrice(const int level_index) const { return m_fibbo_levels[level_index].level_price; }
|
| | |
|
| | | // Obtiene el indice en el array de un nivel
|
| | | __forceinline int GetLevelIndex(const double level_val);
|
| | |
|
| | | // Obtiene los niveles del fibbo
|
| | | void GetArrayLevel(double &levels[], bool contains_lebel_0_100 = false) const;
|
| | | double GetNearestLevel(double target_price, ENUM_MODE_NEAREST_LEVEL_FIBBO mode) const;
|
| | |
|
| | | //--- Getters y Setters generales
|
| | | // Generales
|
| | | inline int TotalFibboLevels() const { return m_total_fibbo_s; }
|
| | | inline double Price1() const { return m_price_1; }
|
| | | inline double Price2() const { return m_price_2; }
|
| | | inline datetime InitTime() const { return m_init_fibbo; }
|
| | | inline long ChartId() const { return m_chart_id; }
|
| | | inline int Subwin() const { return m_subwin; }
|
| | | __forceinline int FibboLevelLastIndex() const { return m_total_fibbo_s - 1; }
|
| | |
|
| | | // Obtencion de un nivel
|
| | | // Por indice
|
| | | __forceinline FibboLevel GetLevelByIndex(const int idx) const { return m_fibbo_levels[idx]; }
|
| | |
|
| | | // Por valor
|
| | | __forceinline FibboLevel GetLevelByValue(const double val) { return m_fibbo_levels[GetLevelIndex(val)]; }
|
| | |
|
| | |
|
| | |
|
| | | //--- Info
|
| | | void Summary();
|
| | | };
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CFibbo::~CFibbo()
|
| | | {
|
| | | ObjectDelete(m_chart_id, m_obj_name);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | CFibbo::CFibbo()
|
| | | : m_init_fibbo(wrong_datetime), m_price_2(0.00), m_price_1(0.00), m_subwin(0), m_chart_id(0), m_total_fibbo_s(0), m_total_fibbo_r(4)
|
| | | {
|
| | | ArrayResize(m_fibbo_levels, m_total_fibbo_r, m_total_fibbo_r);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void CFibbo::Summary(void)
|
| | | {
|
| | | PrintFormat("------| Fibbo %s |------", m_obj_name);
|
| | | Print("Levels: ");
|
| | | ArrayPrint(m_fibbo_levels, 3, " | ", 0, m_total_fibbo_s);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CFibbo::AddLevel(const FibboLevel &new_level)
|
| | | {
|
| | | //--- Verificar si esta dentro
|
| | | //Considerar esto, de pormedio un fibbo level como maximo tiene 3 decimales
|
| | | #define CFIBBO_MIN_VALUE 0.00040
|
| | | for(int i = 0; i < m_total_fibbo_s; i++)
|
| | | {
|
| | | if(fabs(m_fibbo_levels[i].level_value - new_level.level_value) <= CFIBBO_MIN_VALUE)
|
| | | {
|
| | | LogWarning(StringFormat("No se agregara el fibbo level %f dado que ya existe", new_level.level_value), FUNCION_ACTUAL);
|
| | | return false;
|
| | | }
|
| | | }
|
| | |
|
| | | //--- Añadir
|
| | | if(m_total_fibbo_s >= m_total_fibbo_r)
|
| | | {
|
| | | m_total_fibbo_r <<= 1;
|
| | | ArrayResize(m_fibbo_levels, m_total_fibbo_r, m_total_fibbo_r);
|
| | | }
|
| | | m_fibbo_levels[m_total_fibbo_s++] = new_level;
|
| | | return true;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | double CFibbo::GetNearestLevel(double target_price, ENUM_MODE_NEAREST_LEVEL_FIBBO mode) const
|
| | | {
|
| | | //---
|
| | | if(m_total_fibbo_s == 0)
|
| | | return 0.00;
|
| | |
|
| | | //---
|
| | | const bool precio_ascendente = (m_fibbo_levels[0].level_price < m_fibbo_levels[m_total_fibbo_s - 1].level_price);
|
| | |
|
| | | //---
|
| | | if(mode == FIBBO_LEVEL_MAYOR_A_TARGE_PRICE)
|
| | | {
|
| | | if(precio_ascendente)
|
| | | {
|
| | | // Buscar de menor a mayor
|
| | | for(int i = 0; i < m_total_fibbo_s; i++)
|
| | | if(m_fibbo_levels[i].level_price > target_price)
|
| | | return m_fibbo_levels[i].level_price;
|
| | | }
|
| | | else
|
| | | {
|
| | | // Buscar de mayor a menor (invertido)
|
| | | for(int i = m_total_fibbo_s - 1; i >= 0; i--)
|
| | | if(m_fibbo_levels[i].level_price > target_price)
|
| | | return m_fibbo_levels[i].level_price;
|
| | | }
|
| | | }
|
| | | else
|
| | | {
|
| | | if(precio_ascendente)
|
| | | {
|
| | | // Buscar el último menor
|
| | | for(int i = m_total_fibbo_s - 1; i >= 0; i--)
|
| | | if(m_fibbo_levels[i].level_price < target_price)
|
| | | return m_fibbo_levels[i].level_price;
|
| | | }
|
| | | else
|
| | | {
|
| | | // Buscar el primero menor (en orden descendente)
|
| | | for(int i = 0; i < m_total_fibbo_s; i++)
|
| | | if(m_fibbo_levels[i].level_price < target_price)
|
| | | return m_fibbo_levels[i].level_price;
|
| | | }
|
| | | }
|
| | |
|
| | | //---
|
| | | LogWarning(StringFormat("No se ha encontrado nivel cercano al target price = %.*f", 5, target_price), FUNCION_ACTUAL);
|
| | | return 0.00;
|
| | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CFibbo::Create(const long chart_ID,
|
| | | const string name,
|
| | | const int sub_window,
|
| | | const color clr,
|
| | | const ENUM_LINE_STYLE style,
|
| | | const int width,
|
| | | const string tooltip,
|
| | | const bool back = false,
|
| | | const bool selection = false,
|
| | | const long z_order = 0)
|
| | | {
|
| | |
|
| | | //---
|
| | | if(m_create)
|
| | | {
|
| | | LogWarning("Se esta volviendo a redibujar el objeto fibbo..", FUNCION_ACTUAL);
|
| | | }
|
| | |
|
| | | //---
|
| | | m_chart_id = chart_ID;
|
| | | m_subwin = sub_window;
|
| | | const bool res = FiboLevelsCreate(chart_ID, name, sub_window, 0, 0, 0, 0, clr, style, width, back, selection, false, false, z_order);
|
| | | m_obj_name = name;
|
| | |
|
| | | //---
|
| | | if(!res)
|
| | | {
|
| | | LogError(StringFormat("No se pudo crear el fibbo[ %s ], ultimo error = %d", name, GetLastError()), FUNCION_ACTUAL);
|
| | | }
|
| | | else
|
| | | {
|
| | | ObjectSetString(chart_ID, name, OBJPROP_TOOLTIP, tooltip);
|
| | | m_create = true;
|
| | | }
|
| | | return res;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | void CFibbo::GetArrayLevel(double &levels[], bool contains_lebel_0_100 = false) const
|
| | | {
|
| | | for(int i = 0; i < ArraySize(m_fibbo_levels) ; i++)
|
| | | {
|
| | | if(!contains_lebel_0_100 && (m_fibbo_levels[i].level_value == 0.00 || m_fibbo_levels[i].level_value == 1.00))
|
| | | continue;
|
| | | AddArrayNoVerification(levels, m_fibbo_levels[i].level_value, 0);
|
| | | }
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #define FIBBO_FLAG_LEVEL_MODIFY_COLOR_SUCCESS 1
|
| | | #define FIBBO_FLAG_LEVEL_MODIFY_STYLE_SUCCESS 2
|
| | | #define FIBBO_FLAG_LEVEL_MODIFY_WIDTH_SUCCESS 4
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | __forceinline uint8_t CFibbo::ModifyLevel(double level, color new_color = clrNONE, ENUM_LINE_STYLE new_style = -1, int new_widt = -1)
|
| | | {
|
| | | int level_index;
|
| | | return m_hash_level_to_index.TryGet(level, level_index) ? ModifyLevel(level_index, new_color, new_style, new_widt) : 0;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | uint8_t CFibbo::ModifyLevel(int level_index, color new_color = clrNONE, ENUM_LINE_STYLE new_style = -1, int new_widt = -1)
|
| | | {
|
| | | //---
|
| | | uint8_t f = 0;
|
| | |
|
| | | //---
|
| | | if(new_color != clrNONE && ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_LEVELCOLOR, level_index, new_color))
|
| | | f |= FIBBO_FLAG_LEVEL_MODIFY_COLOR_SUCCESS;
|
| | |
|
| | | //---
|
| | | if(new_style != WRONG_VALUE && ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_LEVELSTYLE, level_index, new_style))
|
| | | f |= FIBBO_FLAG_LEVEL_MODIFY_STYLE_SUCCESS;
|
| | |
|
| | | //---
|
| | | if(new_widt >= 1 && ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_LEVELWIDTH, level_index, new_widt))
|
| | | f |= FIBBO_FLAG_LEVEL_MODIFY_WIDTH_SUCCESS;
|
| | |
|
| | | return f;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | __forceinline void CFibbo::UpdateTime2(datetime new_end)
|
| | | {
|
| | | ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_TIME, 1, new_end);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | __forceinline int CFibbo::GetLevelIndex(const double level_val)
|
| | | {
|
| | | int idx;
|
| | | m_hash_level_to_index.TryGet(level_val, idx);
|
| | | return idx;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | __forceinline double CFibbo::GetLevelPrice(const double level_val)
|
| | | {
|
| | | int idx;
|
| | | m_hash_level_to_index.TryGet(level_val, idx);
|
| | | return m_fibbo_levels[idx].level_price;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | void CFibbo::CalculatePriceLevelsFibbo(void)
|
| | | {
|
| | | if(m_price_1 > m_price_2)
|
| | | {
|
| | | /*
|
| | | p1 100
|
| | |
|
| | |
|
| | | p2 p2 0
|
| | | */
|
| | | const double diff = (m_price_1 - m_price_2);
|
| | | for(int i = 0; i < m_total_fibbo_s; i++)
|
| | | m_fibbo_levels[i].level_price = ((m_price_2 + ((m_fibbo_levels[i].level_value) * diff)));
|
| | | }
|
| | | else
|
| | | if(m_price_2 > m_price_1)
|
| | | {
|
| | | /*
|
| | | p2 p2 0
|
| | |
|
| | | p1 100
|
| | | */
|
| | |
|
| | | const double diff = (m_price_2 - m_price_1);
|
| | | for(int i = 0; i < m_total_fibbo_s; i++)
|
| | | m_fibbo_levels[i].level_price = ((m_price_2 - ((m_fibbo_levels[i].level_value) * diff)));
|
| | | }
|
| | | else
|
| | | {
|
| | | LogError("Ambos precios del fibbo, 1 y 2 son iguales", FUNCION_ACTUAL);
|
| | | }
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | typedef bool (*CFibboFuncCompareLevelPrice)(const FibboLevel&, const FibboLevel&);
|
| | | void CFibbo::Move(datetime new_init, datetime new_end, double price1, double price2)
|
| | | {
|
| | | //---
|
| | | ResetLastError();
|
| | | if(!ObjectMove(m_chart_id, m_obj_name, 0, new_init, price1))
|
| | | {
|
| | | LogError(StringFormat("No se pudo movel el anclaje 0, new_init = %s >> price1 = %.5f, ultimo error = %d", TimeToString(new_init), price1, GetLastError()), FUNCION_ACTUAL);
|
| | | }
|
| | |
|
| | | //---
|
| | | ResetLastError();
|
| | | if(!ObjectMove(m_chart_id, m_obj_name, 1, new_end, price2))
|
| | | {
|
| | | LogError(StringFormat("No se pudo movel el anclaje 1, time2 = %s >> price2 = %.5f, ultimo error = %d", TimeToString(new_end), price2, GetLastError()), FUNCION_ACTUAL);
|
| | | }
|
| | |
|
| | | //---
|
| | | m_price_1 = price1;
|
| | | m_price_2 = price2;
|
| | | m_init_fibbo = new_init;
|
| | | CalculatePriceLevelsFibbo();
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CFibbo::SetLevels(const string& vals, const string& clrs, ENUM_LINE_STYLE styles, int widths, ushort separator_str)
|
| | | {
|
| | | //---
|
| | | string res_vals[];
|
| | | int num_vals;
|
| | | string res_clrs[];
|
| | | int num_clrs;
|
| | |
|
| | | //---
|
| | | if((num_vals = StringSplit(vals, separator_str, res_vals)) == -1)
|
| | | {
|
| | | LogError(StringFormat("La cadena de valores %s no contiene el separador %s o esta vacia", vals, ShortToString(separator_str)), FUNCION_ACTUAL);
|
| | | Remover();
|
| | | return false;
|
| | | }
|
| | |
|
| | | if((num_clrs = StringSplit(clrs, separator_str, res_clrs)) == -1)
|
| | | {
|
| | | LogError(StringFormat("La cadena de colores %s no contiene el separador %s o esta vacia", vals, ShortToString(separator_str)), FUNCION_ACTUAL);
|
| | | Remover();
|
| | | return false;
|
| | | }
|
| | |
|
| | | //---
|
| | | if(num_vals != num_clrs)
|
| | | {
|
| | | LogCriticalError(StringFormat("El tamaño del array de niveles %d y colores %d no son iguales", num_vals, num_clrs), FUNCION_ACTUAL);
|
| | | Remover();
|
| | | return(false);
|
| | | }
|
| | |
|
| | | //---
|
| | | m_total_fibbo_s = 0;
|
| | | m_hash_level_to_index.Clear();
|
| | |
|
| | | //---
|
| | | for(int i = 0; i < num_clrs; i++)
|
| | | {
|
| | | FibboLevel new_level;
|
| | |
|
| | | //--- para color trim, mql5 confunde con espacion asuem black
|
| | | StringTrimLeft(res_clrs[i]);
|
| | | StringTrimLeft(res_clrs[i]);
|
| | |
|
| | | //---
|
| | | new_level.level_color = StringToColor(res_clrs[i]);
|
| | |
|
| | | //--- para oduble si, si hay eopacions no importa
|
| | | new_level.level_value = StringToDouble(res_vals[i]);
|
| | | new_level.level_price = 0.00;
|
| | | AddLevel(new_level);
|
| | | }
|
| | |
|
| | | //--- Ordenamos de menor a mayor
|
| | | CSimpleSort::SortAscendente(m_fibbo_levels, m_total_fibbo_s, (CFibboFuncCompareLevelPrice)FibboLevel::MayorLevel);
|
| | |
|
| | | //--- Agregamos al hashmap
|
| | | for(int i = 0; i < m_total_fibbo_s; i++)
|
| | | m_hash_level_to_index.Add(m_fibbo_levels[i].level_value, i);
|
| | |
|
| | | //--- Info
|
| | | if(IsInfoLogEnabled())
|
| | | {
|
| | | FastLog(FUNCION_ACTUAL, INFO_TEXT, "Niveles de fibbos listos: ");
|
| | | ArrayPrint(m_fibbo_levels, 3, " | ");
|
| | | }
|
| | |
|
| | | //--- Establecemos el número de los niveles
|
| | | ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_LEVELS, m_total_fibbo_s);
|
| | |
|
| | | //--- Establecemos las propiedades de los niveles en el ciclo
|
| | | for(int i = 0; i < m_total_fibbo_s; i++)
|
| | | {
|
| | | //--- valor del nivel
|
| | | ObjectSetDouble(m_chart_id, m_obj_name, OBJPROP_LEVELVALUE, i, m_fibbo_levels[i].level_value);
|
| | | //--- color del nivel
|
| | | ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_LEVELCOLOR, i, m_fibbo_levels[i].level_color);
|
| | | //--- estilo del nivel
|
| | | ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_LEVELSTYLE, i, styles);
|
| | | //--- grosor del nivel
|
| | | ObjectSetInteger(m_chart_id, m_obj_name, OBJPROP_LEVELWIDTH, i, widths);
|
| | | //--- descripción del nivel
|
| | | ObjectSetString(m_chart_id, m_obj_name, OBJPROP_LEVELTEXT, i, DoubleToString(100 * m_fibbo_levels[i].level_value, 1));
|
| | | }
|
| | |
|
| | | //--- ejecución con éxito
|
| | | return(true);
|
| | | }
|
2026-09-13 08:47:52 -05:00 | | | }
|
2026-09-12 19:41:52 -05:00 | | | //+------------------------------------------------------------------+
|
| | | #endif // MQLARTICLES_UTILS_FIBONACCI_MQH
|
| | | //+------------------------------------------------------------------+
|