forked from nique_372/MQLArticles
496 lines
34 KiB
MQL5
496 lines
34 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| 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"
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
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;
| |
| |
//---
| |
CHashMap<double, int> m_hash_level_to_index;
| |
| |
//---
| |
int m_total_fibbo;
| |
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(string vals, 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; }
| |
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 - 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(0)
| |
{
| |
ArrayResize(m_fibbo_levels, 0);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CFibbo::Summary(void)
| |
{
| |
PrintFormat("------| Fibbo %s |------", m_obj_name);
| |
Print("Levels: ");
| |
ArrayPrint(m_fibbo_levels, 3, " | ");
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
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; 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
| |
ArrayResize(m_fibbo_levels, m_total_fibbo + 1);
| |
m_fibbo_levels[m_total_fibbo] = new_level;
| |
m_total_fibbo++;
| |
return true;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
double CFibbo::GetNearestLevel(double target_price, ENUM_MODE_NEAREST_LEVEL_FIBBO mode) const
| |
{
| |
//---
| |
if(m_total_fibbo == 0)
| |
return 0.00;
| |
| |
//---
| |
const bool precio_ascendente = (m_fibbo_levels[0].level_price < m_fibbo_levels[m_total_fibbo - 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; 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 - 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 - 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; 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.TryGetValue(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.TryGetValue(level_val, idx);
| |
return idx;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
__forceinline double CFibbo::GetLevelPrice(const double level_val)
| |
{
| |
int idx;
| |
m_hash_level_to_index.TryGetValue(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; 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; 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(string vals, 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 = ArrayResize(m_fibbo_levels, 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
| |
const string res_color = StringTrimChar(res_clrs[i]);
| |
new_level.level_color = StringToColor(res_color);
| |
| |
//--- 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, (CFibboFuncCompareLevelPrice)FibboLevel::MayorLevel);
| |
| |
//--- Agregamos al hashmap
| |
for(int i = 0; i < m_total_fibbo; 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);
| |
| |
//--- Establecemos las propiedades de los niveles en el ciclo
| |
for(int i = 0; i < m_total_fibbo; 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);
| |
}
| |
//+------------------------------------------------------------------+
| |
#endif // MQLARTICLES_UTILS_FIBONACCI_MQH
| |
//+------------------------------------------------------------------+
|