MQLArticles/Utils/FA/Atr.mqh

553 lines
37 KiB
MQL5

2025-10-01 12:22:08 -05:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Atr.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372/news |
//+------------------------------------------------------------------+
2025-11-10 09:33:53 -05:00
#property copyright "Copyright 2025, Niquel Mendoza."
2025-10-01 12:22:08 -05:00
#property link "https://www.mql5.com/es/users/nique_372/news"
#property strict
#ifndef MQLARTICLES_UTILS_FA_ATR_MQH
#define MQLARTICLES_UTILS_FA_ATR_MQH
//+------------------------------------------------------------------+
//| Includes |
//+------------------------------------------------------------------+
2026-01-06 13:03:52 -05:00
#include "SimpleLogger.mqh"
2025-10-01 12:22:08 -05:00
#include "BarControler.mqh"
//+------------------------------------------------------------------+
2026-01-06 13:03:52 -05:00
2026-01-13 14:49:49 -05:00
//| Resources |
//+------------------------------------------------------------------+
2025-10-01 12:22:08 -05:00
#resource "AtrCts.ex5"
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
//+------------------------------------------------------------------+
2026-01-06 13:03:52 -05:00
//| Class to handle the atr |
//+------------------------------------------------------------------+
2026-01-13 14:49:49 -05:00
class CAtr : public CLoggerBase
2025-10-01 12:22:08 -05:00
2026-01-06 13:03:52 -05:00
{
2026-01-13 14:49:49 -05:00
private:
2025-10-01 12:22:08 -05:00
2026-01-06 13:03:52 -05:00
double arr[];
2025-10-01 12:22:08 -05:00
ENUM_TIMEFRAMES timeframe;
int handle;
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
public:
~CAtr();
CAtr();
2026-01-06 13:03:52 -05:00
//---
2025-10-01 12:22:08 -05:00
inline bool IsIdxValid(const int idx, const string& function_name) const;
2026-01-13 14:49:49 -05:00
2025-10-01 12:22:08 -05:00
2026-01-13 14:49:49 -05:00
//---
2025-10-01 12:22:08 -05:00
void SetAsSeries(bool flag);
2026-01-13 14:49:49 -05:00
inline void CopyData(int start, int count);
2025-10-01 12:22:08 -05:00
inline void CopyData(int count);
//---
void Create(ENUM_TIMEFRAMES tf, string symb, int period, bool execute_on_bar, bool hide_indicator = true);
void Create(int handle_);
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
//---
inline ENUM_TIMEFRAMES Timeframe() const { return timeframe; }
inline int Handle() const { return handle; }
void Free() { ArrayFree(arr); }
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
//---
// Para evitar erroers use el check..
double operator[](int _index) const { return arr[_index]; }
};
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
//+------------------------------------------------------------------+
//| Contructor and Destructor |
//+------------------------------------------------------------------+
CAtr::CAtr(void)
: handle(INVALID_HANDLE), timeframe(WRONG_VALUE)
{
ArrayResize(arr, 0);
}
//+------------------------------------------------------------------+
2026-01-13 14:49:49 -05:00
2025-10-01 12:22:08 -05:00
CAtr::~CAtr()
2026-01-13 14:49:49 -05:00
{
2025-10-01 12:22:08 -05:00
2026-01-13 14:49:49 -05:00
if(handle != INVALID_HANDLE)
2025-10-01 12:22:08 -05:00
IndicatorRelease(handle);
2026-01-13 14:49:49 -05:00
//Free();
2025-10-01 12:22:08 -05:00
}
2026-01-13 14:49:49 -05:00
2025-10-01 12:22:08 -05:00
//+------------------------------------------------------------------+
//| Check index |
//+------------------------------------------------------------------+
inline bool CAtr::IsIdxValid(const int idx, const string& function_name) const
{
if(int(arr.Size()) > idx && idx >= 0)
return true;
else
{
LogError(StringFormat("Acceso al array de atr denegado, indice %d fuera de rango, tama<00>o del array = %u", idx, arr.Size()), function_name);
return false;
}
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
}
//+------------------------------------------------------------------+
inline void CAtr::CopyData(int start, int count)
{
ResetLastError();
if(CopyBuffer(handle, 0, start, count, arr) < count)
LogError(StringFormat("No se pudo copiar data del indicador de atr [start %d -> count: %d], ultimo error = %d", start, count, GetLastError()), FUNCION_ACTUAL);
// FastLog(FUNCION_ACTUAL, INFO_TEXT, StringFormat("El handle del indicador es %s", (handle == INVALID_HANDLE ? "invalido" : "valido")));
}
//+------------------------------------------------------------------+
2026-02-14 17:00:45 -05:00
2025-10-01 12:22:08 -05:00
inline void CAtr::CopyData(int count)
2026-02-14 17:00:45 -05:00
{
2025-10-01 12:22:08 -05:00
ResetLastError();
if(CopyBuffer(handle, 0, 0, count, arr) < count)
2026-02-14 17:00:45 -05:00
LogError(StringFormat("No se pudo copiar data del indicador de atr [0 -> count: %d], ultimo error = %d", count, GetLastError()), FUNCION_ACTUAL);
2025-10-01 12:22:08 -05:00
2026-02-14 17:00:45 -05:00
//FastLog(FUNCION_ACTUAL, INFO_TEXT, StringFormat("El handle del indicador es %s", (handle == INVALID_HANDLE ? "invalido" : "valido")));
2025-10-01 12:22:08 -05:00
}
//+------------------------------------------------------------------+
void CAtr::Create(ENUM_TIMEFRAMES tf, string symb, int period, bool execute_on_bar, bool hide_indicator = true)
{
ResetLastError();
2026-02-14 17:00:45 -05:00
2025-10-01 12:22:08 -05:00
if(hide_indicator)
TesterHideIndicators(true);
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
int handle_ = iCustom(symb, (timeframe = tf), "::AtrCts.ex5", period, execute_on_bar);
2026-02-14 17:00:45 -05:00
2025-10-01 12:22:08 -05:00
if(hide_indicator)
TesterHideIndicators(false);
2026-01-06 13:03:52 -05:00
Create(handle_);
2025-10-01 12:22:08 -05:00
}
2026-02-14 17:00:45 -05:00
//+------------------------------------------------------------------+
2025-10-01 12:22:08 -05:00
void CAtr::Create(int handle_)
{
if(handle_ == INVALID_HANDLE)
{
LogFatalError(StringFormat("No se pudo crear el handle para el indicador atr, ultimo error = %d", GetLastError()), FUNCION_ACTUAL);
Remover();
return;
}
//---
this.handle = handle_;
int16_t atemps = 250;
double dummy[100];
//---
while(atemps-- > 0)
{
//--- Copiamos
if(CopyBuffer(handle, 0, 0, 100, dummy) != 100)
continue;
//--- Verificamos que la data sea valida
2026-02-07 08:52:57 -05:00
if(DataIsValid(dummy))
2025-10-01 12:22:08 -05:00
break;
}
2026-02-07 08:52:57 -05:00
2025-10-01 12:22:08 -05:00
}
//+------------------------------------------------------------------+
2026-02-07 08:52:57 -05:00
2025-10-01 12:22:08 -05:00
void CAtr::SetAsSeries(bool flag)
{
ArraySetAsSeries(this.arr, flag);
}
//+------------------------------------------------------------------+
2026-01-06 13:03:52 -05:00
2025-10-01 12:22:08 -05:00
bool DataIsValid(const double &arr[])
{
for(int i = 0; i < (int)arr.Size(); i++)
{
2026-02-14 17:00:45 -05:00
if(arr[i] == 0.00 || arr[i] == EMPTY_VALUE)
2025-10-01 12:22:08 -05:00
return false;
}
2026-02-14 17:00:45 -05:00
2025-10-01 12:22:08 -05:00
return true;
}
2026-02-14 17:00:45 -05:00
2025-10-01 12:22:08 -05:00
//+------------------------------------------------------------------+
//| Base class to implement the atr |
//+------------------------------------------------------------------+
class CAtrOptimized : public CLoggerBase
{
protected:
ENUM_TIMEFRAMES m_timeframe;
string m_symbol;
int m_index;
int m_period;
double m_atr_value; // Valor ATR espec<EFBFBD>fico para m_index
double wilder_factor;
double inv_period;
//---
double high[];
double low[];
double close[];
double atr[];
//---
CBarControler* controler_curr;
inline double CalculeTrueRange(int idx);
inline double CalculeTrueRangeForIndexCts(int index);
bool CopyData();
public:
CAtrOptimized(ENUM_TIMEFRAMES tf, const string& symbol, int index, int period);
~CAtrOptimized(void);
virtual inline double GetAtrValue(const datetime curr_time) = 0;
2026-02-14 17:00:45 -05:00
};
2025-10-01 12:22:08 -05:00
//+------------------------------------------------------------------+
2026-02-14 17:00:45 -05:00
2025-10-01 12:22:08 -05:00
//| Constructor and destructor |
//+------------------------------------------------------------------+
2026-01-06 13:03:52 -05:00
CAtrOptimized::CAtrOptimized(ENUM_TIMEFRAMES tf, const string& symbol, int index, int period)
2025-10-01 12:22:08 -05:00
{
2026-02-14 17:00:45 -05:00
//---
2025-10-01 12:22:08 -05:00
bool custom = false;
if(SymbolExist(symbol, custom) == false)
{
LogFatalError(StringFormat("El simbolo %s, es invalido", symbol), FUNCION_ACTUAL);
Remover();
return;
}
if(period <= 0)
{
LogFatalError(StringFormat("El periodo del atr %d, es invalido", period), FUNCION_ACTUAL);
Remover();
return;
}
//---
m_timeframe = tf;
m_symbol = symbol;
m_index = index;
m_period = period;
m_atr_value = 0.0;
controler_curr = new CBarControler(tf);
wilder_factor = (double)(m_period - 1) / m_period; // 13/14 para per<EFBFBD>odo 14
inv_period = 1.0 / m_period; // 1/14 para per<EFBFBD>odo 14
//---
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArrayResize(high, 0);
ArrayResize(low, 0);
ArrayResize(close, 0);
ArrayResize(atr, m_period + 2);
}
//+------------------------------------------------------------------+
CAtrOptimized::~CAtrOptimized(void)
{
//ArrayFree(high);
//ArrayFree(low);
//ArrayFree(close);
//ArrayFree(atr);
if(CheckPointer(controler_curr) == POINTER_DYNAMIC && controler_curr != NULL)
delete controler_curr;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#define CopyAtrExtraValue 3
#define CopyAtr(p) p*2+CopyAtrExtraValue
//---
bool CAtrOptimized::CopyData()
{
int to_copy = CopyAtr(m_period);
if(CopyHigh(this.m_symbol, this.m_timeframe, m_index, to_copy, high) < to_copy)
{
LogError(StringFormat("Al copiar data de los highs, start = %d - count = %d", m_index, to_copy), FUNCION_ACTUAL);
return false;
}
if(CopyClose(this.m_symbol, this.m_timeframe, m_index, to_copy, close) < to_copy)
{
2026-01-06 13:03:52 -05:00
LogError(StringFormat("Al copiar data de los closes start = %d - count = %d", m_index, to_copy), FUNCION_ACTUAL);
return false;