799 行
31 KiB
MQL5
799 行
31 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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),
|
|
m_funcion_check_sup(NULL), m_magic_number(im_empty ? NOT_MAGIC_NUMBER : _risk_pointer.MagicNumber())
|
|
{
|
|
//---
|
|
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
|