2026-02-19 11:31:44 -05:00
//+------------------------------------------------------------------+
//| Base.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372 |
//+------------------------------------------------------------------+
# property copyright " Copyright 2025, Niquel Mendoza. "
# property link " https://www.mql5.com/es/users/nique_372 "
# property strict
# ifndef MQLARTICLES_RM_LOSSPROFIT_BASE_MQH
# define MQLARTICLES_RM_LOSSPROFIT_BASE_MQH
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
# include "..\\RiskManagementBases.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CLossProfit ; // Advance declaration for the typedef
//+------------------------------------------------------------------+
//| Defines |
//+------------------------------------------------------------------+
typedef bool ( * FuncionLossProfitSuperate ) ( const double & value , const double & saved_value , void * ptr ) ;
typedef void ( * FLossPoriftDynamic ) ( CLossProfit & , Dynamic_LossProfit & , Loss_Profit & , bool & , bool & , const int , int & , int & , const int , double & ) ;
# define MAX_VAL_DEFINES_CLOSS_PROFIT ( DBL_MAX )
# define MIN_VAL_DEFINES_CLOSE_PROFIT ( - DBL_MAX )
//---
__forceinline bool LossProfitEmptyFuncionSup ( const double & value , const double & saved_value , void * ptr ) { return false ; }
//--- Tipos basicos
# define LOSSPROFIT_TYPE_GMLPO 0 / / Tipo base % a arriesgar
//---
# define LOSSPROFIT_TYPE_MDL 1 / / Maxima perdida diaria
# define LOSSPROFIT_TYPE_MWL 2 / / Maxima perdida semanal
# define LOSSPROFIT_TYPE_MML 3 / / Maxima perdida mensual
# define LOSSPROFIT_TYPE_ML 4 / / Maxima perdida
# define LOSSPROFIT_TYPE_MDDPICO 5 / / Maxima perdida desde nuevo pico de la cuenta
//---
# define LOSSPROFIT_TYPE_MDP 6 / / Maxima ganancia diaria
# define LOSSPROFIT_TYPE_MWP 7 / / Maxima ganancia semanal
# define LOSSPROFIT_TYPE_MMP 8 / / Maxima ganancia mensual
# define LOSSPROFIT_TYPE_MP 9 / / Maxima ganancia
# define LOSSPROFIT_TYPE_MDDBAJO 10 / / Maxima ganancia desde el bajo de la cuenta
//--- Losses Profits
# define LOSS_PROFIT_COUNT 11
//+------------------------------------------------------------------+
//| CLossProfit Class |
//+------------------------------------------------------------------+
class CLossProfit : public CAccountGestor
{
protected :
//--- General
const bool m_active_hook_on_superated ;
const int m_type ; // Type of maximum loss or profit.
Loss_Profit m_lp ; // Structure that will store info of this maximum loss or profit.
FLossPoriftDynamic m_f_change_dynamic ; // Function for dynamic risk
double m_initial_calc_value ; // Initial percentage
bool m_empty_flag ; // Empty flag
double m_saved_value ; // Valor base
string m_name ; // Nombre
ENUM_LOSS_PROFIT m_type_loss_or_profit ; // Tipo
FuncionLossProfitSuperate m_funcion_check_sup ; // Funcion custom que chekea si se ha superado
const ulong m_magic_number ; // Numero magico para filtrar
//---
void * m_ptr_to_superate ; // Ptr al superar
//---
CRiskManagemetBase * m_risk ; // Risk management to which this class is subject
CHashMap < double , double > m_balance_risk_map ; // HashMap for dynamic risk (percentages to exceed and new risk percentage)
//--- Dynamic risk
Dynamic_LossProfit m_dynamic_lp ; // Structure containing the % to exceed and risks to apply
bool m_activate_dynamic_risk_per_operation ; // Flag indicating if dynamic risk will be applied to this "maximum loss or profit"
double m_chosen_balance ; // Chosen initial balance
int m_index_cambio ; // Change index between positives and negatives
int m_size_dynamic ; // Size of changes
bool m_min_val_is ; // Minimum value exceeded
bool m_max_val_is ; // Maximum value exceeded
int m_pos_derecha ; // Current position on right
int m_pos_izquierda ; // Current position on left
double m_new_balance_to_overcome ; // Next balance to overcome
// Cache for dynamic risk parameters
string m_cache_percentages_to_activate ;
string m_cache_risks_to_be_applied ;
//---
virtual void OnSuperated ( ) { }
public :
//--- Constructor
CLossProfit ( const int type , const bool im_empty , const bool act_hook , CRiskManagemetBase * _risk_pointer ) ;
~ CLossProfit ( ) { }
//--- Setters basicos
void SetDynamic ( string percentages_to_activate , string risks_to_be_applied , double _chosen_balance ) ;
void SetDynamic ( double _chosen_balance ) ;
void SetPtrSuperated ( void * ptr ) { m_ptr_to_superate = ptr ; }
//--- Dynamic risk
// Verifies and checks if the risk can be modified (only works in dynamic risk)
inline void CheckAndModifyThePercentage ( ) ;
// Returns true if the risk is dynamic
inline bool IsDynamicMode ( ) const { return m_activate_dynamic_risk_per_operation ; }
//--- General getters
// Returns true if the "maximum loss or profit" has been exceeded
bool IsSuperated ( ) const ;
__forceinline bool IsEmpty ( ) const { return m_empty_flag ; } // Esta vacio ?
inline string Name ( ) const { return m_name ; } // Nombre
inline ENUM_APPLIED_PERCENTAGES AppliedType ( ) const { return m_lp . percentage_applied_to ; } // Porcentage aplicado
inline int Type ( ) const { return m_type ; } // Tipo
inline ENUM_LOSS_PROFIT TypeLossProfit ( ) const { return m_type_loss_or_profit ; } // Tipo de loss profit
//--- Functions to work with the (Percentage | Value | Profit) of the "maximum loss or profit"
// Set value with calc value
virtual inline bool Set ( ) = 0 ;
virtual bool ForzeCalcValue ( ) const = 0 ;
// Initial calc value (percentage or money)
inline double GetInitialCalcValue ( ) const { return m_initial_calc_value ; } // Getter
inline double SetInitialCalcValue ( ) const { return ( ( ( CLossProfit * ) & this ) . m_lp . calculation_value = m_initial_calc_value ) ; } // Setter
// Current value
__forceinline double GetValue ( ) const { return m_lp . value ; } // Getter
bool SetValue ( double val ) ; // Setter
// Percentage (given that if the calculation mode is money, calculation_value has the money value, of course.
// But modifying "m_lp.calculation_value" has no effect.
inline double GetCalcValue ( ) const { return m_lp . calculation_value ; } // Getter
virtual bool SetCalcValue ( double val ) const = 0 ; // Setter
// Saved value
double SetSavedValue ( ) { return ( m_saved_value = m_lp . value ) ; }
inline double GetSavedValue ( ) const { return m_saved_value ; }
// Magic number
__forceinline ulong MagicNumber ( ) const { return m_magic_number ; }
//--- Static functions for risk modification (only used for dynamic risk)
static void CheckPositives ( CLossProfit & ptr , Dynamic_LossProfit & l_p , Loss_Profit & lossprofit , bool & min_val_is_sup , bool & empty_ , const int size_cambios , int & curr_pos , int & empty_i , const int empy_a ,
double & new_balance_to_superate_arriba ) ;
static void CheckNegatives ( CLossProfit & ptr , Dynamic_LossProfit & l_p , Loss_Profit & lossprofit , bool & min_val_is_sup , bool & empty_ , const int size_cambios , int & curr_pos , int & empty_i , const int empy_a ,
double & new_balance_to_superate_arriba ) ;
static void CheckNegativesAndPositives ( CLossProfit & ptr , Dynamic_LossProfit & l_p , Loss_Profit & lossprofit , bool & min_val_sup , bool & max_val_sup , const int size_cambios , int & curr_pos_izq ,
int & curr_pos_drc , const int index_change , double & new_balance_to_superate_arriba ) ;
} ;
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CLossProfit : : CLossProfit ( const int type , const bool im_empty , const bool act_hook , CRiskManagemetBase * _risk_pointer )
:
//--- Basico
m_empty_flag ( im_empty ) , m_type ( type ) , m_initial_calc_value ( 0.00 ) , m_saved_value ( 0.00 ) , m_ptr_to_superate ( NULL ) ,
//--- Hook
m_active_hook_on_superated ( act_hook ) ,
//--- Riesgo dinamico
m_min_val_is ( false ) , m_max_val_is ( false ) , m_pos_derecha ( 0 ) , m_pos_izquierda ( 0 ) , m_f_change_dynamic ( NULL ) ,
m_activate_dynamic_risk_per_operation ( false ) , m_index_cambio ( 0 ) , m_chosen_balance ( 0.00 ) ,
m_new_balance_to_overcome ( 0.00 ) , m_cache_percentages_to_activate ( NULL ) , m_cache_risks_to_be_applied ( NULL ) ,
2026-02-19 14:41:21 -05:00
m_funcion_check_sup ( NULL ) , m_magic_number ( im_empty ? NOT_MAGIC_NUMBER : _risk_pointer . MagicNumber ( ) )
2026-02-19 11:31:44 -05:00
{
//---
if ( m_empty_flag )
return ;
//---
this . m_risk = _risk_pointer ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLossProfit : : IsSuperated ( void ) const
{
if ( m_funcion_check_sup ( m_lp . value , m_saved_value , m_ptr_to_superate ) )
{
if ( m_active_hook_on_superated )
( ( CLossProfit * ) & this ) . OnSuperated ( ) ;
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| Establecer el valor |
//+------------------------------------------------------------------+
bool CLossProfit : : SetValue ( double val )
{
//---
if ( m_empty_flag )
{
# ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogWarning ( StringFormat ( " Trying to modify value in empty object '%s' " , m_name ) , FUNCION_ACTUAL ) ;
# endif
return false ;
}
//---
if ( val < = 0.0000001 )
{
LogError ( StringFormat ( " Invalid value %.2f for '%s': must be greater than 0.00 " , val , m_name ) , FUNCION_ACTUAL ) ;
return false ;
}
//---
# ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogInfo ( StringFormat ( " Risk value '%s' updated: %.2f " , m_name , val ) , FUNCION_ACTUAL ) ;
# endif
//---
m_lp . value = val ;
return true ;
}
//+------------------------------------------------------------------+
//| Establecer el riesgo dinamico |
//+------------------------------------------------------------------+
void CLossProfit : : SetDynamic ( double _chosen_balance )
{
if ( m_cache_percentages_to_activate = = NULL | | m_cache_risks_to_be_applied = = NULL )
{
LogError ( " Invalid strings, first call SetDynamic(string, string, double) " , FUNCION_ACTUAL ) ;
return ;
}
//---
SetDynamic ( m_cache_percentages_to_activate , m_cache_risks_to_be_applied , _chosen_balance ) ;
}
//+------------------------------------------------------------------+
void CLossProfit : : SetDynamic ( string percentages_to_activate , string risks_to_be_applied , double _chosen_balance )
{
//---
if ( m_empty_flag )
{
LogError ( " The risk is invalid " , FUNCION_ACTUAL ) ;
this . m_activate_dynamic_risk_per_operation = false ;
Remover ( ) ;
return ;
}
//---
StrTo : : CstArray ( this . m_dynamic_lp . balance_to_activate_the_risk , percentages_to_activate , ' , ' ) ;
StrTo : : CstArray ( this . m_dynamic_lp . risk_to_be_adjusted , risks_to_be_applied , ' , ' ) ;
//---
if ( this . m_dynamic_lp . risk_to_be_adjusted .Size ( ) < 1 | | this . m_dynamic_lp . balance_to_activate_the_risk .Size ( ) < 1 )
{
LogCriticalError ( " The size of the array is less than 1 " , FUNCION_ACTUAL ) ;
this . m_activate_dynamic_risk_per_operation = false ;
return ;
}
if ( this . m_dynamic_lp . balance_to_activate_the_risk .Size ( ) ! = this . m_dynamic_lp . risk_to_be_adjusted .Size ( ) )
{
LogCriticalError ( " The double arrays for the risk due to dynamic operation are not equal " , FUNCION_ACTUAL ) ;
this . m_activate_dynamic_risk_per_operation = false ;
return ;
}
//--- Cache values
m_cache_percentages_to_activate = percentages_to_activate ;
m_cache_risks_to_be_applied = risks_to_be_applied ;
//---
if ( IsInfoLogEnabled ( ) )
{
FastLog ( FUNCION_ACTUAL , INFO_TEXT , " Arrays before revision " ) ;
PrintArrayAsTable ( m_dynamic_lp . balance_to_activate_the_risk , " Negative percentages to modify the risk " , " balance " ) ;
PrintArrayAsTable ( m_dynamic_lp . risk_to_be_adjusted , " Risk to be adjusted " , " new risk " ) ;
}
//---
m_balance_risk_map . Clear ( ) ;
int indexes_to_remove [ ] ;
this . m_chosen_balance = _chosen_balance ;
//---
for ( int i = 0 ; i < ArraySize ( m_dynamic_lp . balance_to_activate_the_risk ) ; i + + )
{
if ( m_dynamic_lp . balance_to_activate_the_risk [ i ] = = 0 )
{
LogWarning ( " The percentage value that will be exceeded to modify the risk is 0 or less than this (it will not be taken into account) " , FUNCION_ACTUAL ) ;
AddArrayNoVerification ( indexes_to_remove , i , 0 ) ;
continue ;
}
if ( m_balance_risk_map . ContainsKey ( m_dynamic_lp . balance_to_activate_the_risk [ i ] ) = = false )
m_balance_risk_map . Add ( m_dynamic_lp . balance_to_activate_the_risk [ i ] , m_dynamic_lp . risk_to_be_adjusted [ i ] ) ;
else
AddArrayNoVerification ( indexes_to_remove , i , 0 ) ;
}
//---
RemoveMultipleIndexes ( m_dynamic_lp . balance_to_activate_the_risk , indexes_to_remove , 0 ) ;
ArraySort ( m_dynamic_lp . balance_to_activate_the_risk ) ;
ArrayResize ( m_dynamic_lp . risk_to_be_adjusted , ArraySize ( m_dynamic_lp . balance_to_activate_the_risk ) ) ;
//---
this . m_size_dynamic = ArraySize ( m_dynamic_lp . balance_to_activate_the_risk ) ;
//---
const bool hay_positivos = HayPositivosArray ( m_dynamic_lp . balance_to_activate_the_risk ) ;
const bool hay_negativos = HayNegativosArray ( m_dynamic_lp . balance_to_activate_the_risk ) ;
bool c = false ;
//---
for ( int i = 0 ; i < this . m_size_dynamic ; i + + )
{
double value ;
m_balance_risk_map . TryGetValue ( this . m_dynamic_lp . balance_to_activate_the_risk [ i ] , value ) ;
m_dynamic_lp . risk_to_be_adjusted [ i ] = value ;
m_dynamic_lp . balance_to_activate_the_risk [ i ] = ( this . m_chosen_balance + ( this . m_chosen_balance * ( m_dynamic_lp . balance_to_activate_the_risk [ i ] / 100.0 ) ) ) ;
if ( i < ArraySize ( m_dynamic_lp . balance_to_activate_the_risk ) - 1 & & hay_negativos & & hay_positivos & & ! c )
{
if ( m_dynamic_lp . balance_to_activate_the_risk [ i ] > 0 & & m_dynamic_lp . balance_to_activate_the_risk [ i + 1 ] < 0 )
{
m_index_cambio = i + 1 ; //WARNING: left position is used by default for the simple case only negatives or positives.
}
}
}
//---
this . m_min_val_is = false ;
this . m_max_val_is = false ;
//---
if ( hay_negativos & & ! hay_positivos )
{
m_pos_izquierda = this . m_size_dynamic - 1 ;
m_new_balance_to_overcome = MAX_VAL_DEFINES_CLOSS_PROFIT ;
m_f_change_dynamic = CLossProfit : : CheckNegatives ;
}
else
if ( hay_positivos & & ! hay_negativos )
{
m_pos_izquierda = 0 ;
m_new_balance_to_overcome = MIN_VAL_DEFINES_CLOSE_PROFIT ;
m_f_change_dynamic = CLossProfit : : CheckPositives ;
}
else
{
m_pos_izquierda = m_index_cambio + 1 ;
m_pos_derecha = m_index_cambio ;
m_f_change_dynamic = CLossProfit : : CheckNegativesAndPositives ;
}
//---
this . m_activate_dynamic_risk_per_operation = true ;
if ( IsInfoLogEnabled ( ) )
{
FastLog ( FUNCION_ACTUAL , INFO_TEXT , " Arrays ready " ) ;
PrintArrayAsTable ( m_dynamic_lp . balance_to_activate_the_risk , " Negative percentages to modify the risk " , " balance " ) ;
PrintArrayAsTable ( m_dynamic_lp . risk_to_be_adjusted , " Risk to be adjusted " , " new risk " ) ;
}
}
//+------------------------------------------------------------------+
//| Checks and modifies the percentage |
//+------------------------------------------------------------------+
inline void CLossProfit : : CheckAndModifyThePercentage ( void )
{
if ( ! m_activate_dynamic_risk_per_operation )
{
LogError ( StringFormat ( " Risk %s is not allowed to use dynamic risk " , m_name ) , FUNCION_ACTUAL ) ;
Remover ( ) ;
return ;
}
this . m_f_change_dynamic ( this , m_dynamic_lp , m_lp , m_min_val_is , m_max_val_is , m_size_dynamic , m_pos_izquierda , m_pos_derecha , m_index_cambio , m_new_balance_to_overcome ) ;
// Print(m_lp.calculation_value);
}
//+------------------------------------------------------------------+
//| Funciones estaticas para chekear y modficar el porcentaje |
//+------------------------------------------------------------------+
static void CLossProfit : : CheckPositives ( CLossProfit & ptr , Dynamic_LossProfit & l_p , Loss_Profit & lossprofit , bool & min_val_is_sup , bool & empty_ , const int size_cambios , int & curr_pos , int & empty_i , const int empy_a ,
double & new_balance_to_superate_arriba )
{
//---
const double account_equity = AccountInfoDouble ( ACCOUNT_EQUITY ) ;
//---
if ( ! min_val_is_sup & & account_equity > l_p . balance_to_activate_the_risk [ curr_pos ] ) //toca aumentar riesgo o parar
{
bool normal = false ;
const int last = size_cambios - 1 ;
while ( curr_pos < last )
{
if ( account_equity > l_p . balance_to_activate_the_risk [ curr_pos + + ] & & l_p . balance_to_activate_the_risk [ curr_pos ] > account_equity )
{
normal = true ;
break ;
}
}
if ( normal )
{
new_balance_to_superate_arriba = l_p . balance_to_activate_the_risk [ curr_pos - 1 ] ;
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos - 1 ] ;
}
else
if ( account_equity > l_p . balance_to_activate_the_risk [ curr_pos ] )
{
//verificamos si es mayor, si lo es entonces asiganmos como el maixmo, (hacemos esto por que si size_cambio es 1 no entratra al while, si es mayor a 2 esta verificaion no tiene sentido )
//pero para no estar haciendo otro else if, enotnce shacmeos esto
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos ] ; //llegamos al maximo asignamos el maximo posible
new_balance_to_superate_arriba = curr_pos > 0 ? l_p . balance_to_activate_the_risk [ curr_pos - 1 ] : l_p . balance_to_activate_the_risk [ curr_pos ] ;
min_val_is_sup = true ; //llegamos al maximo
}
}
//---
if ( account_equity < new_balance_to_superate_arriba ) //toca disminir riesgo o parar
{
bool normal = false ;
while ( curr_pos > 0 )
{
curr_pos - - ;
if ( l_p . balance_to_activate_the_risk [ curr_pos ] < account_equity )
{
normal = true ;
break ;
}
}
if ( normal )
{
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos ] ;
new_balance_to_superate_arriba = l_p . balance_to_activate_the_risk [ curr_pos ] ;
curr_pos + + ;
}
else
{
new_balance_to_superate_arriba = MIN_VAL_DEFINES_CLOSE_PROFIT ;
// En este caso si o si es porcentaje
lossprofit . calculation_value = ptr . GetInitialCalcValue ( ) ; //nos pasamos del miinimo entonces aisgnamos el porcentake inicial
}
min_val_is_sup = false ; //Reseteamos, ahora si es pobible aumentar el riesgo
}
}
//+------------------------------------------------------------------+
static void CLossProfit : : CheckNegatives ( CLossProfit & ptr , Dynamic_LossProfit & l_p , Loss_Profit & lossprofit , bool & min_val_is_sup , bool & empty_ , const int size_cambios , int & curr_pos , int & empty_i ,
const int empy_a ,
double & new_balance_to_superate_arriba )
{
//---
const double account_equity = AccountInfoDouble ( ACCOUNT_EQUITY ) ;
//---
if ( ! min_val_is_sup & & account_equity < l_p . balance_to_activate_the_risk [ curr_pos ] ) //toca aumentar riesgo o parar
{
bool normal = false ;
while ( curr_pos > 0 )
{
curr_pos - - ;
if ( account_equity > l_p . balance_to_activate_the_risk [ curr_pos ] )
{
normal = true ;
break ;
}
}
if ( normal )
empty_i = curr_pos + 1 ; //curpos apunta abajo, y empty a arriab
else
{
empty_i = curr_pos ; //ambos abajo pero eso cambia
min_val_is_sup = true ; //llegamos al minimo
}
//---
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ empty_i ] ;
new_balance_to_superate_arriba = l_p . balance_to_activate_the_risk [ empty_i ] ; //arriba
}
//---
if ( account_equity > new_balance_to_superate_arriba ) //toca disminir riesgo o parar
{
const int last = size_cambios - 1 ;
bool normal = false ;
while ( curr_pos < last )
{
if ( account_equity < l_p . balance_to_activate_the_risk [ curr_pos + + ] & & account_equity < l_p . balance_to_activate_the_risk [ curr_pos ] )
{
normal = true ;
break ;
}
}
if ( normal )
{
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos ] ; //usa el riesgo de aqui
empty_i = curr_pos ;
new_balance_to_superate_arriba = l_p . balance_to_activate_the_risk [ empty_i ] ;
curr_pos - - ; //apunta abajo
}
else //nos pasmaos entonces, riesgo inicial
{
lossprofit . calculation_value = ptr . GetInitialCalcValue ( ) ; // En este caso si o si es porcentaje
new_balance_to_superate_arriba = MAX_VAL_DEFINES_CLOSS_PROFIT ;
}
min_val_is_sup = false ; //llegamos al maximo
}
}
//+------------------------------------------------------------------+
static void CLossProfit : : CheckNegativesAndPositives ( CLossProfit & ptr , Dynamic_LossProfit & l_p , Loss_Profit & lossprofit , bool & min_val_sup ,
bool & max_val_sup , const int size_cambios , int & curr_pos_izq , int & curr_pos_drc , const int index_change , double & new_balance_to_superate_arriba )
{
//---
const double account_equity = AccountInfoDouble ( ACCOUNT_EQUITY ) ;
// PrintFormat("%d - %d - cambio en: %d",curr_pos_izq,curr_pos_drc, index_change);
//---
if ( ! min_val_sup & & account_equity < l_p . balance_to_activate_the_risk [ curr_pos_drc ] ) //toca aumentar riesgo o parar
{
if ( max_val_sup )
curr_pos_izq + + ; //size + 1, y luego en while ya se ve la direfencia de 1
//---
bool normal = false ;
bool mid = false ;
//---
while ( curr_pos_drc > 0 )
{
curr_pos_izq - - ;
curr_pos_drc - - ;
if ( account_equity > l_p . balance_to_activate_the_risk [ curr_pos_drc ] )
{
mid = curr_pos_drc = = index_change ;
normal = true ;
break ;
}
}
//---
if ( mid )
lossprofit . calculation_value = ptr . GetInitialCalcValue ( ) ; // En este caso si o si es porcentaje
else
if ( normal )
{
const int sum = curr_pos_drc < index_change ; //si es
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos_drc + sum ] ; //+0 si estamos en linea psoitov y +1 si en negacitva (dado que en positiva los porecntjases son <-)
}
else
{
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos_drc ] ;
min_val_sup = true ; //llegamos al minimo
curr_pos_izq = curr_pos_drc ;
}
max_val_sup = false ;
}
//---
if ( ! max_val_sup & & account_equity > l_p . balance_to_activate_the_risk [ curr_pos_izq ] ) //toca disminir riesgo o parar
{
if ( min_val_sup )
{
curr_pos_drc - - ; //-1
}
const int last = size_cambios - 1 ;
bool normal = false ;
bool mid = false ;
while ( curr_pos_izq < last )
{
curr_pos_drc + + ;
curr_pos_izq + + ;
if ( l_p . balance_to_activate_the_risk [ curr_pos_izq ] > account_equity & & account_equity > l_p . balance_to_activate_the_risk [ curr_pos_drc ] )
{
normal = true ;
mid = curr_pos_drc = = index_change ;
break ;
}
}
if ( mid )
lossprofit . calculation_value = ptr . GetInitialCalcValue ( ) ; // En este caso si o si es porcentaje
else
if ( normal )
{
const int sum = curr_pos_izq < index_change ; //si es
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos_izq + sum ] ;
}
else //nos pasmaos entonces, riesgo inicial
{
lossprofit . calculation_value = l_p . risk_to_be_adjusted [ curr_pos_izq ] ; //maximo
max_val_sup = true ; //llegamos al maximo
curr_pos_drc = curr_pos_izq ;
}
min_val_sup = false ;
}
//---
//PrintFormat("%d - %d - cambio en: %d",curr_pos_izq,curr_pos_drc, index_change);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template < typename TPadre >
class CLossProfitPercentage : public TPadre
{
public :
//---
CLossProfitPercentage ( const int type , const bool im_empty , const bool act_hook , CRiskManagemetBase * & _risk_pointer )
: TPadre ( type , im_empty , act_hook , _risk_pointer ) { }
~ CLossProfitPercentage ( void ) { }
//---
bool ForzeCalcValue ( ) const override ;
bool SetCalcValue ( double val ) const override ;
bool Set ( ) override ;
} ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template < typename TPadre >
bool CLossProfitPercentage : : ForzeCalcValue ( ) const
{
if ( m_empty_flag | | m_type = = LOSSPROFIT_TYPE_GMLPO ) // Si esta vacio o es gmplo retornamos
return false ;
//---
const double dff = GetSavedValue ( ) - m_lp . value ;
CLossProfitPercentage < TPadre > * este = ( CLossProfitPercentage < TPadre > * ) & this ;
este . m_lp . value = m_risk . GetValorWithApplied ( m_lp . calculation_value , m_type , m_lp . percentage_applied_to ) - dff ;
este . m_saved_value = este . m_lp . value ;
return true ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
inline bool CLossProfitPercentage : : Set ( )
{
if ( m_empty_flag )
return false ;
m_lp . value = m_risk . GetValorWithApplied ( m_lp . calculation_value , m_type , m_lp . percentage_applied_to ) ;
# ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogCaution ( StringFormat ( " New value of %s: %.2f " , this . m_name , m_lp . value ) , FUNCION_ACTUAL ) ;
# endif
return true ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
bool CLossProfitPercentage : : SetCalcValue ( double val ) const
{
//---
if ( m_empty_flag )
{
# ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogWarning ( StringFormat ( " Trying to modify percentage on empty object '%s' " , m_name ) , FUNCION_ACTUAL ) ;
# endif
return false ;
}
//---
if ( val < = 0.00 )
{
LogError ( StringFormat ( " Invalid percentage %.2f%% for '%s': must be greater than 0 " , val , m_name ) , FUNCION_ACTUAL ) ;
return false ;
}
//---
if ( val > = 100.00 )
{
LogWarning ( StringFormat ( " Percentage %.2f for '%s' exceeds 100%%, limiting to 100%% " , val , m_name ) , FUNCION_ACTUAL ) ;
val = 100.00 ;
}
//---
LogInfo ( StringFormat ( " Risk percentage '%s' updated: %.2f%% " , m_name , val ) , FUNCION_ACTUAL ) ;
//---
( ( CLossProfitPercentage < TPadre > * ) & this ) . m_lp . calculation_value = val ;
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template < typename TPadre >
class CLossProfitMoney : public TPadre
{
public :
//---
CLossProfitMoney ( const int type , const bool im_empty , const bool act_hook , CRiskManagemetBase * & _risk_pointer )
: TPadre ( type , im_empty , act_hook , _risk_pointer ) { }
~ CLossProfitMoney ( void ) { }
//---
bool SetCalcValue ( double val ) const override ;
bool Set ( ) override ;
bool ForzeCalcValue ( ) const override ;
} ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template < typename TPadre >
bool CLossProfitMoney : : ForzeCalcValue ( ) const
{
if ( m_empty_flag | | m_type = = LOSSPROFIT_TYPE_GMLPO ) // Si esta vacio o es gmplo retornamos
return false ;
//---
const double dff = GetSavedValue ( ) - m_lp . calculation_value ;
CLossProfitMoney < TPadre > * este = ( CLossProfitMoney < TPadre > * ) & this ;
este . m_lp . value = m_lp . calculation_value - dff ;
este . m_saved_value = este . m_lp . value ;
return true ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
inline bool CLossProfitMoney : : Set ( )
{
if ( m_empty_flag )
return false ;
m_lp . value = m_lp . calculation_value ;
# ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogCaution ( StringFormat ( " New value of %s: %.2f " , this . m_name , m_lp . value ) , FUNCION_ACTUAL ) ;
# endif
return true ;
}
//+------------------------------------------------------------------+
template < typename TPadre >
bool CLossProfitMoney : : SetCalcValue ( double val ) const
{
//---
if ( m_empty_flag )
{
# ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogWarning ( StringFormat ( " Trying to modify base money on empty object '%s' " , m_name ) , FUNCION_ACTUAL ) ;
# endif
return false ;
}
//---
if ( val < = 0.00 )
{
LogError ( StringFormat ( " Invalid new base money %.2f for '%s': must be greater than 0.00 " , val , m_name ) , FUNCION_ACTUAL ) ;
return false ;
}
//---
LogInfo ( StringFormat ( " Risk base money '%s' updated: %.2f " , m_name , val ) , FUNCION_ACTUAL ) ;
//---
( ( CLossProfitMoney < TPadre > * ) & this ) . m_lp . calculation_value = val ;
return true ;
}
//+------------------------------------------------------------------+
# endif // MQLARTICLES_RM_LOSSPROFIT_BASE_MQH