2026-09-12 19:41:52 -05:00
//+------------------------------------------------------------------+
//| Atr.mqh |
//| Copyright 2026, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372/news |
//+------------------------------------------------------------------+
# property copyright " Copyright 202, Niquel Mendoza. "
# 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 |
//+------------------------------------------------------------------+
# include "SimpleLogger.mqh"
# include "BarControler.mqh"
//+------------------------------------------------------------------+
//| Resources |
//+------------------------------------------------------------------+
# resource "AtrCts.ex5"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| Class to handle the atr |
//+------------------------------------------------------------------+
class CAtr : public CLoggerBase
{
private :
double arr [ ] ;
ENUM_TIMEFRAMES timeframe ;
int handle ;
public :
~ CAtr ( ) ;
CAtr ( ) ;
//---
inline bool IsIdxValid ( const int idx , const string & function_name ) const ;
//---
void SetAsSeries ( bool flag ) ;
bool CopyData ( int start , int count ) ;
bool CopyData ( int count ) ;
//---
bool Create ( ENUM_TIMEFRAMES tf , const string & symb , int period , bool execute_on_bar , bool hide_indicator = true ) ;
bool Create ( const int handle_ ) ;
bool Sincronize ( const int min_bars_calc , const int ms_sleep , int attemps = 100 ) ;
//---
inline ENUM_TIMEFRAMES Timeframe ( ) const { return timeframe ; }
inline int Handle ( ) const { return handle ; }
void Free ( ) { ArrayFree ( arr ) ; }
//---
// Para evitar erroers use el check..
double operator [ ] ( int _index ) const { return arr [ _index ] ; }
} ;
//+------------------------------------------------------------------+
//| Contructor and Destructor |
//+------------------------------------------------------------------+
CAtr : : CAtr ( void )
: handle ( INVALID_HANDLE ) , timeframe ( WRONG_VALUE )
{
ArrayResize ( arr , 0 ) ;
}
//+------------------------------------------------------------------+
CAtr : : ~ CAtr ( )
{
if ( handle ! = INVALID_HANDLE )
IndicatorRelease ( handle ) ;
//Free();
}
//+------------------------------------------------------------------+
//| 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ño del array = %u " , idx , arr .Size ( ) ) , function_name ) ;
return false ;
}
}
//+------------------------------------------------------------------+
bool 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 ) ;
return false ;
}
// FastLog(FUNCION_ACTUAL, INFO_TEXT, StringFormat("El handle del indicador es %s", (handle == INVALID_HANDLE ? "invalido" : "valido")));
return true ;
}
//+------------------------------------------------------------------+
bool CAtr : : CopyData ( int count )
{
ResetLastError ( ) ;
if ( CopyBuffer ( handle , 0 , 0 , count , arr ) ! = count )
{
LogError ( StringFormat ( " No se pudo copiar data del indicador de atr [0 -> count: %d], ultimo error = %d " , count , GetLastError ( ) ) , FUNCION_ACTUAL ) ;
return false ;
//FastLog(FUNCION_ACTUAL, INFO_TEXT, StringFormat("El handle del indicador es %s", (handle == INVALID_HANDLE ? "invalido" : "valido")));
}
return true ;
}
//+------------------------------------------------------------------+
bool CAtr : : Create ( ENUM_TIMEFRAMES tf , const string & symb , int period , bool execute_on_bar , bool hide_indicator = true )
{
ResetLastError ( ) ;
//---
if ( hide_indicator )
TesterHideIndicators ( true ) ;
//---
const int handle_ = iCustom ( symb , ( timeframe = tf ) , " ::AtrCts.ex5 " , period , execute_on_bar ) ;
//---
if ( hide_indicator )
TesterHideIndicators ( false ) ;
//---
if ( handle_ = = INVALID_HANDLE )
return false ;
//---
this . handle = handle_ ;
return true ;
}
//+------------------------------------------------------------------+
bool CAtr : : Create ( const int handle_ )
{
if ( handle_ = = INVALID_HANDLE )
return false ;
//---
this . handle = handle_ ;
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAtr : : Sincronize ( const int min_bars_calc , const int ms_sleep , int attemps = 100 )
{
//---
while ( attemps - - > 0 )
{
if ( BarsCalculated ( this . handle ) > = min_bars_calc )
{
return true ;
}
//---
Sleep ( ms_sleep ) ;
}
//---
LogError ( StringFormat ( " Fallo al obtener data del indicador Atr | # Intenos = %d | Min Bars = %d | SleepMs = %d " , attemps , min_bars_calc , ms_sleep ) , FUNCION_ACTUAL ) ;
//---
return false ;
}
//+------------------------------------------------------------------+
void CAtr : : SetAsSeries ( bool flag )
{
ArraySetAsSeries ( this . arr , flag ) ;
}
//+------------------------------------------------------------------+
bool DataIsValid ( const double & arr [ ] )
{
for ( int i = 0 ; i < ( int ) arr .Size ( ) ; i + + )
{
if ( arr [ i ] = = 0.00 | | arr [ i ] = = EMPTY_VALUE )
return false ;
}
return true ;
}
//+------------------------------------------------------------------+
//| 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í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 ;
//---
template < typename T >
static __forceinline T MinValue ( const T val , const T val2 ) { return val > val2 ? val2 : val ; }
template < typename T >
static __forceinline T MaxValue ( const T val , const T val2 ) { return val < val2 ? val2 : val ; }
} ;
//+------------------------------------------------------------------+
//| Constructor and destructor |
//+------------------------------------------------------------------+
CAtrOptimized : : CAtrOptimized ( ENUM_TIMEFRAMES tf , const string & symbol , int index , int period )
: controler_curr ( tf )
{
//---
m_timeframe = tf ;
m_symbol = symbol ;
m_index = index ;
m_period = period ;
m_atr_value = 0.0 ;
wilder_factor = ( double ) ( m_period - 1 ) / m_period ; // 13/14 para período 14
inv_period = 1.0 / m_period ; // 1/14 para perí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 )
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
# 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 )
{
LogError ( StringFormat ( " Al copiar data de los closes start = %d - count = %d " , m_index , to_copy ) , FUNCION_ACTUAL ) ;
return false ;
}
if ( CopyLow ( this . m_symbol , this . m_timeframe , m_index , to_copy , low ) < to_copy )
{
LogError ( StringFormat ( " Al copiar data de los lows, start = %d - count = %d " , m_index , to_copy ) , FUNCION_ACTUAL ) ;
return false ;
}
return true ;
}
//+------------------------------------------------------------------+
inline double CAtrOptimized : : CalculeTrueRange ( int idx )
{
return MaxValue ( high [ idx ] , close [ idx + 1 ] ) - MinValue ( low [ idx ] , close [ idx + 1 ] ) ;
}
//+------------------------------------------------------------------+
inline double CAtrOptimized : : CalculeTrueRangeForIndexCts ( int index )
{
const double prev_close = iClose ( m_symbol , m_timeframe , index + 1 ) ;
return MaxValue ( iHigh ( m_symbol , m_timeframe , index ) , prev_close ) - MinValue ( iLow ( m_symbol , m_timeframe , index ) , prev_close ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CAtrOptimizedZero : public CAtrOptimized
{
private :
double CalculateAtrForIndexComplete ( ) ;
double CalculateAtrForIndexFast ( ) ;
//---
double cached_prev_atr ;
double cached_tr_period ;
public :
CAtrOptimizedZero ( ENUM_TIMEFRAMES tf , const string & symbol , int period ) ;
inline double GetAtrValue ( const datetime curr_time ) override ;
} ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CAtrOptimizedZero : : CAtrOptimizedZero ( ENUM_TIMEFRAMES tf , const string & symbol , int period )
: CAtrOptimized ( tf , symbol , 0 , period )
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
inline double CAtrOptimizedZero : : GetAtrValue ( const datetime curr_time )
{
if ( controler_curr . IsNewBar ( curr_time ) )
{
if ( controler_curr . GetNextPrevBarTime ( ) + controler_curr . PeriodsInSeconds ( ) < curr_time ) //hubo suspension
return CalculateAtrForIndexComplete ( ) ;
else
return CalculateAtrForIndexFast ( ) ;
}
m_atr_value = cached_prev_atr + ( CalculeTrueRangeForIndexCts ( 0 ) - cached_tr_period ) * inv_period ;
return m_atr_value ;
}
//+------------------------------------------------------------------+
double CAtrOptimizedZero : : CalculateAtrForIndexComplete ( void )
{
if ( ! CopyData ( ) )
return 0.00 ;
double sum = 0 ;
for ( int i = 1 ; i < = m_period ; i + + ) // Empezar desde 1, evitar la barra actual
sum + = CalculeTrueRange ( i ) ;
sum * = inv_period ;
double current_atr = sum ;
for ( int i = m_period - 1 ; i > = 1 ; i - - ) // Desde m_period-1 hacia 1
{
double tr = CalculeTrueRange ( i ) ;
current_atr = current_atr * wilder_factor + tr * inv_period ;
}
cached_prev_atr = current_atr ;
cached_tr_period = CalculeTrueRange ( m_period ) ; // TR que se usará en fast
double tr_current = CalculeTrueRange ( 0 ) ;
m_atr_value = current_atr + ( tr_current - cached_tr_period ) * inv_period ;
return m_atr_value ;
}
//+------------------------------------------------------------------+
double CAtrOptimizedZero : : CalculateAtrForIndexFast ( void )
{
this . cached_prev_atr = this . m_atr_value ;
this . cached_tr_period = CalculeTrueRangeForIndexCts ( m_period ) ; // no sumamos m_index por que eso zero
m_atr_value = cached_prev_atr + ( CalculeTrueRangeForIndexCts ( 0 ) - cached_tr_period ) * inv_period ;
return m_atr_value ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CAtrOptimizedNonZero : public CAtrOptimized
{
double CalculateAtrForIndexComplete ( ) ; // Calcular solo para el índice específico
double CalculateAtrForIndexFast ( ) ;
double cached_prev_atr ;
public :
CAtrOptimizedNonZero ( ENUM_TIMEFRAMES tf , const string & symbol , int index , int period ) ;
inline double GetAtrValue ( const datetime curr_time ) override ;
} ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CAtrOptimizedNonZero : : CAtrOptimizedNonZero ( ENUM_TIMEFRAMES tf , const string & symbol , int index , int period )
: CAtrOptimized ( tf , symbol , index , period )
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
inline double CAtrOptimizedNonZero : : GetAtrValue ( const datetime curr_time )
{
if ( controler_curr . IsNewBar ( curr_time ) )
{
if ( controler_curr . GetNextPrevBarTime ( ) + controler_curr . PeriodsInSeconds ( ) < curr_time ) //hubo suspension
return CalculateAtrForIndexComplete ( ) ;
else
return CalculateAtrForIndexFast ( ) ;
}
return this . m_atr_value ;
}
//+------------------------------------------------------------------+
double CAtrOptimizedNonZero : : CalculateAtrForIndexFast ( void )
{
this . cached_prev_atr = m_atr_value ;
double tr_current = CalculeTrueRangeForIndexCts ( m_index ) ;
double cached_prev_tr_period = CalculeTrueRangeForIndexCts ( m_index + m_period ) ;
m_atr_value = cached_prev_atr + ( tr_current - cached_prev_tr_period ) * inv_period ;
return m_atr_value ;
}
//+------------------------------------------------------------------+
double CAtrOptimizedNonZero : : CalculateAtrForIndexComplete ( void )
{
if ( ! CopyData ( ) )
return 0.00 ;
double sum = 0 ;
for ( int i = 0 ; i < = m_period ; i + + )
sum + = CalculeTrueRange ( i ) ;
double initial_atr = sum * inv_period ;
double current_atr = initial_atr ;
for ( int i = m_period - 1 ; i > = 0 ; i - - )
{
double tr = CalculeTrueRange ( i ) ;
current_atr = current_atr * wilder_factor + tr * inv_period ;
if ( i = = 1 ) // Guardar ATR[1] para el cache
cached_prev_atr = current_atr ;
}
m_atr_value = current_atr ; // current_atr ahora es ATR[0]
return m_atr_value ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CAtrUltraOptimized
{
private :
ENUM_TIMEFRAMES m_timeframe ;
string m_symbol ;
int m_index ;
int m_period ;
public :
CAtrUltraOptimized ( ) ;
~ CAtrUltraOptimized ( ) ;
//---
CAtrOptimized * base ;
//---
void SetVariables ( ENUM_TIMEFRAMES tf , string symbol_ , int index_ , int period_ ) ;
//---
void Period ( int new_value ) { this . m_period = new_value ; }
void Symbol ( string new_value ) { this . m_symbol = new_value ; }
void Index ( int new_value ) { this . m_index = new_value ; }
void Timeframe ( ENUM_TIMEFRAMES new_value ) { this . m_timeframe = new_value ; }
//---
inline int Period ( ) const { return m_period ; }
inline string Symbol ( ) const { return m_symbol ; }
inline int Index ( ) const { return m_index ; }
inline ENUM_TIMEFRAMES Timeframe ( ) const { return m_timeframe ; }
//---
bool SetInternalPointer ( ) ;
} ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CAtrUltraOptimized : : CAtrUltraOptimized ( void )
: base ( NULL ) , m_timeframe ( : : Period ( ) ) , m_symbol ( : : Symbol ( ) ) , m_index ( 0 ) , m_period ( 14 )
{
}
//+------------------------------------------------------------------+
CAtrUltraOptimized : : ~ CAtrUltraOptimized ( )
{
if ( : : CheckPointer ( base ) = = POINTER_DYNAMIC )
delete base ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CAtrUltraOptimized : : SetInternalPointer ( void )
{
if ( : : CheckPointer ( base ) = = POINTER_DYNAMIC )
delete base ;
if ( this . m_index = = 0 )
base = new CAtrOptimizedZero ( this . m_timeframe , this . m_symbol , this . m_period ) ;
else
base = new CAtrOptimizedNonZero ( this . m_timeframe , this . m_symbol , this . m_index , this . m_period ) ;
return ( : : CheckPointer ( base ) = = POINTER_DYNAMIC ) ;
}
//+------------------------------------------------------------------+
void CAtrUltraOptimized : : SetVariables ( ENUM_TIMEFRAMES tf , string symbol_ , int index_ , int period_ )
{
this . m_timeframe = tf ;
this . m_symbol = symbol_ ;
this . m_index = index_ ;
this . m_period = period_ ;
}
}
# endif // MQLARTICLES_UTILS_FA_ATR_MQH
//+------------------------------------------------------------------+