MQLArticles/Utils/FA/ClasesBases.mqh

450 lines
30 KiB
MQL5

//+------------------------------------------------------------------+
//| 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
//+------------------------------------------------------------------+