//+------------------------------------------------------------------+ //| 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 #ifndef RISK_LOSS_PROFIT_MQH #define RISK_LOSS_PROFIT_MQH #include "RiskManagementBases.mqh" class CLossProfit; //declaracion anticipada para el typedef //+------------------------------------------------------------------+ //| Defines | //+------------------------------------------------------------------+ typedef bool (*FuncionLossProfitSuperate)(double profit_, double value_, bool strict, double extra_value); 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 //+------------------------------------------------------------------+ //| CLossProfit Class | //+------------------------------------------------------------------+ class CLossProfit : public CLoggerBase { private: //--- General ENUM_TYPE_LOSS_PROFIT type; // Type of maximum loss or profit. Loss_Profit lp; // Structure that will store info of this maximum loss or profit. 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 double initial_percentage; // Initial percentage bool empty_flag; // Flag indicating if "this" class is null double curr_profit; // Current profit referring to this maximum loss or profit bool is_strict; // Flag indicating that if this class is of maximum profit type, the verification of exceeding will be strict long cv; string name; // Type of maximum loss or profit in string // 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; //--- CRiskManagemetBase *_risk; // Risk management to which this class is subject CHashMap 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; //--- Extra value double extra_value; public: //--- Constructor CLossProfit(bool im_empty, CRiskManagemetBase *_risk_pointer); //--- Main setters inline bool Set(); void SetProperties(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_RISK_CALCULATION_MODE _mode, ENUM_TYPE_LOSS_PROFIT _type, FuncionLossProfitSuperate f_check_sup, bool _is_strict = false); void SetDynamic(string percentages_to_activate, string risks_to_be_applied, double _chosen_balance); void SetDynamic(double _chosen_balance); //--- 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 ActivateDynamicRiskPerOperation; } //--- General getters // Returns true if the "maximum loss or profit" has been exceeded inline bool IsSuperated() const; // Returns true if "this" object is invalid inline bool IsEmpty() const { return empty_flag; } // Type of "maximum loss or profit" in string (character string) inline string Name() const { return name; } // Returns what this "maximum loss or profit" is "applied to" for its calculation inline ENUM_APPLIED_PERCENTAGES GetAppliedType() const { return lp.percentage_applied_to; } // Returns the calculation mode (money or % applied to "lp.percentage_applied_to") inline ENUM_RISK_CALCULATION_MODE GetModeCalculation() const { return lp.mode_calculation_risk; } // Returns the type of "maximum loss or profit" in ENUM format inline ENUM_TYPE_LOSS_PROFIT GetType() const { return type; } //--- Functions to work with the (Percentage | Value | Accumulated Profit) of the "maximum loss or profit" // Initial percentage or money inline double GetInitialPercentageOrMoney() const { return this.initial_percentage; } // Getter inline void SetInitialPercentageOrMoney() { lp.assigned_percentage = this.initial_percentage; } // Setter // Current value inline double GetValue() const { return lp.value; } // Getter bool SetValue(double val, int8_t i); // Setter // Percentage (given that if the calculation mode is money, assigned_percentage has the money value, of course. // But modifying "lp.assigned_percentage" has no effect. inline double GetPercentage() const { return lp.assigned_percentage; } // Getter bool SetPercentage(double val); // Setter // Sets the profit bool SetProfit(double val, int8_t i); //--- 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(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), initial_percentage(0.00), empty_flag(false), is_strict(false), name(NULL), ActivateDynamicRiskPerOperation(false), index_cambio(0), type_loss_or_profit(WRONG_VALUE), extra_value(0.00), chosen_balance(0.00), NewBalanceToOvercome(0.00), m_cache_percentages_to_activate(NULL), m_cache_risks_to_be_applied(NULL) { this.empty_flag = im_empty; if(empty_flag) return; this._risk = _risk_pointer; //--- this.cv = _risk.d(); this.extra_value = _risk.GetExtraValueForLossProfit(); } //+------------------------------------------------------------------+ //| Function to set the percentage | //+------------------------------------------------------------------+ //#define DEBUG_LOSS_PROFIT_DEFINE //--- bool CLossProfit::SetPercentage(double val) { //--- if(empty_flag) { #ifdef DEBUG_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); lp.assigned_percentage = val; return true; } //+------------------------------------------------------------------+ bool CLossProfit::SetValue(double val, int8_t i) { //--- if(empty_flag) { #ifdef DEBUG_LOSS_PROFIT_DEFINE LogWarning(StringFormat("Trying to modify value in empty object '%s'", name), FUNCION_ACTUAL); #endif return false; } //--- if(cv != i) { LogError(StringFormat("Unauthorized access to modify the value of '%s'", name), FUNCION_ACTUAL); return false; } //--- if(val <= 0.00) { LogError(StringFormat("Invalid value %.2f for '%s': must be greater than 0", val, name), FUNCION_ACTUAL); return false; } //--- LogInfo(StringFormat("Risk value '%s' updated: %.2f", name, val), FUNCION_ACTUAL); this.lp.value = val; return true; } //+------------------------------------------------------------------+ //| Function to set the profit | //+------------------------------------------------------------------+ bool CLossProfit::SetProfit(double val, int8_t i) { //--- if(empty_flag) { #ifdef DEBUG_LOSS_PROFIT_DEFINE LogWarning(StringFormat("Trying to modify profit on empty object '%s'", name), FUNCION_ACTUAL); #endif return false; } //--- if(cv != i) { LogError(StringFormat("Unauthorized access to modify profit of '%s'", name), FUNCION_ACTUAL); return false; } //--- LogInfo(StringFormat("Updated '%s' profit: %.2f", name, val), FUNCION_ACTUAL); this.curr_profit = val; return true; } //+--------------------------------------------------------------------------+ //| Function to check if this maximum loss or profit has been exceeded | //+--------------------------------------------------------------------------+ inline bool CLossProfit::IsSuperated() const { if(empty_flag || type == LP_GMLPO) return false; return funcion_check_superate(curr_profit, lp.value, this.is_strict, this.extra_value); //this.type_loss_or_profit == T_PROFIT ? _risk.IsSuperatedProfit(curr_profit, lp.value, mode, is_strict, type) : _risk.IsSuperatedLoss(curr_profit, lp.value, mode, type); } //+------------------------------------------------------------------+ //| Main setter function to set the properties | //+------------------------------------------------------------------+ void CLossProfit::SetProperties(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_RISK_CALCULATION_MODE _mode, ENUM_TYPE_LOSS_PROFIT _type, FuncionLossProfitSuperate f_check_sup, bool _is_strict = false) { if(empty_flag) return; //--- Check if(_percentage < 0.0000000001) { const string val = RiskCalcModeToString[_mode]; LogCriticalError(StringFormat("%s %.2f invalid, %s must be greater than 0.00", val, _percentage, val), FUNCION_ACTUAL); empty_flag = true; return; } //--- lp.assigned_percentage = _percentage; lp.mode_calculation_risk = _mode; lp.percentage_applied_to = _applied; //--- this.type = _type; this.initial_percentage = _percentage; this.is_strict = _is_strict; this.lp.value = (this.lp.mode_calculation_risk == money) ? lp.assigned_percentage : 0.00; //--- Get the type switch(_type) { case LP_GMLPO: 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: LogFatalError(StringFormat("The maximum profit or loss type '%s' is invalid", EnumToString(_type)), FUNCION_ACTUAL); Remover(); break; } switch(_type) { case LP_GMLPO: this.name = "Gross maximum loss per operation"; // Risk per operation break; case LP_MDL: this.name = "Maximum daily loss"; break; case LP_MWL: this.name = "Maximum weekly loss"; break; case LP_MML: this.name = "Maximum monthly loss"; break; case LP_ML: this.name = "Maximum total loss"; break; case LP_MDP: this.name = "Maximum daily profit"; break; case LP_MWP: this.name = "Maximum weekly profit"; break; case LP_MMP: this.name = "Maximum monthly profit"; break; default: LogFatalError(StringFormat("The maximum profit or loss type '%s' is invalid", EnumToString(_type)), FUNCION_ACTUAL); Remover(); break; } if(f_check_sup == NULL) { LogFatalError(StringFormat("The function to check for exceeding '%s' is invalid.", this.name), FUNCION_ACTUAL); Remover(); } else { this.funcion_check_superate = f_check_sup; } } //+------------------------------------------------------------------------------------------+ //| Function to automatically set the value of the "maximum loss or profit" | //+------------------------------------------------------------------------------------------+ inline bool CLossProfit::Set() { if(empty_flag) return false; this.lp.value = lp.mode_calculation_risk == percentage ? _risk.GetValorWithApplied(lp.assigned_percentage, type, lp.percentage_applied_to) : lp.value; LogCaution(StringFormat("New value of %s: %.2f", this.name, this.lp.value), FUNCION_ACTUAL); return true; } //+------------------------------------------------------------------+ //| Set properties for dynamic risk | //+------------------------------------------------------------------+ //--- void CLossProfit::SetDynamic(double _chosen_balance) { if(m_cache_percentages_to_activate == NULL || m_cache_risks_to_be_applied == NULL) { LogError("Strings invalidos, primero llame a 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(empty_flag) { LogError("The risk is invalid", FUNCION_ACTUAL); this.ActivateDynamicRiskPerOperation = false; Remover(); return; } if(this.lp.mode_calculation_risk == money) { this.ActivateDynamicRiskPerOperation = false; LogCriticalError("'Money' mode is not valid for dynamic risk, change it to 'Percentage %' or change the group mode to 'No dynamic risk for risk per operation' ", FUNCION_ACTUAL); 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; //--- 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) { index_cambio = i + 1; //WARNING: left position is used by default for the simple case only negatives or positives. } } } //--- 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; f_change_dynamic = CLossProfit::CheckNegatives; } else if(hay_positivos && !hay_negativos) { pos_izquierda = 0; NewBalanceToOvercome = MIN_VAL_DEFINES_CLOSE_PROFIT; f_change_dynamic = CLossProfit::CheckPositives; } else { pos_izquierda = index_cambio + 1; pos_derecha = index_cambio; f_change_dynamic = CLossProfit::CheckNegativesAndPositives; } //--- 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"); } } //+------------------------------------------------------------------+ //| Checks and modifies the percentage | //+------------------------------------------------------------------+ inline void CLossProfit::CheckAndModifyThePercentage(void) { if(!ActivateDynamicRiskPerOperation) { LogError(StringFormat("Risk %s is not allowed to use dynamic risk", name), FUNCION_ACTUAL); Remover(); return; } this.f_change_dynamic(this, dynamic_lp, lp, min_val_is, max_val_is, size_dynamic, pos_izquierda, pos_derecha, index_cambio, NewBalanceToOvercome); // Print(lp.assigned_percentage); } //+------------------------------------------------------------------+ //| 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.assigned_percentage = 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.assigned_percentage = 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.assigned_percentage = 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.assigned_percentage = ptr.GetInitialPercentageOrMoney(); //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.assigned_percentage = 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.assigned_percentage = 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.assigned_percentage = ptr.GetInitialPercentageOrMoney(); // 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.assigned_percentage = ptr.GetInitialPercentageOrMoney(); // En este caso si o si es porcentaje else if(normal) { const int sum = curr_pos_drc < index_change; //si es lossprofit.assigned_percentage = 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.assigned_percentage = 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.assigned_percentage = ptr.GetInitialPercentageOrMoney(); // En este caso si o si es porcentaje else if(normal) { const int sum = curr_pos_izq < index_change; //si es lossprofit.assigned_percentage = l_p.risk_to_be_adjusted[curr_pos_izq + sum]; } else //nos pasmaos entonces, riesgo inicial { lossprofit.assigned_percentage = 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); } //+------------------------------------------------------------------+ //| Manager class to work with different poses | //+------------------------------------------------------------------+ class CLossProfitManager : public CSpecializedManager { private: //--- CLossProfit* empty_obj; //--- CLossProfit* m_losses_profits[LOSS_PROFIT_COUNT]; bool m_is_add[LOSS_PROFIT_COUNT]; // Si esta añadido int m_valid_indexes[]; public: ~CLossProfitManager(); CLossProfitManager(); //--- inline int SizeValids() const { return ArraySize(m_valid_indexes); } inline int GetIndexValid(const int index) { return m_valid_indexes[index]; } //--- inline bool IsAdd(const ENUM_TYPE_LOSS_PROFIT type) { return m_is_add[type]; } //--- Clear void Clear(); //--- void Add(CLossProfit * new_loss_profit); // Add CLossProfit //--- void SetNewChossenBalanceForDynamics(double _chosen_balance, bool update); void SetValues(); // Setear valores void SetValuesAndDynamic(); // Valores y dinamicos void CheckDynamic(); //--- Operadores CLossProfit* operator[](const ENUM_TYPE_LOSS_PROFIT type); CLossProfit* operator[](const int index) { return m_losses_profits[index]; } }; //+------------------------------------------------------------------+ //| Contructor y Destructor | //+------------------------------------------------------------------+ CLossProfitManager::CLossProfitManager() { ArrayResize(m_valid_indexes, 0); empty_obj = new CLossProfit(true, NULL); for(int i = 0; i < LOSS_PROFIT_COUNT; i++) { m_losses_profits[i] = NULL; m_is_add[i] = false; } } //+------------------------------------------------------------------+ CLossProfitManager::~CLossProfitManager(void) { delete empty_obj; Clear(); // Eliminamos todos los punteros } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CLossProfitManager::SetValues() { for(int i = 0; i < ArraySize(m_valid_indexes); i++) m_losses_profits[m_valid_indexes[i]].Set(); // Setea el valor } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CLossProfitManager::SetValuesAndDynamic() { for(int i = 0; i < ArraySize(m_valid_indexes); 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 } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CLossProfitManager::CheckDynamic(void) { for(int i = 0; i < ArraySize(m_valid_indexes); i++) { const int key = m_valid_indexes[i]; if(m_losses_profits[key].IsDynamicMode()) // Check si es dinamico m_losses_profits[key].CheckAndModifyThePercentage(); // Modificamos } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CLossProfitManager::SetNewChossenBalanceForDynamics(double _chosen_balance, bool update) { for(int i = 0; i < ArraySize(m_valid_indexes); i++) { const int key = m_valid_indexes[i]; 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(); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CLossProfitManager::Clear(void) { ArrayInitialize(m_is_add, false); ArrayResize(m_valid_indexes, 0); CleanItems("CLossProfitManager"); // Delete pointers (m_losses_profits } //+------------------------------------------------------------------+ //| operator[] | //+------------------------------------------------------------------+ CLossProfit* CLossProfitManager::operator[](const ENUM_TYPE_LOSS_PROFIT type) { return m_is_add[type] ? m_losses_profits[type] : empty_obj; } //+------------------------------------------------------------------+ //| Function that is executed every time a new item is added | //+------------------------------------------------------------------+ // check_duplicate: No tiene efecto void CLossProfitManager::Add(CLossProfit * new_loss_profit) { //--- if(CheckPointer(new_loss_profit) == POINTER_INVALID) { LogFatalError("The pointer to CLossProfit* is invalid", FUNCION_ACTUAL); Remover(); return; } //--- const int idx = (int)new_loss_profit.GetType(); if(m_is_add[idx]) { LogWarning(StringFormat("The loss or gain %s has already been added, it will not be added.", new_loss_profit.Name()), FUNCION_ACTUAL); return; } //--- AddArrayNoVerification2(m_valid_indexes, idx, 0) //--- m_is_add[idx] = true; m_losses_profits[idx] = new_loss_profit; //--- AddLogger(new_loss_profit); } /* ADVERTENCIA: - Al momento de añ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. */ //+------------------------------------------------------------------+ #endif //+------------------------------------------------------------------+