//+------------------------------------------------------------------+ //| ClasesBases.mqh | //| Copyright 2025, Niquel Mendoza. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Niquel Mendoza." #property link "https://www.mql5.com" #property strict #ifndef UTILS_FA_CLASES_BASES_MQH #define UTILS_FA_CLASES_BASES_MQH //+------------------------------------------------------------------+ //| Includes | //+------------------------------------------------------------------+ //--- (CManagerBase | CSpecializedManager) #include "Managers.mqh" //--- (CBarControler | CBarControlerFast | CAtr | CAtrOptimized | CAtrOptimizedZero | CAtrOptimizedNonZero | CAtrUltraOptimized) #include "Atr.mqh" //+------------------------------------------------------------------+ //| Clase CDiff - Defines | //+------------------------------------------------------------------+ enum ENUM_MODE_DIFF { MODE_DIFF_BY_FIXED_POITNS, // By Points MODE_DIFF_BY_ATR // By Atr }; //--- Definición del tipo de función para gestionar diferentes modos de cálculo typedef void(*FuncionCDiffOnBar)(double atr_mul, double atr_val, double &diff_prev); //--- Función para calcular diferencia basada en ATR inline void Diff_OnBarFuncionAtr(double atr_mul, double atr_val, double &diff_prev) { diff_prev = atr_mul * atr_val; } //--- Función para calcular diferencia basada en puntos (no hace nada, ya que se establece al inicializar) inline void Diff_OnBarFuncionPoint(double atr_mul, double atr_val, double &diff_prev) { return; } //+------------------------------------------------------------------+ //| Clase CDiff - Cálculo de diferencia basado en ATR o puntos fijos | //+------------------------------------------------------------------+ /* Para usar la clase, solo se puede setear una vez.. 1. llame y configure el modo SetMode 2. Luego condigura SetAtr y SetMode To use the class, you can only set it once. 1. Call and set the SetMode mode. 2. Then set SetAtr and SetMode. */ //--- class CDiff : public CLoggerBase { private: //--- bool set_atr; bool set_point; //--- int idx; // Índice para ATR string symbol; // Símbolo para cálculo de puntos double diff; // Valor de diferencia calculado ENUM_MODE_DIFF mode_diff; // Modo de cálculo de diferencia double mul; // Multiplicador para ATR CAtr* atr; // Puntero a objeto ATR FuncionCDiffOnBar f; // Puntero a función para cálculo según modo static float empty_val; // Valor vacío estático bool is_atr; // Flag para indicar si se usa ATR //--- inline double GetVal() { return is_atr ? atr[idx] : 0.00; } public: CDiff(); CDiff(const CDiff & diff_); //--- Métodos para configuración void SetMode(ENUM_MODE_DIFF mode_diff_); void SetAtr(CAtr * atr_, int idx_, double mul_); void SetPoint(string symbol_, int min_diff_points_); //--- Método para actualizar en nueva vela inline void OnNewBar() { f(mul, GetVal(), diff); } //--- inline bool AtrIsActivate() const { return is_atr; } inline ENUM_MODE_DIFF GetTypeDiff() const { return mode_diff; } inline double AtrMul() const { return mul; } void AtrMul(double new_value); inline CAtr * GetAtrPointer() const { return atr; } inline void SetNewDiffAtrValue(const int new_idx); inline void DiffPoints(int new_diff_points) { this.diff = new_diff_points * SymbolInfoDouble(this.symbol, SYMBOL_POINT); } inline int DiffPoints() const { return (int)(this.diff / SymbolInfoDouble(this.symbol, SYMBOL_POINT)); } inline double Diff() const { return diff; } }; float CDiff::empty_val = 0.00; //+------------------------------------------------------------------+ //| Constructor por defecto | //+------------------------------------------------------------------+ CDiff::CDiff(void) : idx(0), set_atr(false), set_point(false), diff(0.00), mul(1.00), atr(NULL), f(NULL), is_atr(false) { // Inicializamos con valores por defecto } //+------------------------------------------------------------------+ //| Constructor de copia | //+------------------------------------------------------------------+ CDiff::CDiff(const CDiff &diff_) : idx(diff_.idx), symbol(diff_.symbol), diff(diff_.diff), mode_diff(diff_.mode_diff), mul(diff_.mul), atr(diff_.atr), f(diff_.f), is_atr(diff_.is_atr), set_atr(diff_.set_atr), set_point(diff_.set_point) { } //+------------------------------------------------------------------+ //| Actualiza el valor de diferencia basado en ATR | //+------------------------------------------------------------------+ void CDiff::SetNewDiffAtrValue(const int new_idx) { if(!is_atr) //Solo estabelcer diff si es atr y es valido return; this.diff = atr[new_idx] * mul; } //+------------------------------------------------------------------+ //| Establece el modo de cálculo | //+------------------------------------------------------------------+ void CDiff::SetMode(ENUM_MODE_DIFF mode_diff_) { //-- No permitir cambiar el modo si ya está configurado if(set_atr || set_point) //Si ya se ha establecido un modo enotnces no permitir return; this.mode_diff = mode_diff_; this.is_atr = (mode_diff_ == MODE_DIFF_BY_ATR); //-- Asignar la función adecuada según el modo if(mode_diff_ == MODE_DIFF_BY_ATR) f = Diff_OnBarFuncionAtr; else f = Diff_OnBarFuncionPoint; } //+------------------------------------------------------------------+ //| Cambia el multiplicador ATR | //+------------------------------------------------------------------+ void CDiff::AtrMul(double new_value) { if(!set_atr) //Si no se ha seteado el atr, retun return; //-- this.mul = new_value; //-- if(mul <= 0.00) { LogWarning(StringFormat("Multiplicador ATR invalido ( %f ), cambiando a modo puntos", mul), __FUNCTION__); f = Diff_OnBarFuncionPoint; is_atr = false; } else { f = Diff_OnBarFuncionAtr; is_atr = true; } } //+------------------------------------------------------------------+ //| Configura el cálculo por puntos | //+------------------------------------------------------------------+ void CDiff::SetPoint(string symbol_, int min_diff_points_) { if(mode_diff != MODE_DIFF_BY_FIXED_POITNS) return; //-- if(set_point) //Ya se ha seteado puntos { LogError("Modo por puntos ya configurado. Use DiffPoints para cambiar", __FUNCTION__); return; } //-- this.symbol = symbol_; set_point = true; //-- if(symbol_ == "" || !SymbolInfoDouble(symbol_, SYMBOL_POINT)) { LogFatalError(StringFormat("Simbolo invalido en SetPoint: %s", symbol_), __FUNCTION__); this.diff = 0; Remover(); return; } this.diff = SymbolInfoDouble(this.symbol, SYMBOL_POINT) * min_diff_points_; } //+------------------------------------------------------------------+ //| Configura el cálculo por ATR | //+------------------------------------------------------------------+ void CDiff::SetAtr(CAtr* atr_, int idx_, double mul_) { if(mode_diff != MODE_DIFF_BY_ATR) return; //Si no es atr entonces salimos //-- if(set_atr) //Ya se ha seteado atr { LogError("Modo ATR ya configurado. Use AtrMul para cambiar", __FUNCTION__); return; } //-- set_atr = true; //--- if(CheckPointer(atr_) == POINTER_INVALID) { LogCriticalError("Puntero ATR invalido en SetAtr", __FUNCTION__); return; } //--- if(atr_.Handle() == INVALID_HANDLE) { LogFatalError("El handle pasado es invalido", FUNCION_ACTUAL); Remover(); return; } //--- if(idx_ < 0) { LogWarning(StringFormat("Indice ATR invalido %d, ajustando a 0", idx_), __FUNCTION__); idx_ = 0; } //--- this.atr = atr_; this.idx = idx_; this.mul = mul_; //--- Opimtizar, si el mul es invalido, entonces usamos puntos if(mul_ <= 0.00) { LogWarning(StringFormat("Multiplicador ATR invalido %f, cambiando a modo puntos", mul_), FUNCION_ACTUAL); f = Diff_OnBarFuncionPoint; is_atr = false; } } //+------------------------------------------------------------------+ //| Crea un objeto CDiff en el heap y devuelve su puntero | //+------------------------------------------------------------------+ CDiff* CreateDiffptr(ENUM_MODE_DIFF diff_mod, string symbol_, CAtr* atr_, int idx_, double mul_or_points) { CDiff* obj = new CDiff(); obj.SetMode(diff_mod); //-- if(diff_mod == MODE_DIFF_BY_FIXED_POITNS) obj.SetPoint(symbol_, (int)mul_or_points); else obj.SetAtr(atr_, idx_, mul_or_points); return obj; } //+------------------------------------------------------------------+ //| Crea un objeto CDiff en el stack y lo devuelve | //+------------------------------------------------------------------+ CDiff CreateDiffInstance(ENUM_MODE_DIFF diff_mod, string symbol_, CAtr* atr_, int idx_, double mul_or_points) { CDiff obj; obj.SetMode(diff_mod); //-- if(diff_mod == MODE_DIFF_BY_FIXED_POITNS) obj.SetPoint(symbol_, (int)mul_or_points); else obj.SetAtr(atr_, idx_, mul_or_points); return obj; } //+------------------------------------------------------------------+ //| Clase para detectar si la PC ha sido suspendida | //+------------------------------------------------------------------+ class CSuspendChecker { private: uint m_lastTick; // Último tick registrado uchar m_threshold; // Umbral en minutos datetime m_last_time_revised; public: // Constructor, establece el umbral de tiempo CSuspendChecker() { m_threshold = 2; m_lastTick = GetTickCount64Minutes; // Inicializa con el tiempo actual m_last_time_revised = TimeCurrent(); } // Verifica si ha habido una suspensión bool CheckForSuspend(bool flag_new_day) { if(TESTER_FLAG) return false; const uint currentTick = GetTickCount64Minutes; m_last_time_revised = TimeCurrent(); m_lastTick = currentTick; // Actualiza el último tick // Si la diferencia supera el umbral, es probable que la PC estuviera suspendida if((currentTick - m_lastTick) > m_threshold && flag_new_day == false) return true; return false; } inline datetime GetLasTimeRevised() { return this.m_last_time_revised; } inline void Threshold(uchar new_minutes) { m_threshold = new_minutes; } }; //+------------------------------------------------------------------+ //| Clase CConversions: precio ↔ píxeles ↔ barras | //+------------------------------------------------------------------+ class CConversions { private: double valor_1_unidad_precio_a_px; double valor_1_px_a_unidad_precio; double valor_1_barra_a_px; double valor_1_px_a_barra; long chart_id; public: CConversions(long chartID = 0) : chart_id(chartID) { Update(); } // Precio → píxeles inline int PrecioAPixeles(double distancia_precio) { return (int)(distancia_precio * this.valor_1_unidad_precio_a_px); } // Píxeles → precio inline double PixelesAPrecio(int pixeles) { return pixeles * this.valor_1_px_a_unidad_precio; } // Barras → píxeles inline int BarrasAPixeles(double num_barras) { return (int)(num_barras * this.valor_1_barra_a_px); } // Píxeles → barras inline double PixelesABarras(int pixeles) { return pixeles * this.valor_1_px_a_barra; } // Actualizar escala void Update() { // Escala vertical (precio) double precio_max = ChartGetDouble(chart_id, CHART_PRICE_MAX); double precio_min = ChartGetDouble(chart_id, CHART_PRICE_MIN); double dist_precio = MathAbs(precio_max - precio_min); int chart_height_px = (int)ChartGetInteger(chart_id, CHART_HEIGHT_IN_PIXELS); int chart_width_px = (int)ChartGetInteger(chart_id, CHART_WIDTH_IN_PIXELS); if(chart_height_px > 0 && dist_precio > 0) { this.valor_1_unidad_precio_a_px = (double)chart_height_px / dist_precio; this.valor_1_px_a_unidad_precio = dist_precio / (double)chart_height_px; } // Escala horizontal (barras) int barras_horizontal = (int)ChartGetInteger(chart_id, CHART_WIDTH_IN_BARS); if(chart_width_px > 0 && barras_horizontal > 0) { this.valor_1_barra_a_px = (double)chart_width_px / (double)barras_horizontal; this.valor_1_px_a_barra = (double)barras_horizontal / (double)chart_width_px; } } // Manejo automático del zoom y cambios gráficos void OnEvent(const int id, const long & lparam, const double & dparam, const string & sparam) { if(id != CHARTEVENT_CHART_CHANGE) return; if(lparam == 49 || lparam == 2) Update(); } // Método extra para obtener dimensiones actuales void ImprimirDimensionesChart() { int chart_width = (int)ChartGetInteger(chart_id, CHART_WIDTH_IN_PIXELS); int chart_height = (int)ChartGetInteger(chart_id, CHART_HEIGHT_IN_PIXELS); int barras_horizontal = (int)ChartGetInteger(chart_id, CHART_WIDTH_IN_BARS); PrintFormat("Dimensiones actuales del gráfico: ancho=%d px, alto=%d px, barras visibles=%d", chart_width, chart_height, barras_horizontal); } }; CConversions manager_graph; //+------------------------------------------------------------------+ #endif //+------------------------------------------------------------------+