2026-09-13 08:47:52 -05:00
//+------------------------------------------------------------------+
//| StrategyBase.mqh |
//| Copyright 2025, Leo. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
# property copyright " Copyright 2025, Leo. "
# property link " https://www.mql5.com "
# property strict
# ifndef MQLARTICLES_STRATEGY_CORE_BASE_MQH
# define MQLARTICLES_STRATEGY_CORE_BASE_MQH
/ / + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
//| Include |
//+------------------------------------------------------------------+
# include "Defines.mqh"
# include "..\\Utils\\YearFilter.mqh"
# include "..\\Utils\\DailyFilter.mqh"
# include "..\\..\\Utils\\FA\\DiffCalc.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| Clase base para las estrategias de trading |
//+------------------------------------------------------------------+
// TPadre = [Cualquier clase de eventos CAllEventsBasic, CAccountGestor, etc]
template < typename TPadre >
class CStrategyBaseTemplate : public TPadre
{
protected :
//--- Variables
// Generales
const ENUM_TIMEFRAMES m_timeframe ; //Timeframe de la estrategia
const string m_symbol ;
const int m_subwindow ;
const long m_chart_id ;
const int m_period_in_seconds ;
const string m_strategy_name ;
string m_obj_code ;
bool m_enable_strategy ; // Habilitar la logica de la estrategia (como un boton de off on para ejecutar la estrategia)
int8_t m_new_bar_idx ; // Indice para consultar nueva barra (otros TFs - CNewBarManager)
// Parametros generales
bool m_is_enable_buy ;
bool m_is_enable_sell ;
const ulong m_max_deviation ;
const ulong m_magic_number ;
// Info del simbolo
MqlTick m_tick ;
double m_point_value ;
int8_t m_digits ;
double m_vol_min ;
double m_vol_max ;
double m_vol_step ;
double m_stops_leevel ;
// Apertura de operaciones
double m_TP_POINTS ;
double m_SL_POINTS ;
double m_LOT_SIZE ;
CTrade m_trade ;
ENUM_TYPE_TP_SL_FIXED m_tp_sl_mode ;
// Atr optimizado para el calculo del tp, sl e uso interno
CAtrUltraOptimized * m_atr_pointer ;
double m_atr_multiplier_tp ;
double m_atr_multiplier_sl ;
//--- Funciones
// TP\SL basico para posiciones
inline double GetSL ( const double entry_price , const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const ;
inline double GetTP ( const double entry_price , const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const ;
__forceinline double GetSLDistance ( const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const ;
__forceinline double GetTPDistance ( const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const ;
// Utilidades extra
inline int DistanceToPoints ( double dist ) { return ( m_point_value = = 0.00 ) ? 0 : ( int ) : : MathRound ( dist / m_point_value ) ; }
inline double GetDiff ( ENUM_MODE_DIFF mode , double val , datetime curr_time ) const { return mode = = MODE_DIFF_BY_ATR ? ( m_atr_pointer . base . GetAtrValue ( curr_time ) * val ) : ( val * m_point_value ) ; }
public :
CStrategyBaseTemplate ( const ulong magic_number_ , const string & symbol_ , const ENUM_TIMEFRAMES timeframe_ , const long chart_id_ ,
const int subwindow_ , const ulong max_deviation_ , const string & name ) ;
~ CStrategyBaseTemplate ( ) ;
//--- Funciones para establecer valores de la clase
void SetTP_SL ( long new_sl_value , long new_tp_value ) ;
void SetAtrTP_SL ( CAtrUltraOptimized * atr_ptr , double atr_mult_tp_ , double atr_mult_sl_ ) ;
void SetOperateMode ( ENUM_TYPE_TRADE trade_type , ENUM_TYPE_TP_SL_FIXED tp_sl_mode_ ) ;
//--- Funciones getter y setter
// General getters
inline ENUM_TIMEFRAMES Timeframe ( ) const { return m_timeframe ; }
inline long ChartId ( ) const { return m_chart_id ; }
inline int Subwin ( ) const { return m_subwindow ; }
inline string Symbol ( ) const { return m_symbol ; }
inline int TimeframeInSeconds ( ) const { return m_period_in_seconds ; }
inline ulong MagicNumber ( ) const { return m_magic_number ; }
inline string Name ( ) const { return m_strategy_name ; }
// Codigo de objeto
inline string ObjCode ( ) const { return m_obj_code ; }
void ObjCode ( const string & new_value ) { m_obj_code = new_value ; }
__forceinline string ObjCodeConc ( string str ) const { return ( m_obj_code + str ) ; }
// Puntero de CTrade utilizado
// Evitamos la modificacion de dirreicon y del obejto y de las variabes miembro de la clase
const CTrade * const TradePointer ( ) const { return & m_trade ; }
// Tamaño de lote
__forceinline double FixedLotSize ( ) const { return m_LOT_SIZE ; }
void FixedLotSize ( double new_lot ) ;
// Ventas y commpras habilitadas
__forceinline bool EnableBuyTrades ( ) const { return m_is_enable_buy ; }
__forceinline bool EnableSellTrades ( ) const { return m_is_enable_sell ; }
//
__forceinline bool EnableStrategy ( ) const { return m_enable_strategy ; }
void EnableStrategy ( const bool enable ) { m_enable_strategy = enable ; }
//--- Funciones de ejecucion
virtual void OnNewBar ( const datetime curr_time ) = 0 ; // Funcion que se ejecutara cada nueva vela
virtual void OnTick ( const datetime curr_time ) = 0 ; // Funcion que se ejecutara cada nuevo tick
// Funcion que se llama anted de detener el llamado a OnTick y OnNewBar
// La estrategia tomara sus acciones como que en la siguiente llamada a OnNewBar o OnTick hacer un recalculo completo
// Esto depende de la estrategia habra unas que no lo requieren otras que si etc
virtual void OnInterupcion ( ) { }
} ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template < typename TPadre > CStrategyBaseTemplate : : CStrategyBaseTemplate ( const ulong magic_number_ , const string & symbol_ , const ENUM_TIMEFRAMES timeframe_ , const long chart_id_ ,
const int subwindow_ , const ulong max_deviation_ , const string & name )
:
//---
m_TP_POINTS ( 0 ) , m_SL_POINTS ( 0 ) , m_LOT_SIZE ( 0.00 ) , m_atr_multiplier_sl ( 2.0 ) , m_atr_multiplier_tp ( 4.0 ) , m_is_enable_buy ( true ) ,
m_is_enable_sell ( true ) , m_atr_pointer ( NULL ) , m_enable_strategy ( true ) ,
//---
m_symbol ( symbol_ ) , m_magic_number ( magic_number_ ) , m_chart_id ( chart_id_ ) , m_subwindow ( subwindow_ ) , m_timeframe ( ( timeframe_ = = PERIOD_CURRENT ? _Period : timeframe_ ) ) ,
m_period_in_seconds ( CTimeframe : : PeriodSecondsFast ( timeframe_ ) ) , m_max_deviation ( max_deviation_ ) , m_strategy_name ( name )
{
//---
//AddLogFlags(LOG_LEVEL_WARNING);
//---
m_trade . LogLevel ( LOG_LEVEL_NO ) ;
m_trade . SetExpertMagicNumber ( m_magic_number ) ;
//---
m_digits = ( int8_t ) : : SymbolInfoInteger ( symbol_ , SYMBOL_DIGITS ) ;
m_vol_max = : : SymbolInfoDouble ( symbol_ , SYMBOL_VOLUME_MAX ) ;
m_vol_step = : : SymbolInfoDouble ( symbol_ , SYMBOL_VOLUME_STEP ) ;
m_vol_min = : : SymbolInfoDouble ( symbol_ , SYMBOL_VOLUME_MIN ) ;
m_point_value = : : SymbolInfoDouble ( m_symbol , SYMBOL_POINT ) ;
m_stops_leevel = ( : : SymbolInfoInteger ( symbol_ , SYMBOL_TRADE_STOPS_LEVEL ) * m_point_value ) + ( m_point_value * 10 ) ;
//---
if ( max_deviation_ > NO_MAX_DEVIATION_DEFINED )
m_trade . SetDeviationInPoints ( max_deviation_ ) ;
//---
: : MathSrand ( : : GetTickCount ( ) ) ;
//---
m_obj_code = : : StringFormat ( " %s_%s_%d_ " , name , CTimeframe : : ToStrUpper ( m_timeframe ) , : : rand ( ) ) ;
}
//+------------------------------------------------------------------+
template < typename TPadre > CStrategyBaseTemplate : : ~ CStrategyBaseTemplate ( ) /* ADVERTENCIA SI SE AÑADEN PUNTEROS EN ITEMS ENTONCES ESTOS SE LIMPIARAN NO HACE FALTA HACERLO EN EL DESTRUCTOE DEL HIJO*/
{
// Para que no se elimina y copratri recomeindion instancia global
//Se Elimina el atr ultra optimizado
CleanItems ( " StrategyBase " ) ; //Limpiamos todos los punteros de CLogger, en este caso solo se limpiaria el "base", el atr_pointer lo hacemos manual:
if ( : : CheckPointer ( m_atr_pointer ) = = POINTER_DYNAMIC )
delete m_atr_pointer ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// Notas:
// - Tick debe de ser obtenido antes
// - Esta funcion solo debe invocarse para posiciones, mejor para ordenes a mercado
// - Esta funcion solo es compatible con el tipo de tp y sl Atr, Points, si tiene otro modo redefina la funcion.. dado que m_tp_sl_mdode para un valor (0) llamara a atr
// de lo contrario para cualquier valor a puntos... asi que ya esta avisado.
//+------------------------------------------------------------------+
template < typename TPadre >
inline double CStrategyBaseTemplate : : GetTP ( const double entry_price , const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const
{
const double distance = ( m_tp_sl_mode ) ? ( m_point_value * m_TP_POINTS ) : ( m_atr_multiplier_tp * m_atr_pointer . base . GetAtrValue ( curr_time ) ) ;
if ( distance < DBL_EPSILON )
return 0.00 ;
const double to_sum = : : fmax ( ( m_stops_leevel + ( m_tick . ask - m_tick . bid ) ) , distance ) ;
return position_type = = POSITION_TYPE_BUY ? entry_price + to_sum : entry_price - to_sum ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
inline double CStrategyBaseTemplate : : GetSL ( const double entry_price , const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const
{
const double distance = ( m_tp_sl_mode ) ? ( m_point_value * m_SL_POINTS ) : ( m_atr_multiplier_sl * m_atr_pointer . base . GetAtrValue ( curr_time ) ) ;
if ( distance < DBL_EPSILON )
return 0.00 ;
const double to_sum = : : fmax ( ( m_stops_leevel + ( m_tick . ask - m_tick . bid ) ) , distance ) ;
return position_type = = POSITION_TYPE_BUY ? entry_price - to_sum : entry_price + to_sum ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
__forceinline double CStrategyBaseTemplate : : GetTPDistance ( const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const
{
return ( m_tp_sl_mode ) ? ( m_point_value * m_TP_POINTS ) : ( m_atr_multiplier_tp * m_atr_pointer . base . GetAtrValue ( curr_time ) ) ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
__forceinline double CStrategyBaseTemplate : : GetSLDistance ( const ENUM_POSITION_TYPE position_type , const datetime curr_time ) const
{
return ( m_tp_sl_mode ) ? ( m_point_value * m_SL_POINTS ) : ( m_atr_multiplier_sl * m_atr_pointer . base . GetAtrValue ( curr_time ) ) ;
}
//+------------------------------------------------------------------+
//| Setters |
//+------------------------------------------------------------------+
template < typename TPadre >
void CStrategyBaseTemplate : : FixedLotSize ( double new_lot )
{
if ( new_lot < = STRATEGY_BASE_EMPTY_VALUE )
return ;
if ( new_lot < m_vol_min )
{
LogWarning ( : : StringFormat ( " El nuevo lote %f es menor al minimo volumen permitido, se ajustara al valor permitido mas cercano " , new_lot ) , FUNCION_ACTUAL ) ;
new_lot = m_vol_min ;
}
if ( new_lot > m_vol_max )
{
LogWarning ( : : StringFormat ( " El nuevo lote %f es mayor al maximo volumen permitido, se ajustara al valor permitido mas cercano " , new_lot ) , FUNCION_ACTUAL ) ;
new_lot = m_vol_max ;
}
m_LOT_SIZE = new_lot ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
void CStrategyBaseTemplate : : SetAtrTP_SL ( CAtrUltraOptimized * atr_ptr , double atr_mult_tp_ , double atr_mult_sl_ )
{
if ( atr_ptr ! = NULL )
{
if ( m_atr_pointer ! = NULL ) //Si no es invalido eliminamos el anteior solo si es dinamico
{
RemoveLogger ( m_atr_pointer . base ) ;
if ( : : CheckPointer ( m_atr_pointer ) = = POINTER_DYNAMIC )
{
delete m_atr_pointer ;
m_atr_pointer = NULL ;
LogWarning ( " Se ha eliminado el puntero anteior a CAtrUltraOptimized* " , FUNCION_ACTUAL ) ;
}
}
m_atr_pointer = atr_ptr ;
AddLogger ( m_atr_pointer . base ) ;
}
else
{
if ( : : CheckPointer ( m_atr_pointer ) = = POINTER_INVALID | | : : CheckPointer ( m_atr_pointer . base ) = = POINTER_INVALID )
{
LogError ( " El puntero a CAtrUltraOptimized es invalido, corregir ahora " , FUNCION_ACTUAL ) ;
Remover ( ) ;
}
}
if ( atr_mult_sl_ > STRATEGY_BASE_EMPTY_VALUE )
m_atr_multiplier_sl = atr_mult_sl_ ;
if ( atr_mult_tp_ > STRATEGY_BASE_EMPTY_VALUE )
m_atr_multiplier_tp = atr_mult_tp_ ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
void CStrategyBaseTemplate : : SetTP_SL ( long new_sl_value , long new_tp_value )
{
if ( new_sl_value > STRATEGY_BASE_EMPTY_VALUE )
{
if ( new_sl_value < 1 )
{
LogWarning ( : : StringFormat ( " Los puntos del stoploss %d son menores a 1 los proximos trades no tendran stoploss " , new_sl_value ) , FUNCION_ACTUAL ) ;
new_sl_value = 0 ;
}
m_SL_POINTS = ( double ) new_sl_value ;
}
if ( new_tp_value > STRATEGY_BASE_EMPTY_VALUE )
{
if ( new_tp_value < 1 )
{
LogWarning ( : : StringFormat ( " Los puntos del takeprofit %d son menores a 1, los proximos trades no tendran takeprofit " , new_tp_value ) , FUNCION_ACTUAL ) ;
new_tp_value = 0 ;
}
m_TP_POINTS = ( double ) new_tp_value ;
}
}
//+------------------------------------------------------------------+
template < typename TPadre >
void CStrategyBaseTemplate : : SetOperateMode ( ENUM_TYPE_TRADE trade_type , ENUM_TYPE_TP_SL_FIXED tp_sl_mode_ )
{
if ( trade_type ! = WRONG_VALUE )
{
if ( trade_type = = TR_BUY_SELL )
{
m_is_enable_sell = true ;
m_is_enable_buy = true ;
}
else
if ( trade_type = = TR_BUY )
{
m_is_enable_sell = false ;
m_is_enable_buy = true ;
}
else
{
m_is_enable_sell = true ;
m_is_enable_buy = false ;
}
}
if ( tp_sl_mode_ ! = WRONG_VALUE )
m_tp_sl_mode = tp_sl_mode_ ;
}
//+------------------------------------------------------------------+
//| Clase para compatibilidad |
//+------------------------------------------------------------------+
class CStrategyBase : public CStrategyBaseTemplate < CAccountGestor >
{
public :
CStrategyBase ( const ulong magic_number_ , const string & symbol_ , const ENUM_TIMEFRAMES timeframe_ , const long chart_id_ ,
const int subwindow_ , const ulong max_deviation_ , const string & name )
: CStrategyBaseTemplate < CAccountGestor > ( magic_number_ , symbol_ , timeframe_ , chart_id_ , subwindow_ , max_deviation_ , name ) { }
~ CStrategyBase ( void ) { }
} ;
}
# endif // MQLARTICLES_STRATEGY_CORE_BASE_MQH
//+------------------------------------------------------------------+`
/*
//+------------------------------------------------------------------+
//| Open Order Default |
//+------------------------------------------------------------------+
void CEstrategia::OpenOrder(ENUM_POSITION_TYPE type)
{
::SymbolInfoTick(m_symbol, m_tick);
if(type == POSITION_TYPE_BUY)
{
double entry = m_tick.ask;
double sl = GetSL(entry, type, m_tick.time);
double tp = GetTP(entry, type, m_tick.time);
risk.SetStopLoss(entry - sl);
double l = m_LOT_SIZE > 0.00 ? m_LOT_SIZE : risk.GetLote(ORDER_TYPE_BUY, entry, m_max_deviation, 0);
m_trade.Buy(l, m_symbol, entry, sl, tp, "Ea buy");
}
else
if(type == POSITION_TYPE_SELL)
{
double entry = m_tick.bid;
double sl = GetSL(entry, type, m_tick.time);
double tp = GetTP(entry, type, m_tick.time);
risk.SetStopLoss(sl - entry);
double l = m_LOT_SIZE > 0.00 ? m_LOT_SIZE : risk.GetLote(ORDER_TYPE_SELL, entry, m_max_deviation, 0);
m_trade.Sell(l, m_symbol, entry, sl, tp, "Ea sell");
}
Clean();
}
*/
//+------------------------------------------------------------------+