//+------------------------------------------------------------------+ //| 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 }; //--- Function type definition to manage different calculation modes typedef void(*FuncionCDiffOnBar)(double atr_mul, double atr_val, double &diff_prev); //--- Function to calculate difference based on ATR inline void Diff_OnBarFuncionAtr(double atr_mul, double atr_val, double &diff_prev) { diff_prev = atr_mul * atr_val; } //--- Function to calculate difference based on points (does nothing, as it's set during initialization) inline void Diff_OnBarFuncionPoint(double atr_mul, double atr_val, double &diff_prev) { return; } //+-------------------------------------------------------------------------+ //| Class CDiff - Difference calculation based on ATR or fixed points | //+-------------------------------------------------------------------------+ /* ESP: Para usar la clase, solo se puede setear una vez.. 1. llame y configure el modo SetMode 2. Luego condigura SetAtr y SetMode Nota: El atr, ya debera de copiar los datos que luego seran accedios por esta clase, la clase unicamente calcula la diferencia. ENG: To use the class, you can only set it once. 1. Call and set the SetMode mode. 2. Then set SetAtr and SetMode. Note: The atr should already copy the data that will later be accessed by this class, the class only calculates the difference. */ //--- class CDiff : public CLoggerBase { private: //--- bool set_atr; bool set_point; //--- int idx; // Index for ATR string symbol; // Symbol for point calculation double diff; // Calculated difference value ENUM_MODE_DIFF mode_diff; // Difference calculation mode double mul; // Multiplier for ATR CAtr* atr; // Pointer to ATR object FuncionCDiffOnBar f; // Function pointer for calculation according to mode static float empty_val; // Static empty value bool is_atr; // Flag to indicate if ATR is used //--- inline double GetVal() { return is_atr ? atr[idx] : 0.00; } public: CDiff(); CDiff(const CDiff & diff_); //--- Configuration methods void SetMode(ENUM_MODE_DIFF mode_diff_); void SetAtr(CAtr * atr_, int idx_, double mul_); void SetPoint(string symbol_, int min_diff_points_); //--- Method to update on new candle 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; //+------------------------------------------------------------------+ //| Default constructor | //+------------------------------------------------------------------+ CDiff::CDiff(void) : idx(0), set_atr(false), set_point(false), diff(0.00), mul(1.00), atr(NULL), f(NULL), is_atr(false) { // Initialize with default values } //+------------------------------------------------------------------+ //| Copy constructor | //+------------------------------------------------------------------+ 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) { } //+------------------------------------------------------------------+ //| Updates difference value based on ATR | //+------------------------------------------------------------------+ void CDiff::SetNewDiffAtrValue(const int new_idx) { if(!is_atr) //Only set diff if it's atr and valid return; this.diff = atr[new_idx] * mul; } //+------------------------------------------------------------------+ //| Sets the calculation mode | //+------------------------------------------------------------------+ void CDiff::SetMode(ENUM_MODE_DIFF mode_diff_) { //-- Don't allow changing mode if already configured if(set_atr || set_point) //If a mode has already been set then don't allow return; this.mode_diff = mode_diff_; this.is_atr = (mode_diff_ == MODE_DIFF_BY_ATR); //-- Assign the appropriate function according to mode if(mode_diff_ == MODE_DIFF_BY_ATR) f = Diff_OnBarFuncionAtr; else f = Diff_OnBarFuncionPoint; } //+------------------------------------------------------------------+ //| Changes the ATR multiplier | //+------------------------------------------------------------------+ void CDiff::AtrMul(double new_value) { if(!set_atr) //If atr hasn't been set, return return; //-- this.mul = new_value; //-- if(mul <= 0.00) { LogWarning(StringFormat("Invalid ATR multiplier ( %f ), switching to points mode", mul), __FUNCTION__); f = Diff_OnBarFuncionPoint; is_atr = false; } else { f = Diff_OnBarFuncionAtr; is_atr = true; } } //+------------------------------------------------------------------+ //| Configures calculation by points | //+------------------------------------------------------------------+ void CDiff::SetPoint(string symbol_, int min_diff_points_) { if(mode_diff != MODE_DIFF_BY_FIXED_POITNS) return; //-- if(set_point) //Points have already been set { LogError("Points mode already configured. Use DiffPoints to change", __FUNCTION__); return; } //-- this.symbol = symbol_; set_point = true; //-- if(symbol_ == "" || !SymbolInfoDouble(symbol_, SYMBOL_POINT)) { LogFatalError(StringFormat("Invalid symbol in SetPoint: %s", symbol_), __FUNCTION__); this.diff = 0; Remover(); return; } this.diff = SymbolInfoDouble(this.symbol, SYMBOL_POINT) * min_diff_points_; } //+------------------------------------------------------------------+ //| Configures calculation by ATR | //+------------------------------------------------------------------+ void CDiff::SetAtr(CAtr* atr_, int idx_, double mul_) { if(mode_diff != MODE_DIFF_BY_ATR) return; //If it's not atr then we exit //-- if(set_atr) //ATR has already been set { LogError("ATR mode already configured. Use AtrMul to change", __FUNCTION__); return; } //-- set_atr = true; //--- if(CheckPointer(atr_) == POINTER_INVALID) { LogCriticalError("Invalid ATR pointer in SetAtr", __FUNCTION__); return; } //--- if(atr_.Handle() == INVALID_HANDLE) { LogFatalError("The passed handle is invalid", FUNCION_ACTUAL); Remover(); return; } //--- if(idx_ < 0) { LogWarning(StringFormat("Invalid ATR index %d, adjusting to 0", idx_), __FUNCTION__); idx_ = 0; } //--- this.atr = atr_; this.idx = idx_; this.mul = mul_; //--- Optimize, if mul is invalid, then we use points if(mul_ <= 0.00) { LogWarning(StringFormat("Invalid ATR multiplier %f, switching to points mode", mul_), FUNCION_ACTUAL); f = Diff_OnBarFuncionPoint; is_atr = false; } } //+------------------------------------------------------------------+ //| Creates a CDiff object on the heap and returns its pointer | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Creates a CDiff object on the stack and returns it | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Class to detect if the PC has been suspended | //+------------------------------------------------------------------+ class CSuspendChecker { private: uint m_lastTick; // Last recorded tick uchar m_threshold; // Threshold in minutes datetime m_last_time_revised; public: // Constructor, sets the time threshold CSuspendChecker() { m_threshold = 2; m_lastTick = GetTickCount64Minutes; // Initialize with current time m_last_time_revised = TimeCurrent(); } // Checks if there has been a suspension bool CheckForSuspend(bool flag_new_day) { if(TESTER_FLAG) return false; const uint currentTick = GetTickCount64Minutes; m_last_time_revised = TimeCurrent(); m_lastTick = currentTick; // Update the last tick // If the difference exceeds the threshold, the PC was likely suspended 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; } }; //+------------------------------------------------------------------+ //| CConversions Class: price ↔ pixels ↔ bars | //+------------------------------------------------------------------+ class CGraphConversion { 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: CGraphConversion(long chartID = 0) : chart_id(chartID) { Update(); } // Price → pixels inline int PrecioAPixeles(double distancia_precio) { return (int)(distancia_precio * this.valor_1_unidad_precio_a_px); } // Pixels → price inline double PixelesAPrecio(int pixeles) { return pixeles * this.valor_1_px_a_unidad_precio; } // Bars → pixels inline int BarrasAPixeles(double num_barras) { return (int)(num_barras * this.valor_1_barra_a_px); } // Pixels → bars inline double PixelesABarras(int pixeles) { return pixeles * this.valor_1_px_a_barra; } // Update scale void Update() { // Vertical scale (price) 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; } // Horizontal scale (bars) 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; } } // Automatic handling of zoom and chart changes 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(); } // Extra method to get current dimensions 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("Current chart dimensions: width=%d px, height=%d px, visible bars=%d", chart_width, chart_height, barras_horizontal); } }; CGraphConversion manager_graph; //+------------------------------------------------------------------+ #endif //+------------------------------------------------------------------+