MQLArticles/RM/LossProfit.mqh

1225 lines
84 KiB
MQL5
Raw Permalink Normal View History

2025-09-22 09:09:20 -05:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| LossProfit.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372/news |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Niquel Mendoza."
#property link "https://www.mql5.com/es/users/nique_372/news"
#property strict
2025-11-10 09:33:30 -05:00
#ifndef MQLARTICLES_RM_LOSSPROFIT_MQH
#define MQLARTICLES_RM_LOSSPROFIT_MQH
2025-09-22 09:09:20 -05:00
#include "RiskManagementBases.mqh"
2025-11-10 09:33:30 -05:00
class CLossProfit; // Advance declaration for the typedef
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| Defines |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
typedef bool (*FuncionLossProfitSuperate)(const double& value, const double& saved_value, void* ptr);
2025-09-22 09:09:20 -05:00
typedef void (*FLossPoriftDynamic)(CLossProfit&, Dynamic_LossProfit&, Loss_Profit&, bool&, bool&, const int, int&, int&, const int, double&);
#define MAX_VAL_DEFINES_CLOSS_PROFIT 1.7976931348623158e+300
#define MIN_VAL_DEFINES_CLOSE_PROFIT 1.7976931348623158e-300
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| CLossProfit Class |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
class CLossProfit : public CLoggerBase
{
2025-11-26 07:03:20 -05:00
protected:
2025-09-24 14:00:58 -05:00
//--- General
ENUM_TYPE_LOSS_PROFIT type; // Type of maximum loss or profit.
2025-11-26 07:03:20 -05:00
Loss_Profit m_lp; // Structure that will store info of this maximum loss or profit.
2025-09-24 14:00:58 -05:00
FuncionLossProfitSuperate funcion_check_superate; // Function that will "check" if this maximum loss or profit has been exceeded.
FLossPoriftDynamic f_change_dynamic; // Function for dynamic risk
2025-11-26 07:03:20 -05:00
double m_initial_calc_value; // Initial percentage
2025-09-24 14:00:58 -05:00
bool empty_flag; // Flag indicating if "this" class is null
2025-11-26 07:03:20 -05:00
double m_saved_value;
2025-09-24 14:00:58 -05:00
bool is_strict; // Flag indicating that if this class is of maximum profit type, the verification of exceeding will be strict
string name; // Type of maximum loss or profit in string
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
// Variables that store if the type of maximum loss or profit
// if it's a maximum loss = T_LOSS
// if it's a maximum profit = T_PROFIT
ENUM_LOSS_PROFIT type_loss_or_profit;
2025-09-22 09:09:20 -05:00
//---
2025-11-26 07:03:20 -05:00
void* m_ptr_to_superate;
//---
const CRiskManagemetBase *_risk; // Risk management to which this class is subject
2025-09-24 14:00:58 -05:00
CHashMap<double, double> balanceRiskMap; // HashMap for dynamic risk (percentages to exceed and new risk percentage)
//--- Dynamic risk
Dynamic_LossProfit dynamic_lp; // Structure containing the % to exceed and risks to apply
bool ActivateDynamicRiskPerOperation; // Flag indicating if dynamic risk will be applied to this "maximum loss or profit"
double chosen_balance; // Chosen initial balance
int index_cambio; // Change index between positives and negatives
int size_dynamic; // Size of changes
bool min_val_is; // Minimum value exceeded
bool max_val_is; // Maximum value exceeded
int pos_derecha; // Current position on right
int pos_izquierda; // Current position on left
double NewBalanceToOvercome; // Next balance to overcome
string m_cache_percentages_to_activate;
string m_cache_risks_to_be_applied;
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
public:
2025-09-24 14:00:58 -05:00
//--- Constructor
2025-09-22 09:09:20 -05:00
CLossProfit(bool im_empty, CRiskManagemetBase *_risk_pointer);
2025-09-24 14:00:58 -05:00
//--- Main setters
2025-11-26 07:03:20 -05:00
void SetProperties(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_TYPE_LOSS_PROFIT _type, FuncionLossProfitSuperate f_check_sup, bool _is_strict);
2025-09-22 09:09:20 -05:00
void SetDynamic(string percentages_to_activate, string risks_to_be_applied, double _chosen_balance);
void SetDynamic(double _chosen_balance);
2025-11-26 07:03:20 -05:00
void SetPtrSuperated(void* ptr) { m_ptr_to_superate = ptr; }
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//--- Dynamic risk
// Verifies and checks if the risk can be modified (only works in dynamic risk)
2025-09-22 09:09:20 -05:00
inline void CheckAndModifyThePercentage();
2025-09-24 14:00:58 -05:00
// Returns true if the risk is dynamic
2025-09-22 09:09:20 -05:00
inline bool IsDynamicMode() const { return ActivateDynamicRiskPerOperation; }
2025-09-24 14:00:58 -05:00
//--- General getters
// Returns true if the "maximum loss or profit" has been exceeded
2025-10-05 13:01:48 -05:00
__forceinline bool IsSuperated() const;
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
// Returns true if "this" object is invalid
inline bool IsEmpty() const { return empty_flag; }
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
// Type of "maximum loss or profit" in string (character string)
inline string Name() const { return name; }
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
// Returns what this "maximum loss or profit" is "applied to" for its calculation
2025-11-26 07:03:20 -05:00
inline ENUM_APPLIED_PERCENTAGES GetAppliedType() const { return m_lp.percentage_applied_to; }
2025-09-24 14:00:58 -05:00
// Returns the type of "maximum loss or profit" in ENUM format
2025-09-22 09:09:20 -05:00
inline ENUM_TYPE_LOSS_PROFIT GetType() const { return type; }
2025-11-26 07:03:20 -05:00
//
inline ENUM_LOSS_PROFIT GetTypeLossProfit() const { return type_loss_or_profit;}
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
//--- 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
2025-09-24 14:00:58 -05:00
// Current value
2025-11-26 07:03:20 -05:00
__forceinline double GetValue() const { return m_lp.value; } // Getter
bool SetValue(double val); // Setter
2025-09-24 14:00:58 -05:00
2025-11-26 07:03:20 -05:00
// 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; }
// On Profit
bool OnProfit(const double& new_p);
2025-09-24 14:00:58 -05:00
2025-11-26 07:03:20 -05:00
//bool SetProfit(double val);
2025-09-24 14:00:58 -05:00
//--- 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,
2025-09-22 09:09:20 -05:00
double& new_balance_to_superate_arriba);
2025-09-24 14:00:58 -05:00
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,
2025-09-22 09:09:20 -05:00
double& new_balance_to_superate_arriba);
2025-09-24 14:00:58 -05:00
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,
2025-09-22 09:09:20 -05:00
int& curr_pos_drc, const int index_change, double& new_balance_to_superate_arriba);
};
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| Constructor |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
CLossProfit::CLossProfit(bool im_empty, CRiskManagemetBase * _risk_pointer)
: min_val_is(false), max_val_is(false), pos_derecha(0), pos_izquierda(0), type(WRONG_VALUE), funcion_check_superate(NULL), f_change_dynamic(NULL),
2025-11-26 07:03:20 -05:00
m_initial_calc_value(0.00), empty_flag(false), is_strict(false), name(NULL), ActivateDynamicRiskPerOperation(false), index_cambio(0), type_loss_or_profit(WRONG_VALUE),
chosen_balance(0.00), NewBalanceToOvercome(0.00), m_cache_percentages_to_activate(NULL), m_cache_risks_to_be_applied(NULL), m_saved_value(0.00), m_ptr_to_superate(NULL)
2025-09-22 09:09:20 -05:00
{
this.empty_flag = im_empty;
if(empty_flag)
return;
this._risk = _risk_pointer;
}
//+------------------------------------------------------------------+
//| Functions set |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
//#define MORE_INFO_LOSS_PROFIT_DEFINE
//+------------------------------------------------------------------+
bool CLossProfit::SetValue(double val)
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
//---
2025-09-22 09:09:20 -05:00
if(empty_flag)
{
#ifdef MORE_INFO_LOSS_PROFIT_DEFINE
2025-09-24 14:00:58 -05:00
LogWarning(StringFormat("Trying to modify value in empty object '%s'", name), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
#endif
return false;
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
//---
if(val <= 0.0000001)
2025-09-22 09:09:20 -05:00
{
LogError(StringFormat("Invalid value %.2f for '%s': must be greater than 0.00", val, name), FUNCION_ACTUAL);
return false;
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
//---
#ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogInfo(StringFormat("Risk value '%s' updated: %.2f", name, val), FUNCION_ACTUAL);
#endif
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//---
2025-11-26 07:03:20 -05:00
m_lp.value = val;
return true;
2025-09-22 09:09:20 -05:00
}
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
bool CLossProfit::OnProfit(const double& new_p)
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
//---
2025-09-22 09:09:20 -05:00
if(empty_flag)
return false;
2025-11-26 07:03:20 -05:00
//---
if(new_p < 0.00)
{
if(type_loss_or_profit == T_LOSS)
{
m_lp.value += new_p; // Si es negativo es por que se supero y por mucho
}
//---
else
if(type_loss_or_profit == T_PROFIT)
{
const double nv = m_lp.value - new_p;
m_lp.value = (is_strict && nv > m_saved_value) ? m_saved_value : nv;
}
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
//---
2025-11-26 07:03:20 -05:00
else
if(new_p > 0.00)
{
if(type_loss_or_profit == T_LOSS)
{
const double nv = m_lp.value + new_p;
m_lp.value = (is_strict && nv > m_saved_value) ? m_saved_value : nv;
}
//---
else
if(type_loss_or_profit == T_PROFIT)
{
m_lp.value -= new_p; // Si es negativo es por que ya se supero y se gano demas y por mucho
}
}
//---
#ifdef MORE_INFO_LOSS_PROFIT_DEFINE
2025-11-26 07:03:20 -05:00
LogInfo(StringFormat("Risk value '%s' updated: %.2f", name, m_lp.value), FUNCION_ACTUAL);
#endif
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//---
return true;
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
//| Main setter function to set the properties |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
void CLossProfit::SetProperties(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_TYPE_LOSS_PROFIT _type, FuncionLossProfitSuperate f_check_sup, bool _is_strict)
2025-09-22 09:09:20 -05:00
{
if(empty_flag)
return;
2025-09-24 14:00:58 -05:00
//--- Check
if(_percentage < 0.0000000001)
{
2025-11-26 07:03:20 -05:00
LogCriticalError(StringFormat("Invalid calc value %.2f ,must be greater than 0.00", _percentage), FUNCION_ACTUAL);
2025-09-24 14:00:58 -05:00
empty_flag = true;
return;
}
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//---
2025-11-26 07:03:20 -05:00
m_lp.calculation_value = _percentage;
m_lp.percentage_applied_to = _applied;
m_lp.value = 0.00;
2025-09-22 09:09:20 -05:00
this.type = _type;
2025-11-26 07:03:20 -05:00
m_initial_calc_value = _percentage;
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//--- Get the type
2025-09-22 09:09:20 -05:00
switch(_type)
{
case LP_GMLPO:
2025-11-26 07:03:20 -05:00
this.type_loss_or_profit = T_GMLPO;
break;
2025-09-22 09:09:20 -05:00
case LP_MDL:
case LP_MWL:
case LP_MML:
case LP_ML:
this.type_loss_or_profit = T_LOSS;
break;
case LP_MDP:
case LP_MWP:
case LP_MMP:
this.type_loss_or_profit = T_PROFIT;
break;
default:
2025-09-24 14:00:58 -05:00
LogFatalError(StringFormat("The maximum profit or loss type '%s' is invalid", EnumToString(_type)), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
Remover();
break;
}
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
switch(_type)
{
case LP_GMLPO:
2025-09-24 14:00:58 -05:00
this.name = "Gross maximum loss per operation"; // Risk per operation
2025-09-22 09:09:20 -05:00
break;
case LP_MDL:
2025-09-24 14:00:58 -05:00
this.name = "Maximum daily loss";
2025-09-22 09:09:20 -05:00
break;
case LP_MWL:
2025-09-24 14:00:58 -05:00
this.name = "Maximum weekly loss";
2025-09-22 09:09:20 -05:00
break;
case LP_MML:
2025-09-24 14:00:58 -05:00
this.name = "Maximum monthly loss";
2025-09-22 09:09:20 -05:00
break;
case LP_ML:
2025-09-24 14:00:58 -05:00
this.name = "Maximum total loss";
2025-09-22 09:09:20 -05:00
break;
case LP_MDP:
2025-09-24 14:00:58 -05:00
this.name = "Maximum daily profit";
2025-09-22 09:09:20 -05:00
break;
case LP_MWP:
2025-09-24 14:00:58 -05:00
this.name = "Maximum weekly profit";
2025-09-22 09:09:20 -05:00
break;
case LP_MMP:
2025-09-24 14:00:58 -05:00
this.name = "Maximum monthly profit";
2025-09-22 09:09:20 -05:00
break;
default:
2025-09-24 14:00:58 -05:00
LogFatalError(StringFormat("The maximum profit or loss type '%s' is invalid", EnumToString(_type)), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
Remover();
break;
}
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
if(f_check_sup == NULL)
{
2025-09-24 14:00:58 -05:00
LogFatalError(StringFormat("The function to check for exceeding '%s' is invalid.", this.name), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
Remover();
}
else
{
this.funcion_check_superate = f_check_sup;
}
2025-11-26 07:03:20 -05:00
//---
this.is_strict = (this.type_loss_or_profit == T_LOSS) ? _is_strict : !_is_strict;
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
2025-11-26 07:03:20 -05:00
//+--------------------------------------------------------------------------+
//| Function to check if this maximum loss or profit has been exceeded |
//+--------------------------------------------------------------------------+
__forceinline bool CLossProfit::IsSuperated() const
{
return funcion_check_superate(m_lp.value, m_saved_value, m_ptr_to_superate);
}
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
//| Set properties for dynamic risk |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
//---
void CLossProfit::SetDynamic(double _chosen_balance)
{
if(m_cache_percentages_to_activate == NULL || m_cache_risks_to_be_applied == NULL)
{
2025-11-26 07:03:20 -05:00
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);
}
//---
2025-09-22 09:09:20 -05:00
void CLossProfit::SetDynamic(string percentages_to_activate, string risks_to_be_applied, double _chosen_balance)
{
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
if(empty_flag)
{
LogError("The risk is invalid", FUNCION_ACTUAL);
this.ActivateDynamicRiskPerOperation = false;
Remover();
return;
}
//---
StrTo::CstArray(this.dynamic_lp.balance_to_activate_the_risk, percentages_to_activate, ',');
StrTo::CstArray(this.dynamic_lp.risk_to_be_adjusted, risks_to_be_applied, ',');
//---
if(this.dynamic_lp.risk_to_be_adjusted.Size() < 1 || this.dynamic_lp.balance_to_activate_the_risk.Size() < 1)
{
LogCriticalError("The size of the array is less than 1", FUNCION_ACTUAL);
this.ActivateDynamicRiskPerOperation = false;
return;
}
if(this.dynamic_lp.balance_to_activate_the_risk.Size() != this.dynamic_lp.risk_to_be_adjusted.Size())
{
LogCriticalError("The double arrays for the risk due to dynamic operation are not equal", FUNCION_ACTUAL);
this.ActivateDynamicRiskPerOperation = false;
return;
}
//--- Cache values
m_cache_percentages_to_activate = percentages_to_activate;
m_cache_risks_to_be_applied = risks_to_be_applied;
//---
2025-09-22 09:09:20 -05:00
if(IsInfoLogEnabled())
{
FastLog(FUNCION_ACTUAL, INFO_TEXT, "Arrays before revision");
PrintArrayAsTable(dynamic_lp.balance_to_activate_the_risk, "Negative percentages to modify the risk", "balance");
PrintArrayAsTable(dynamic_lp.risk_to_be_adjusted, "Risk to be adjusted", "new risk");
}
//---
balanceRiskMap.Clear();
int indexes_to_remove[];
this.chosen_balance = _chosen_balance;
//---
for(int i = 0 ; i < ArraySize(dynamic_lp.balance_to_activate_the_risk) ; i++)
{
if(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(balanceRiskMap.ContainsKey(dynamic_lp.balance_to_activate_the_risk[i]) == false)
balanceRiskMap.Add(dynamic_lp.balance_to_activate_the_risk[i], dynamic_lp.risk_to_be_adjusted[i]);
else
AddArrayNoVerification(indexes_to_remove, i, 0);
}
//---
RemoveMultipleIndexes(dynamic_lp.balance_to_activate_the_risk, indexes_to_remove, 0);
ArraySort(dynamic_lp.balance_to_activate_the_risk);
ArrayResize(dynamic_lp.risk_to_be_adjusted, ArraySize(dynamic_lp.balance_to_activate_the_risk));
//---
this.size_dynamic = ArraySize(dynamic_lp.balance_to_activate_the_risk);
//---
const bool hay_positivos = HayPositivosArray(dynamic_lp.balance_to_activate_the_risk);
const bool hay_negativos = HayNegativosArray(dynamic_lp.balance_to_activate_the_risk);
bool c = false;
//---
for(int i = 0 ; i < this.size_dynamic; i++)
{
double value;
balanceRiskMap.TryGetValue(this.dynamic_lp.balance_to_activate_the_risk[i], value);
dynamic_lp.risk_to_be_adjusted[i] = value;
dynamic_lp.balance_to_activate_the_risk[i] = (this.chosen_balance + (this.chosen_balance * (dynamic_lp.balance_to_activate_the_risk[i] / 100.0)));
if(i < ArraySize(dynamic_lp.balance_to_activate_the_risk) - 1 && hay_negativos && hay_positivos && !c)
{
if(dynamic_lp.balance_to_activate_the_risk[i] > 0 && dynamic_lp.balance_to_activate_the_risk[i + 1] < 0)
{
2025-09-24 14:00:58 -05:00
index_cambio = i + 1; //WARNING: left position is used by default for the simple case only negatives or positives.
2025-09-22 09:09:20 -05:00
}
}
}
//---
this.min_val_is = false;
this.max_val_is = false;
//---
if(hay_negativos && !hay_positivos)
{
pos_izquierda = this.size_dynamic - 1;
NewBalanceToOvercome = MAX_VAL_DEFINES_CLOSS_PROFIT;
2025-09-24 14:00:58 -05:00
f_change_dynamic = CLossProfit::CheckNegatives;
2025-09-22 09:09:20 -05:00
}
else
if(hay_positivos && !hay_negativos)
{
pos_izquierda = 0;
NewBalanceToOvercome = MIN_VAL_DEFINES_CLOSE_PROFIT;
2025-09-24 14:00:58 -05:00
f_change_dynamic = CLossProfit::CheckPositives;
2025-09-22 09:09:20 -05:00
}
else
{
pos_izquierda = index_cambio + 1;
pos_derecha = index_cambio;
2025-09-24 14:00:58 -05:00
f_change_dynamic = CLossProfit::CheckNegativesAndPositives;
2025-09-22 09:09:20 -05:00
}
//---
this.ActivateDynamicRiskPerOperation = true;
if(IsInfoLogEnabled())
{
FastLog(FUNCION_ACTUAL, INFO_TEXT, "Arrays ready");
PrintArrayAsTable(dynamic_lp.balance_to_activate_the_risk, "Negative percentages to modify the risk", "balance");
PrintArrayAsTable(dynamic_lp.risk_to_be_adjusted, "Risk to be adjusted", "new risk");
}
}
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| Checks and modifies the percentage |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
inline void CLossProfit::CheckAndModifyThePercentage(void)
{
if(!ActivateDynamicRiskPerOperation)
{
2025-09-24 14:00:58 -05:00
LogError(StringFormat("Risk %s is not allowed to use dynamic risk", name), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
Remover();
return;
}
2025-11-26 07:03:20 -05:00
this.f_change_dynamic(this, dynamic_lp, m_lp, min_val_is, max_val_is, size_dynamic, pos_izquierda, pos_derecha, index_cambio, NewBalanceToOvercome);
// Print(m_lp.calculation_value);
2025-09-22 09:09:20 -05:00
}
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| 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,
2025-09-22 09:09:20 -05:00
double& new_balance_to_superate_arriba)
{
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
const double account_equity = AccountInfoDouble(ACCOUNT_EQUITY);
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
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];
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[curr_pos - 1];
2025-09-22 09:09:20 -05:00
}
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
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[curr_pos]; //llegamos al maximo asignamos el maximo posible
2025-09-22 09:09:20 -05:00
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
}
}
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
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)
{
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[curr_pos];
2025-09-22 09:09:20 -05:00
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;
2025-09-24 14:00:58 -05:00
// En este caso si o si es porcentaje
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = ptr.GetInitialCalcValue(); //nos pasamos del miinimo entonces aisgnamos el porcentake inicial
2025-09-22 09:09:20 -05:00
}
min_val_is_sup = false; //Reseteamos, ahora si es pobible aumentar el riesgo
}
}
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
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,
2025-09-22 09:09:20 -05:00
const int empy_a,
double& new_balance_to_superate_arriba)
{
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
const double account_equity = AccountInfoDouble(ACCOUNT_EQUITY);
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
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
}
//---
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[empty_i];
2025-09-22 09:09:20 -05:00
new_balance_to_superate_arriba = l_p.balance_to_activate_the_risk[empty_i]; //arriba
}
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
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)
{
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[curr_pos]; //usa el riesgo de aqui
2025-09-22 09:09:20 -05:00
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
{
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = ptr.GetInitialCalcValue(); // En este caso si o si es porcentaje
2025-09-22 09:09:20 -05:00
new_balance_to_superate_arriba = MAX_VAL_DEFINES_CLOSS_PROFIT;
}
min_val_is_sup = false; //llegamos al maximo
}
}
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
static void CLossProfit::CheckNegativesAndPositives(CLossProfit& ptr, Dynamic_LossProfit& l_p, Loss_Profit &lossprofit, bool& min_val_sup,
2025-09-22 09:09:20 -05:00
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)
{
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
const double account_equity = AccountInfoDouble(ACCOUNT_EQUITY);
// PrintFormat("%d - %d - cambio en: %d",curr_pos_izq,curr_pos_drc, index_change);
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
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)
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = ptr.GetInitialCalcValue(); // En este caso si o si es porcentaje
2025-09-22 09:09:20 -05:00
else
if(normal)
{
const int sum = curr_pos_drc < index_change; //si es
2025-11-26 07:03:20 -05:00
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 <-)
2025-09-22 09:09:20 -05:00
}
else
{
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[curr_pos_drc];
2025-09-22 09:09:20 -05:00
min_val_sup = true; //llegamos al minimo
curr_pos_izq = curr_pos_drc;
}
max_val_sup = false;
}
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
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)
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = ptr.GetInitialCalcValue(); // En este caso si o si es porcentaje
2025-09-22 09:09:20 -05:00
else
if(normal)
{
const int sum = curr_pos_izq < index_change; //si es
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[curr_pos_izq + sum];
2025-09-22 09:09:20 -05:00
}
else //nos pasmaos entonces, riesgo inicial
{
2025-11-26 07:03:20 -05:00
lossprofit.calculation_value = l_p.risk_to_be_adjusted[curr_pos_izq]; //maximo
2025-09-22 09:09:20 -05:00
max_val_sup = true; //llegamos al maximo
curr_pos_drc = curr_pos_izq;
}
min_val_sup = false;
}
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
//PrintFormat("%d - %d - cambio en: %d",curr_pos_izq,curr_pos_drc, index_change);
}
2025-11-26 07:03:20 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CLossProfitPercentage : public CLossProfit
{
private:
public:
//---
CLossProfitPercentage(bool im_empty, CRiskManagemetBase *_risk_pointer) : CLossProfit(im_empty, _risk_pointer) {}
~CLossProfitPercentage(void) {}
//---
bool ForzeCalcValue() const override;
bool SetCalcValue(double val) const override;
bool Set() override;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLossProfitPercentage::ForzeCalcValue() const
{
if(empty_flag || type == LP_GMLPO) // Si esta vacio o es gmplo retornamos
return false;
//---
const double dff = GetSavedValue() - m_lp.value;
CLossProfitPercentage* este = (CLossProfitPercentage*)&this;
este.m_lp.value = _risk.GetValorWithApplied(m_lp.calculation_value, type, m_lp.percentage_applied_to) - dff;
este.m_saved_value = este.m_lp.value;
return true;
}
//+------------------------------------------------------------------+
inline bool CLossProfitPercentage::Set()
{
if(empty_flag)
return false;
m_lp.value = _risk.GetValorWithApplied(m_lp.calculation_value, type, m_lp.percentage_applied_to);
#ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogCaution(StringFormat("New value of %s: %.2f", this.name, m_lp.value), FUNCION_ACTUAL);
#endif
return true;
}
//+------------------------------------------------------------------+
bool CLossProfitPercentage::SetCalcValue(double val) const
{
//---
if(empty_flag)
{
#ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogWarning(StringFormat("Trying to modify percentage on empty object '%s'", name), FUNCION_ACTUAL);
#endif
return false;
}
//---
if(val <= 0.00)
{
LogError(StringFormat("Invalid percentage %.2f%% for '%s': must be greater than 0", val, name), FUNCION_ACTUAL);
return false;
}
//---
if(val >= 100.00)
{
LogWarning(StringFormat("Percentage %.2f for '%s' exceeds 100%%, limiting to 100%%", val, name), FUNCION_ACTUAL);
val = 100.00;
}
//---
LogInfo(StringFormat("Risk percentage '%s' updated: %.2f%%", name, val), FUNCION_ACTUAL);
//---
((CLossProfitPercentage*)&this).m_lp.calculation_value = val;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CLossProfitMoney : public CLossProfit
{
public:
//---
CLossProfitMoney(bool im_empty, CRiskManagemetBase *_risk_pointer) : CLossProfit(im_empty, _risk_pointer) {}
~CLossProfitMoney(void) {}
//---
bool SetCalcValue(double val) const override;
bool Set() override;
bool ForzeCalcValue() const override;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLossProfitMoney::ForzeCalcValue() const
{
if(empty_flag || type == LP_GMLPO) // Si esta vacio o es gmplo retornamos
return false;
//---
const double dff = GetSavedValue() - m_lp.calculation_value;
CLossProfitMoney* este = (CLossProfitMoney*)&this;
este.m_lp.value = m_lp.calculation_value - dff;
este.m_saved_value = este.m_lp.value;
return true;
}
//+------------------------------------------------------------------+
inline bool CLossProfitMoney::Set()
{
if(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.name, m_lp.value), FUNCION_ACTUAL);
#endif
return true;
}
//+------------------------------------------------------------------+
bool CLossProfitMoney::SetCalcValue(double val) const
{
//---
if(empty_flag)
{
#ifdef MORE_INFO_LOSS_PROFIT_DEFINE
LogWarning(StringFormat("Trying to modify base money on empty object '%s'", 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, name), FUNCION_ACTUAL);
return false;
}
//---
LogInfo(StringFormat("Risk base money '%s' updated: %.2f", name, val), FUNCION_ACTUAL);
//---
((CLossProfitMoney*)&this).m_lp.calculation_value = val;
return true;
}
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
//| Manager class to work with different poses |
//+------------------------------------------------------------------+
class CLossProfitManager : public CSpecializedManager
2025-09-22 09:09:20 -05:00
{
private:
//---
2025-09-22 09:09:20 -05:00
CLossProfit* empty_obj;
//---
CLossProfit* m_losses_profits[LOSS_PROFIT_COUNT];
bool m_is_add[LOSS_PROFIT_COUNT]; // Si esta a<EFBFBD>adido
2025-11-26 07:03:20 -05:00
//--- Indices validos
int m_valid_indexes[];
2025-11-26 07:03:20 -05:00
int m_valid_indexes_size;
//---
CLossProfit* m_profits[];
int m_profits_size;
int m_last_idx_profit_sup;
//---
CLossProfit* m_losses[];
int m_losses_size;
int m_last_idx_loss_sup;
2025-09-22 09:09:20 -05:00
public:
~CLossProfitManager();
CLossProfitManager();
2025-09-24 14:00:58 -05:00
//---
2025-11-26 07:03:20 -05:00
__forceinline int SizeValids() const { return m_valid_indexes_size; }
__forceinline int GetIndexValid(const int index) { return m_valid_indexes[index]; }
//---
2025-11-26 07:03:20 -05:00
inline bool IsAdd(const ENUM_TYPE_LOSS_PROFIT type) const { return m_is_add[type]; }
//--- Clear
void Clear();
2025-11-26 07:03:20 -05:00
//--- Add
bool Add(CLossProfit * new_loss_profit); // Add CLossProfit
2025-11-26 07:03:20 -05:00
//--- Is Superated
// Index
__forceinline int GetLastIndexSuperatedProfit() const { return m_last_idx_profit_sup; }
__forceinline int GetLastIndexSuperatedLoss() const { return m_last_idx_loss_sup; }
// Ptr
const CLossProfit* const GetLastLossSuperated() const { return m_losses[m_last_idx_loss_sup]; }
const CLossProfit* const GetLastProfitSuperated() const { return m_profits[m_last_idx_profit_sup]; }
// Type
__forceinline ENUM_TYPE_LOSS_PROFIT GetLastLossSuperatedType() const { return m_losses[m_last_idx_loss_sup].GetType(); }
__forceinline ENUM_TYPE_LOSS_PROFIT GetLastProfitSuperatedType() const { return m_profits[m_last_idx_profit_sup].GetType(); }
// Main
bool MaxProfitIsSuperated() const;
bool MaxLossIsSuperated() const;
//--- On
void OnProfit(const double& p);
void SetNewChossenBalanceForDynamicsAndSet(double _chosen_balance, bool update);
void SetValues(); // Setear valores
void SetValuesAndDynamic(); // Valores y dinamicos
void CheckDynamic();
2025-11-26 07:03:20 -05:00
//---
void Summary() const;
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
CLossProfit* operator[](const ENUM_TYPE_LOSS_PROFIT type);
CLossProfit* operator[](const int index) { return m_losses_profits[index]; }
2025-09-22 09:09:20 -05:00
};
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| Contructor y Destructor |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
CLossProfitManager::CLossProfitManager()
{
2025-11-26 07:03:20 -05:00
//---
m_valid_indexes_size = ArrayResize(m_valid_indexes, 0);
m_profits_size = ArrayResize(m_profits, 0);
m_losses_size = ArrayResize(m_losses, 0);
m_last_idx_profit_sup = -1;
m_last_idx_loss_sup = -1;
//---
empty_obj = new CLossProfitPercentage(true, NULL);
2025-09-22 09:09:20 -05:00
for(int i = 0; i < LOSS_PROFIT_COUNT; i++)
{
m_losses_profits[i] = NULL;
m_is_add[i] = false;
2025-09-22 09:09:20 -05:00
}
}
//+------------------------------------------------------------------+
CLossProfitManager::~CLossProfitManager(void)
{
delete empty_obj;
Clear(); // Eliminamos todos los punteros
2025-09-22 09:09:20 -05:00
}
2025-11-26 07:03:20 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CLossProfitManager::Summary(void) const
{
Print("------------");
Print("Number of losses to revise: ", m_losses_size);
Print("Number of profits to revise: ", m_profits_size);
Print("Total losses and profits: ", SizeValids());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLossProfitManager::MaxProfitIsSuperated(void) const
{
for(int i = 0; i < m_profits_size; i++)
{
if(m_profits[i].IsSuperated())
{
((CLossProfitManager*)&this).m_last_idx_profit_sup = i;
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
bool CLossProfitManager::MaxLossIsSuperated(void) const
{
for(int i = 0; i < m_losses_size; i++)
{
if(m_losses[i].IsSuperated())
{
((CLossProfitManager*)&this).m_last_idx_loss_sup = i;
return true;
}
}
return false;
}
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CLossProfitManager::SetValues()
2025-09-22 09:09:20 -05:00
{
2025-11-26 07:03:20 -05:00
for(int i = 0; i < m_valid_indexes_size; i++)
{
const int k = m_valid_indexes[i];
m_losses_profits[k].Set(); // Setea el valor
m_losses_profits[k].SetSavedValue();
}
2025-09-22 09:09:20 -05:00
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CLossProfitManager::SetValuesAndDynamic()
2025-09-22 09:09:20 -05:00
{
2025-11-26 07:03:20 -05:00
for(int i = 0; i < m_valid_indexes_size; i++)
{
const int key = m_valid_indexes[i];
m_losses_profits[key].Set(); // Setea el valor
if(m_losses_profits[key].IsDynamicMode()) // Check si es dinamico
m_losses_profits[key].CheckAndModifyThePercentage(); // Modificamos
}
2025-09-22 09:09:20 -05:00
}
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CLossProfitManager::SetNewChossenBalanceForDynamicsAndSet(double _chosen_balance, bool update)
2025-09-22 09:09:20 -05:00
{
2025-11-26 07:03:20 -05:00
for(int i = 0; i < m_valid_indexes_size; i++)
2025-09-22 09:09:20 -05:00
{
const int key = m_valid_indexes[i];
m_losses_profits[key].Set();
if(m_losses_profits[key].IsDynamicMode()) // Check si es dinamico
{
m_losses_profits[key].SetDynamic(_chosen_balance); // Modificamos
if(update)
m_losses_profits[key].CheckAndModifyThePercentage();
}
2025-09-22 09:09:20 -05:00
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CLossProfitManager::CheckDynamic(void)
2025-09-22 09:09:20 -05:00
{
2025-11-26 07:03:20 -05:00
for(int i = 0; i < m_valid_indexes_size; i++)
2025-09-22 09:09:20 -05:00
{
const int key = m_valid_indexes[i];
if(m_losses_profits[key].IsDynamicMode()) // Check si es dinamico
m_losses_profits[key].CheckAndModifyThePercentage(); // Modificamos
2025-09-22 09:09:20 -05:00
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
void CLossProfitManager::OnProfit(const double &p)
{
for(int i = 0; i < m_losses_size; i++)
m_losses[i].OnProfit(p);
for(int i = 0; i < m_profits_size; i++)
m_profits[i].OnProfit(p);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CLossProfitManager::Clear(void)
{
2025-11-26 07:03:20 -05:00
//---
ArrayInitialize(m_is_add, false);
2025-11-26 07:03:20 -05:00
//---
m_valid_indexes_size = ArrayResize(m_valid_indexes, 0);
m_profits_size = ArrayResize(m_profits, 0);
m_losses_size = ArrayResize(m_losses, 0);
//---
CleanItems("CLossProfitManager"); // Delete pointers (m_losses_profits
}
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
//| operator[] |
//+------------------------------------------------------------------+
CLossProfit* CLossProfitManager::operator[](const ENUM_TYPE_LOSS_PROFIT type)
{
return m_is_add[type] ? m_losses_profits[type] : empty_obj;
2025-09-22 09:09:20 -05:00
}
//+------------------------------------------------------------------+
//| Function that is executed every time a new item is added |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
// check_duplicate: No tiene efecto
2025-11-26 07:03:20 -05:00
bool CLossProfitManager::Add(CLossProfit * new_loss_profit)
2025-09-22 09:09:20 -05:00
{
//---
2025-09-22 09:09:20 -05:00
if(CheckPointer(new_loss_profit) == POINTER_INVALID)
{
2025-09-24 14:00:58 -05:00
LogFatalError("The pointer to CLossProfit* is invalid", FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
Remover();
2025-11-26 07:03:20 -05:00
return false;
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
//---
2025-09-22 09:09:20 -05:00
const int idx = (int)new_loss_profit.GetType();
if(m_is_add[idx])
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
LogWarning(StringFormat("The loss or gain %s has already been added, it will not be added.", new_loss_profit.Name()), FUNCION_ACTUAL);
2025-11-26 07:03:20 -05:00
return false;
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
//---
2025-11-26 07:03:20 -05:00
ArrayResize(m_valid_indexes, m_valid_indexes_size + 1);
m_valid_indexes[m_valid_indexes_size] = idx;
m_valid_indexes_size++;
//---
if(new_loss_profit.GetTypeLossProfit() == T_LOSS)
{
ArrayResize(m_losses, m_losses_size + 1);
m_losses[m_losses_size] = new_loss_profit;
m_losses_size++;
}
else
if(new_loss_profit.GetTypeLossProfit() == T_PROFIT)
{
ArrayResize(m_profits, m_profits_size + 1);
m_profits[m_profits_size] = new_loss_profit;
m_profits_size++;
}
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//---
m_is_add[idx] = true;
m_losses_profits[idx] = new_loss_profit;
//---
AddLogger(new_loss_profit);
2025-11-26 07:03:20 -05:00
return true;
2025-09-22 09:09:20 -05:00
}
2025-09-22 09:09:20 -05:00
/*
ADVERTENCIA:
- Al momento de a<EFBFBD>adir items a esta clase, esta si son dinamicos las eliminara cuidado.
- El unico que maneja esta clase es CRiskManagement, por lo que no se puede remover elementos
WARNINGS:
- When adding items to this class, if they are dynamic, be careful.
- The only one that handles this class is CRiskManagement, so elements cannot be removed.
2025-09-22 09:09:20 -05:00
*/
//+------------------------------------------------------------------+
2025-11-10 09:33:30 -05:00
#endif // MQLARTICLES_RM_LOSSPROFIT_MQH
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+