forked from nique_372/MQLArticles
1153 lines
44 KiB
MQL5
1153 lines
44 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| RiskManagement.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 MQLARTICLES_RM_RISKMANAGEMENT_MQH
| |
#define MQLARTICLES_RM_RISKMANAGEMENT_MQH
| |
| |
#include "RM_Hooks.mqh"
| |
| |
/*
| |
ADVERTENCIA al momeneto de añadir items a esta clase, esta si son dinamicos las eliminara cuidado, como un modificador.
| |
WARNING when adding items to this class, if they are dynamic, it will remove them carefully, as a modifier.
| |
*/
| |
| |
//open_positions
| |
//+------------------------------------------------------------------+
| |
//| Clase Base CRiskManagement |
| |
//+------------------------------------------------------------------+
| |
class CRiskManagemet : public CRiskManagemetBase
| |
{
| |
protected:
| |
//---
| |
CGetLote* get_lote;
| |
| |
//---
| |
double chosen_balance;
| |
| |
//--- Extra Variables
| |
ENUM_GET_LOT type_get_lot;
| |
| |
//-- main variables
| |
long StopLoss; //StopLoss
| |
double lote; //Last recorded lot
| |
| |
//--- variables to store the values of the maximum losses
| |
double nmlpo; //last expected loss
| |
bool is_init; //flag indicating if it is init
| |
| |
//--- variables that store percentages and enumeration, which will be used for the subsequent calculation of losses
| |
CLossProfitManager loss_profits_manager;
| |
| |
//--- Modifiers
| |
CRiskManagemeHookManager m_hooks;
| |
bool isCachedModifier[LOSS_PROFIT_COUNT];
| |
| |
//--- general function to assign values to loss variables
| |
virtual double GetValorWithApplied(double percentage_, int type, ENUM_APPLIED_PERCENTAGES applied) const override;
| |
| |
//--- Update profits function
| |
void UpdateProfit(const double profit, const double acc_total_profit);
| |
virtual void OnOpenTrade() { }
| |
virtual void OnCloseTrade() { }
| |
| |
//---
| |
virtual FuncionLossProfitSuperate SuperateModeToFunctionProfit(ENUM_TYPE_LOSS_PROFIT type) const;
| |
virtual FuncionLossProfitSuperate SuperateModeToFunctionLoss(ENUM_TYPE_LOSS_PROFIT type) const;
| |
| |
//---
| |
virtual void* GetPtrLossProfits() { return &this; }
| |
| |
| |
public:
| |
//--- Constructor and Destructor
| |
CRiskManagemet(const ulong _magic, const ENUM_GET_LOT type_get_lot_);
| |
~CRiskManagemet();
| |
| |
//--- Set
| |
void EndAddProfitLoss();
| |
virtual void SetGeneralParameters(MqlParam ¶ms[]) = 0;
| |
void SetLote(CGetLote* lote_ptr);
| |
inline void SetStopLoss(double dist_open_sl) { this.StopLoss = (long)ConvertPriceToPoints(_Symbol, dist_open_sl); }
| |
inline void SetStopLoss(long _sl_point_) { this.StopLoss = _sl_point_; }
| |
| |
//--- Get losses and profits
| |
const CLossProfit* const GetLossOrProfit(const ENUM_TYPE_LOSS_PROFIT _type) const { return loss_profits_manager[_type]; }
| |
| |
//--- Superated funcionts
| |
const CLossProfitManager* GetLossProfitManager() const { return &loss_profits_manager; }
| |
| |
//--- Add
| |
// Modificators
| |
bool AddModificator(CExtraModifications* modificator); // Modificator pointer
| |
__forceinline bool AddModificator(CExtraModifications &modificator) { return AddModificator(&modificator); }
| |
| |
// Hook
| |
bool AddRmHook(IRiskManagementHook* hook);
| |
__forceinline bool AddRmHook(IRiskManagementHook& hook) { return AddRmHook(&hook); }
| |
| |
// Loss
| |
| |
bool AddLoss(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_RISK_CALCULATION_MODE _mode, ENUM_TYPE_LOSS_PROFIT type, bool strict,
| |
bool is_dynamic = false, string percentages_to_activate = NULL, string risks_to_be_applied = NULL); // Loss
| |
| |
// Profit
| |
bool AddProfit(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_RISK_CALCULATION_MODE _mode, ENUM_TYPE_LOSS_PROFIT type, bool is_strict_,
| |
bool is_dynamic = false, string percentages_to_activate = NULL, string risks_to_be_applied = NULL); // Profit
| |
| |
//--- Functions inherited from CAccountGestor
| |
// Basic events
| |
void OnNewDay(const datetime curr_time) override;
| |
void OnNewWeek(const datetime curr_time) override;
| |
void OnNewMonth(const datetime curr_time) override;
| |
| |
// Account status
| |
void OnNewProfit(const RAccountProfit &profit, const datetime curr_time) override;
| |
void OnClosePosition(const ROnClosePosition &pos, const int global_pos_index) override;
| |
void OnOpenPosition(const ROnOpenPosition &pos) override;
| |
void OnWithdrawalDeposit(const double value) override;
| |
void OnInitNewPos(const ROnOpenPosition &position) override;
| |
| |
//--- Get the lot using GMPLO and type_get_lot
| |
double GetLote(ENUM_ORDER_TYPE type, double entry_price, ulong deviation, ulong stop_limit);
| |
| |
//--- Obtain the SL by risk per operation
| |
long GetSL(ENUM_ORDER_TYPE type, double entry_price, ulong deviation, ulong stop_limit);
| |
| |
//--- Functions for working with the get lot size mod
| |
void TypeGetLot(ENUM_GET_LOT new_get_mode) { this.type_get_lot = new_get_mode; }
| |
inline ENUM_GET_LOT TypeGetLot() const { return this.type_get_lot; }
| |
| |
| |
//---
| |
__forceinline double LastLotSize() const { return this.lote; }
| |
__forceinline double Nlmpo() const { return this.nmlpo; }
| |
| |
//--- Risk management type
| |
virtual inline ENUM_MODE_RISK_MANAGEMENT ModeRiskManagement() const = 0;
| |
};
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| Constructor |
| |
//+------------------------------------------------------------------+
| |
CRiskManagemet::CRiskManagemet(const ulong _magic, const ENUM_GET_LOT type_get_lot_)
| |
: CRiskManagemetBase(_magic)
| |
{
| |
| |
//---
| |
this.chosen_balance = AccountInfoDouble(ACCOUNT_BALANCE);
| |
for(int i = 0 ; i < LOSS_PROFIT_COUNT; i++)
| |
{
| |
isCachedModifier[i] = false;
| |
}
| |
| |
//---
| |
const bool ac_i = account_status.IsInitialized();
| |
| |
//--- Registramos la clase para recibir eventos
| |
// Basicos
| |
CBasicEvents::Register(&this, BASICEVENT_REG_ALL_FLAG); // OnNewDay, Week, Month
| |
| |
// Para trabajar con las posiciones
| |
account_status.RegisterEvents(&this,
| |
(ACCOUNT_STATUS_REG_FLAG_ON_OPEN_POSITION |
| |
ACCOUNT_STATUS_REG_FLAG_ON_CLOSE_POSITION |
| |
ACCOUNT_STATUS_REG_FLAG_ON_WITHDRAWAL_DEPOSIT |
| |
ACCOUNT_STATUS_REG_FLAG_ON_NEW_PROFIT |
| |
(ac_i ? 0 : ACCOUNT_STATUS_REG_FLAG_ON_INIT_NEW_POS)
| |
));
| |
| |
| |
//---
| |
this.type_get_lot = type_get_lot_;
| |
| |
//---
| |
AddLogger(loss_profits_manager); // Si pertenece..
| |
AddLogger(m_hooks);
| |
| |
//---
| |
if(ac_i) // Se crea luego de que se inicie
| |
{
| |
g_account_open_positions.GetPositionsFromMagic(_magic, m_positions, m_positions_size);
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Destructor |
| |
//+------------------------------------------------------------------+
| |
CRiskManagemet::~CRiskManagemet()
| |
{
| |
//---
| |
CleanItems("RiskManagement");
| |
| |
//--- Registramos la clase para recibir eventos
| |
// Basicos
| |
if(CBasicEvents::IsActive())
| |
CBasicEvents::Unregister(&this, BASICEVENT_REG_ALL_FLAG); // OnNewDay, Week, Month
| |
| |
// Account status
| |
if(account_status.IsActive())
| |
{
| |
// Para trabajar con las posiciones
| |
account_status.UnregisterEvents(&this,
| |
(ACCOUNT_STATUS_REG_FLAG_ON_OPEN_POSITION |
| |
ACCOUNT_STATUS_REG_FLAG_ON_CLOSE_POSITION |
| |
ACCOUNT_STATUS_REG_FLAG_ON_WITHDRAWAL_DEPOSIT |
| |
ACCOUNT_STATUS_REG_FLAG_ON_NEW_PROFIT |
| |
ACCOUNT_STATUS_REG_FLAG_ON_INIT_NEW_POS)
| |
);
| |
}
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::OnInitNewPos(const ROnOpenPosition &position)
| |
{
| |
if(position.position.magic == this.magic_number || this.magic_number == NOT_MAGIC_NUMBER)
| |
{
| |
m_positions[m_positions_size++] = g_account_open_positions.Count() - 1; // Crece hacia arriba
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function to check if the maximum profit per day was exceeded |
| |
//+------------------------------------------------------------------+
| |
__forceinline bool RiskMNormal_IsSuperatedProfit(const double value, const double saved_value, void* ptr)
| |
{
| |
return (account_status_curr_profit > value);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Boolean function to check if a loss was overcome |
| |
//+------------------------------------------------------------------+
| |
__forceinline bool RiskMNormal_IsSuperatedLoss(const double value, const double saved_value, void* ptr)
| |
{
| |
return (-account_status_curr_profit) > value;
| |
}
| |
| |
//#define MQLARTICLES_RM_MULTI_EA_MODE
| |
// En caso se decida usar este bot en varias cuentas use el define: MQLARTICLES_RM_MULTI_EA_MODE
| |
//+------------------------------------------------------------------+
| |
//| Funciones para obtener el tipo de fucnion a superar |
| |
//+------------------------------------------------------------------+
| |
FuncionLossProfitSuperate CRiskManagemet::SuperateModeToFunctionProfit(ENUM_TYPE_LOSS_PROFIT type) const
| |
{
| |
#ifdef MQLARTICLES_RM_MULTI_EA_MODE
| |
return CRiskManagemetBase::WraperIsSupertedProfit;
| |
#else
| |
return RiskMNormal_IsSuperatedProfit;
| |
#endif
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
// Si es GMLPO empty
| |
FuncionLossProfitSuperate CRiskManagemet::SuperateModeToFunctionLoss(ENUM_TYPE_LOSS_PROFIT type) const
| |
{
| |
#ifdef MQLARTICLES_RM_MULTI_EA_MODE
| |
return type == LP_GMLPO ? (FuncionLossProfitSuperate)LossProfitEmptyFuncionSup : (FuncionLossProfitSuperate)CRiskManagemetBase::WraperIsSupertedLoss;
| |
#else
| |
return type == LP_GMLPO ? (FuncionLossProfitSuperate)LossProfitEmptyFuncionSup : (FuncionLossProfitSuperate)RiskMNormal_IsSuperatedLoss;
| |
#endif
| |
}
| |
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| SetLote function |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::SetLote(CGetLote *lote_ptr)
| |
{
| |
if(!CheckPointer(lote_ptr))
| |
{
| |
LogError("El puntero a CGetlote* es invalido", FUNCION_ACTUAL);
| |
return;
| |
}
| |
| |
//---
| |
if(CheckPointer(get_lote) == POINTER_DYNAMIC) // is not equal to 0 (POINTER_INVALID)
| |
{
| |
//---
| |
RemoveLogger(get_lote);
| |
delete get_lote;
| |
| |
//---
| |
AddLogger(lote_ptr);
| |
this.get_lote = lote_ptr;
| |
}
| |
else //Si es null
| |
{
| |
AddLogger(lote_ptr);
| |
this.get_lote = lote_ptr;
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function that will be executed once all the |
| |
//| Maximum profit and loss have been added |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::EndAddProfitLoss()
| |
{
| |
if(is_init)
| |
return;
| |
LogInfo(StringFormat("The total size between maximum profit and loss is: %d", loss_profits_manager.SizeValids()), FUNCION_ACTUAL);
| |
loss_profits_manager.SetValues();
| |
this.is_init = true;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function to add a maximum loss |
| |
//+------------------------------------------------------------------+
| |
bool CRiskManagemet::AddLoss(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_RISK_CALCULATION_MODE _mode, ENUM_TYPE_LOSS_PROFIT type, bool strict,
| |
bool is_dynamic = false, string percentages_to_activate = NULL, string risks_to_be_applied = NULL)
| |
{
| |
//---
| |
if(_percentage <= 0.00)
| |
{
| |
LogWarning(StringFormat("Invalid percentage %.2f for lost profit %s, will not be added to the main array", _percentage, EnumToString(type)), FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//---
| |
if(_percentage > 100.00 && _mode == percentage)
| |
{
| |
LogWarning(StringFormat("Percentage %.2f for %s exceeds 100%%, limiting to 100%%", _percentage, EnumToString(type)), FUNCION_ACTUAL);
| |
_percentage = 100.00;
| |
}
| |
| |
//---
| |
const int index = int(type);
| |
if(index > 5 || index < 0)
| |
{
| |
LogError(StringFormat("Invalid maximum loss type: %s (index: %d)", EnumToString(type), index), FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
| |
//--- Creamos
| |
CLossProfit* new_loss = NULL;
| |
CRiskManagemetBase* basic_risk = ((CRiskManagemetBase*)&this);
| |
| |
// Por tipo
| |
if(_mode == money)
| |
{
| |
switch(index)
| |
{
| |
case LP_GMLPO:
| |
{
| |
CLossLossGmlpo<CLossProfitMoney<CLossProfit>>* temp = new CLossLossGmlpo<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_MDL:
| |
{
| |
CLossLossMaxDaily<CLossProfitMoney<CLossProfit>>* temp = new CLossLossMaxDaily<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_MWL:
| |
{
| |
CLossLossMaxWeekly<CLossProfitMoney<CLossProfit>>* temp = new CLossLossMaxWeekly<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_MML:
| |
{
| |
CLossLossMaxMon<CLossProfitMoney<CLossProfit>>* temp = new CLossLossMaxMon<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_ML:
| |
{
| |
CLossLossMax<CLossProfitMoney<CLossProfit>>* temp = new CLossLossMax<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_ML_PICO:
| |
{
| |
CLossLossMaxDesdeArriba<CLossProfitMoney<CLossProfit>>* temp = new CLossLossMaxDesdeArriba<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
}
| |
}
| |
else // percentage
| |
{
| |
switch(index)
| |
{
| |
case LP_GMLPO:
| |
{
| |
CLossLossGmlpo<CLossProfitPercentage<CLossProfit>>* temp = new CLossLossGmlpo<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_MDL:
| |
{
| |
CLossLossMaxDaily<CLossProfitPercentage<CLossProfit>>* temp = new CLossLossMaxDaily<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_MWL:
| |
{
| |
CLossLossMaxWeekly<CLossProfitPercentage<CLossProfit>>* temp = new CLossLossMaxWeekly<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_MML:
| |
{
| |
CLossLossMaxMon<CLossProfitPercentage<CLossProfit>>* temp = new CLossLossMaxMon<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_ML:
| |
{
| |
CLossLossMax<CLossProfitPercentage<CLossProfit>>* temp = new CLossLossMax<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
case LP_ML_PICO:
| |
{
| |
CLossLossMaxDesdeArriba<CLossProfitPercentage<CLossProfit>>* temp = new CLossLossMaxDesdeArriba<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, strict, SuperateModeToFunctionLoss(type));
| |
new_loss = temp;
| |
break;
| |
}
| |
}
| |
}
| |
| |
| |
//---
| |
if(!loss_profits_manager.Add(new_loss))
| |
{
| |
delete new_loss;
| |
return false;
| |
}
| |
| |
//---
| |
new_loss.SetPtrSuperated(GetPtrLossProfits());
| |
| |
//---
| |
if(is_dynamic && percentages_to_activate != NULL && risks_to_be_applied != NULL)
| |
{
| |
if(!isCachedModifier[index])
| |
{
| |
new_loss.SetDynamic(percentages_to_activate, risks_to_be_applied, this.chosen_balance);
| |
LogInfo(StringFormat("Dynamic maximum loss %s successfully configured", EnumToString(type)), FUNCION_ACTUAL);
| |
}
| |
else
| |
{
| |
LogError(StringFormat("Maximum loss %s already has an active modifier", EnumToString(type)), FUNCION_ACTUAL);
| |
}
| |
}
| |
else
| |
{
| |
LogInfo(StringFormat("Maximum loss %s added: %.2f%s", EnumToString(type), _percentage, (_mode == money ? "money" : "%")), FUNCION_ACTUAL);
| |
}
| |
return true;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function to add a maximum gain |
| |
//+------------------------------------------------------------------+
| |
bool CRiskManagemet::AddProfit(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_RISK_CALCULATION_MODE _mode, ENUM_TYPE_LOSS_PROFIT type, bool is_strict_,
| |
bool is_dynamic = false, string percentages_to_activate = NULL, string risks_to_be_applied = NULL)
| |
{
| |
//---
| |
if(_percentage <= 0.00)
| |
{
| |
LogWarning(StringFormat("Invalid percentage %.2f for maximum gain %s, will not be added to the main array", _percentage, EnumToString(type)), FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//---
| |
if(_percentage > 100.00 && _mode == percentage)
| |
{
| |
LogWarning(StringFormat("Percentage %.2f for %s exceeds 100%%, limiting to 100%%", _percentage, EnumToString(type)), FUNCION_ACTUAL);
| |
_percentage = 100.00;
| |
}
| |
| |
//---
| |
const int index = int(type);
| |
if(index < 6 || index > 10) // Profits: LP_MDP=6 a LP_MP_BAJO=10
| |
{
| |
LogError(StringFormat("Invalid maximum gain type: %s (index: %d)", EnumToString(type), index), FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//--- Creamos
| |
CLossProfit* new_profit = NULL;
| |
CRiskManagemetBase* basic_risk = ((CRiskManagemetBase*)&this);
| |
| |
// Ajustar índice para el switch (restar 6 para que LP_MDP=0, LP_MWP=1, etc.)
| |
const int switch_index = index - 6;
| |
| |
// Por tipo
| |
if(_mode == money)
| |
{
| |
switch(switch_index)
| |
{
| |
case 0: // LP_MDP
| |
{
| |
CLossProfitMaxDaily<CLossProfitMoney<CLossProfit>>* temp = new CLossProfitMaxDaily<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 1: // LP_MWP
| |
{
| |
CLossProfitMaxWeekly<CLossProfitMoney<CLossProfit>>* temp = new CLossProfitMaxWeekly<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 2: // LP_MMP
| |
{
| |
CLossProfitMaxMon<CLossProfitMoney<CLossProfit>>* temp = new CLossProfitMaxMon<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 3: // LP_MP
| |
{
| |
CLossProfitMax<CLossProfitMoney<CLossProfit>>* temp = new CLossProfitMax<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 4: // LP_MP_BAJO
| |
{
| |
CLossProfitMaxDesdeBaajo<CLossProfitMoney<CLossProfit>>* temp = new CLossProfitMaxDesdeBaajo<CLossProfitMoney<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
}
| |
}
| |
else // percentage
| |
{
| |
switch(switch_index)
| |
{
| |
case 0: // LP_MDP
| |
{
| |
CLossProfitMaxDaily<CLossProfitPercentage<CLossProfit>>* temp = new CLossProfitMaxDaily<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 1: // LP_MWP
| |
{
| |
CLossProfitMaxWeekly<CLossProfitPercentage<CLossProfit>>* temp = new CLossProfitMaxWeekly<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 2: // LP_MMP
| |
{
| |
CLossProfitMaxMon<CLossProfitPercentage<CLossProfit>>* temp = new CLossProfitMaxMon<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 3: // LP_MP
| |
{
| |
CLossProfitMax<CLossProfitPercentage<CLossProfit>>* temp = new CLossProfitMax<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
case 4: // LP_MP_BAJO
| |
{
| |
CLossProfitMaxDesdeBaajo<CLossProfitPercentage<CLossProfit>>* temp = new CLossProfitMaxDesdeBaajo<CLossProfitPercentage<CLossProfit>>(false, basic_risk);
| |
temp.Init(_percentage, _applied, is_strict_, SuperateModeToFunctionProfit(type));
| |
new_profit = temp;
| |
break;
| |
}
| |
}
| |
}
| |
| |
//---
| |
if(!loss_profits_manager.Add(new_profit))
| |
{
| |
delete new_profit;
| |
return false;
| |
}
| |
| |
//---
| |
new_profit.SetPtrSuperated(GetPtrLossProfits());
| |
| |
//---
| |
if(is_dynamic && percentages_to_activate != NULL && risks_to_be_applied != NULL)
| |
{
| |
if(!isCachedModifier[index])
| |
{
| |
new_profit.SetDynamic(percentages_to_activate, risks_to_be_applied, this.chosen_balance);
| |
LogInfo(StringFormat("Maximum dynamic gain %s successfully set", EnumToString(type)), FUNCION_ACTUAL);
| |
}
| |
else
| |
{
| |
LogError(StringFormat("Maximum gain %s already has an active modifier", EnumToString(type)), FUNCION_ACTUAL);
| |
}
| |
}
| |
else
| |
{
| |
LogInfo(StringFormat("Maximum gain %s added: %.2f%s", EnumToString(type), _percentage, (_mode == money ? "money" : "%")), FUNCION_ACTUAL);
| |
}
| |
| |
return true;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function to add a risk modifier |
| |
//+------------------------------------------------------------------+
| |
bool CRiskManagemet::AddModificator(CExtraModifications *modificator)
| |
{
| |
//--- Check pointer
| |
if(!CheckPointer(modificator))
| |
{
| |
LogError("The risk modifier is null-invalid", FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//--- Property to be modified is invalid ?
| |
const int loss_or_profit = modificator.MaximumProfitOrLossAModify();
| |
if(loss_or_profit == WRONG_VALUE)
| |
{
| |
LogError("The risk modifier does not modify any risk.", FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//--- Property to modify is "empty" ?
| |
if(loss_profits_manager[loss_or_profit].IsEmpty())
| |
{
| |
LogError(StringFormat("The property to be modified %d is not defined", loss_or_profit), FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//--- Is the loss_or_profit already dynamic ?
| |
if(loss_profits_manager[loss_or_profit].IsDynamicMode())
| |
{
| |
LogError(StringFormat("The property to be modified %d is already dynamic", loss_or_profit), FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//---
| |
const int index = int(loss_or_profit);
| |
| |
if(isCachedModifier[index])
| |
{
| |
LogWarning(StringFormat("The property to be modified %d is already being modified", loss_or_profit), FUNCION_ACTUAL);
| |
return false;
| |
}
| |
| |
//---
| |
modificator.SetPointer(loss_profits_manager[loss_or_profit]);
| |
ModfierInitInfo init;
| |
init.balance = this.chosen_balance;
| |
init.magic = this.magic_number;
| |
modificator.OnInitModifier(init);
| |
| |
LogCaution(StringFormat("The modifier '%s' is being added\nThis will modify the property '%s'", modificator.Name(), loss_profits_manager[loss_or_profit].Name()), FUNCION_ACTUAL);
| |
| |
//--- Add
| |
m_hooks.Add(modificator); // We use the fast version (we already did all the checkpointer checks etc.)
| |
| |
//---
| |
isCachedModifier[index] = true;
| |
return true;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
bool CRiskManagemet::AddRmHook(IRiskManagementHook *hook)
| |
{
| |
//--- Check pointer
| |
if(!CheckPointer(hook))
| |
{
| |
LogError("The RM Hook is null-invalid", FUNCION_ACTUAL);
| |
return false;
| |
}
| |
//--- Add
| |
m_hooks.Add(hook); // We use the fast version (we already did all the checkpointer checks etc.)
| |
//---
| |
return true;
| |
}
| |
| |
| |
//+----------------------------------------------------------------------------------+
| |
//| Get the ideal stop loss based on a specified lot and the maximum loss per trade |
| |
//+----------------------------------------------------------------------------------+
| |
long CRiskManagemet::GetSL(ENUM_ORDER_TYPE type, double entry_price, ulong deviation, ulong stop_limit)
| |
{
| |
if(loss_profits_manager[LP_GMLPO].IsEmpty())
| |
{
| |
LogCriticalError("GMLPO not configured: Stop Loss cannot be calculated", FUNCION_ACTUAL);
| |
Remover();
| |
return 0;
| |
}
| |
| |
double lot;
| |
long sl = get_lote.MoneyToPoints(type, loss_profits_manager[LP_GMLPO].GetValue(), entry_price, lot, deviation, stop_limit);
| |
//If there is an error or the SL is invalid, it is printed in CGetLote
| |
return sl;
| |
}
| |
| |
//+-----------------------------------------------------------------------------------------------+
| |
//| Function to obtain the ideal lot based on the maximum loss per operation and the stop loss |
| |
//+-----------------------------------------------------------------------------------------------+
| |
double CRiskManagemet::GetLote(ENUM_ORDER_TYPE type, double entry_price, ulong deviation, ulong stop_limit)
| |
{
| |
if(loss_profits_manager[LP_GMLPO].IsEmpty())
| |
{
| |
LogCriticalError("GMLPO not configured: unable to calculate lot size", FUNCION_ACTUAL);
| |
Remover();
| |
this.lote = 0.00;
| |
return this.lote;
| |
}
| |
if(this.type_get_lot == GET_LOT_BY_STOPLOSS_AND_RISK_PER_OPERATION)
| |
{
| |
double MaxLote = get_lote.GetMaxLote(type, entry_price, deviation, stop_limit); // We do not check max batch data that is done in GetLote... of CGetLote
| |
this.lote = get_lote.GetLoteByRiskPerOperationAndSL(MaxLote, loss_profits_manager[LP_GMLPO].GetValue(), this.nmlpo, this.StopLoss);
| |
}
| |
else
| |
this.lote = get_lote.GetLoteByRiskPerOperation(type, loss_profits_manager[LP_GMLPO].GetValue(), entry_price, deviation, stop_limit); // If it is less than the minimum batch, a message is printed in CGetLote
| |
| |
return this.lote;
| |
}
| |
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| Function to update profits |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::UpdateProfit(const double profit, const double acc_total_profit)
| |
{
| |
//--- Update profits
| |
this.monthly_profit += profit;
| |
this.daily_profit += profit;
| |
this.weekly_profit += profit;
| |
this.gross_profit += profit;
| |
| |
//---
| |
if(IsInfoLogEnabled())
| |
{
| |
FastLog(FUNCION_ACTUAL, INFO_TEXT, "New profits:");
| |
Print("Daily Profit: ", this.daily_profit);
| |
Print("Gross profit: ", this.gross_profit);
| |
Print("Weekly Profit: ", this.weekly_profit);
| |
Print("Monthly Profit: ", this.monthly_profit);
| |
}
| |
| |
//---
| |
this.account_profit = acc_total_profit; // Set Account total profit
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Initial profit update |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::OnNewProfit(const RAccountProfit & profit, const datetime curr_time)
| |
{
| |
//---Date
| |
this.last_day_time = account_status.last_day_time;
| |
this.last_weekly_time = account_status.last_weekly_time;
| |
this.last_monthly_time = account_status.last_monthly_time;
| |
this.init_trade_time = this.magic_number != NOT_MAGIC_NUMBER ? curr_time : D'1972.01.01 00:00';
| |
| |
//--- Set internal profits
| |
this.account_profit = GetNetProfitSince(true, this.magic_number, D'1972.01.01 00:00');
| |
this.daily_profit = GetNetProfitSince((this.magic_number == NOT_MAGIC_NUMBER ? true : false), this.magic_number, this.last_day_time);
| |
this.weekly_profit = GetNetProfitSince((this.magic_number == NOT_MAGIC_NUMBER ? true : false), this.magic_number, this.last_weekly_time);
| |
this.gross_profit = GetNetProfitSince((this.magic_number == NOT_MAGIC_NUMBER ? true : false), this.magic_number, this.init_trade_time);
| |
this.monthly_profit = GetNetProfitSince((this.magic_number == NOT_MAGIC_NUMBER ? true : false), this.magic_number, this.last_monthly_time);
| |
| |
//--- Info
| |
if(IsInfoLogEnabled())
| |
{
| |
FastLog(FUNCION_ACTUAL, INFO_TEXT, "New profits:");
| |
Print("Daily Profit: ", this.daily_profit);
| |
Print("Gross profit: ", this.gross_profit);
| |
Print("Weekly Profit: ", this.weekly_profit);
| |
Print("Monthly Profit: ", this.monthly_profit);
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| OnTradeTransaction Event |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::OnOpenPosition(const ROnOpenPosition &pos)
| |
{
| |
if(this.magic_number == pos.position.magic || this.magic_number == NOT_MAGIC_NUMBER)
| |
{
| |
LogInfo(StringFormat("Position %I64u added to internal tickets", pos.position.ticket), FUNCION_ACTUAL);
| |
| |
//--- Activate the flag
| |
this.positions_open = true;
| |
| |
//--- Execute the virtual function
| |
OnOpenTrade();
| |
| |
//--- If there are modifiers then execute the OnOpenPosition function
| |
if(m_hooks.SizeOnOpenPosition() > 0)
| |
{
| |
static ModifierOnOpenCloseStruct new_mod;
| |
| |
// Position
| |
new_mod.position = pos.position;
| |
| |
// Profits
| |
new_mod.profit_diario = this.daily_profit;
| |
new_mod.profit_mensual = this.monthly_profit;
| |
new_mod.profit_semanal = this.weekly_profit;
| |
new_mod.profit_total = this.gross_profit;
| |
| |
// Deal
| |
new_mod.deal_profit = pos.deal_profit;
| |
new_mod.deal_ticket = pos.deal_ticket;
| |
new_mod.deal_entry_type = pos.deal_entry_type;
| |
new_mod.deal_reason = pos.deal_reason;
| |
m_hooks.OnOpenPosition(new_mod);
| |
}
| |
| |
//--- Add the operation to positions opened by the Magic
| |
m_positions[m_positions_size++] = (int)g_account_open_positions.m_last_created_pos; // Crece hacia arriba
| |
return;
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::OnClosePosition(const ROnClosePosition &pos, const int global_pos_index)
| |
{
| |
//---
| |
if(TryRemoveFromArrayOfPos(global_pos_index))
| |
{
| |
//--- Logs
| |
LogCaution(StringFormat("Position with ticket %I64u has been closed", pos.position.ticket), FUNCION_ACTUAL);
| |
LogInfo(StringFormat("Total number of positions for magic number %u is: %d", this.magic_number, m_positions_size), FUNCION_ACTUAL);
| |
| |
//--- Update internal profits
| |
UpdateProfit(pos.position.profit, pos.account_profit_total);
| |
| |
//--- Update risks (dynamic)
| |
loss_profits_manager.CheckDynamic();
| |
| |
//--- If there are no more positions, deactivate the flag
| |
if(m_positions_size == 0)
| |
this.positions_open = false;
| |
| |
//--- Execute the function that runs every time a position closes
| |
OnCloseTrade();
| |
| |
//--- If there are modifiers, execute OnOpenClosePosition
| |
if(m_hooks.SizeOnClosePosition() > 0)
| |
{
| |
static ModifierOnOpenCloseStruct new_mod;
| |
| |
// Profit
| |
new_mod.profit_diario = this.daily_profit;
| |
new_mod.profit_mensual = this.monthly_profit;
| |
new_mod.profit_semanal = this.weekly_profit;
| |
new_mod.profit_total = this.gross_profit;
| |
| |
// Position
| |
new_mod.position = pos.position;
| |
| |
// Deal
| |
new_mod.deal_profit = pos.deal_profit;
| |
new_mod.deal_ticket = pos.deal_ticket;
| |
new_mod.deal_entry_type = pos.deal_entry_type;
| |
new_mod.deal_reason = pos.deal_reason;
| |
m_hooks.OnClosePosition(new_mod);
| |
}
| |
| |
//--- Set the new GMLPO value
| |
loss_profits_manager[LP_GMLPO].Set(); // Empty check is done internally
| |
}
| |
else // In case a position closes but it's not from the current bot, we need to update profits (Possibly it was closed by the trader or another bot)
| |
{
| |
//--- Udpate profit
| |
UpdateProfit(pos.position.profit, pos.account_profit_total);
| |
| |
//--- Set GMLPO
| |
loss_profits_manager[LP_GMLPO].Set(); // Empty check is done internally
| |
}
| |
// Partials are not necessary since we did that to ensure trans.position profit also counts the partial close, the other class already does that.
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function that runs every new day |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::OnNewDay(const datetime curr_time)
| |
{
| |
this.daily_profit = 0.00;
| |
this.last_day_time = curr_time;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function that runs every new week |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::OnNewWeek(const datetime curr_time)
| |
{
| |
this.last_weekly_time = curr_time;
| |
this.weekly_profit = 0.00;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Function that runs every new month |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemet::OnNewMonth(const datetime curr_time)
| |
{
| |
this.last_monthly_time = curr_time;
| |
this.monthly_profit = 0.00;
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| Function to obtain the value of a loss or gain based |
| |
//| on the applied value (balance, free margin, equity, net profit) |
| |
//+------------------------------------------------------------------+
| |
double CRiskManagemet::GetValorWithApplied(double percentage_, int type, ENUM_APPLIED_PERCENTAGES applied) const
| |
{
| |
switch(applied)
| |
{
| |
case Balance:
| |
return ((percentage_ * 0.01) * AccountInfoDouble(ACCOUNT_BALANCE));
| |
case ganancianeta:
| |
{
| |
if(this.account_profit <= 0.0000001)
| |
{
| |
LogError(StringFormat("The total profit of the account which is %+.2f is invalid or negative", this.account_profit), FUNCION_ACTUAL);
| |
return 0;
| |
}
| |
else
| |
return ((percentage_ * 0.01) * this.account_profit);
| |
}
| |
case free_margin:
| |
{
| |
if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) <= 0.00000000001)
| |
{
| |
LogError(StringFormat("Free margin of %+.2f is invalid", AccountInfoDouble(ACCOUNT_MARGIN_FREE)), FUNCION_ACTUAL);
| |
return 0;
| |
}
| |
else
| |
return ((percentage_ * 0.01) * AccountInfoDouble(ACCOUNT_MARGIN_FREE));
| |
}
| |
case equity:
| |
return ((percentage_ * 0.01) * AccountInfoDouble(ACCOUNT_EQUITY));
| |
default:
| |
LogFatalError(StringFormat("It was not found that: %s be part of the allowed enumeration", EnumToString(applied)), FUNCION_ACTUAL);
| |
}
| |
//---
| |
return 0.00;
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
//--- Define dangerous, if disabled it could increase the risk strongly, for safety reasons do not comment on it
| |
#define RISK_MANAGEMENT_UPDATE_CHOSEN_BALANCE_DEPOSIT_WITDRAWAL
| |
| |
//---
| |
void CRiskManagemet::OnWithdrawalDeposit(const double value) override
| |
{
| |
// Function that is executed every time a device or profit occurs
| |
//--- Uodate
| |
#ifdef RISK_MANAGEMENT_UPDATE_CHOSEN_BALANCE_DEPOSIT_WITDRAWAL
| |
this.chosen_balance += value;
| |
loss_profits_manager.SetNewChossenBalanceForDynamicsAndSet(chosen_balance, true);
| |
#else
| |
loss_profits_manager.SetValuesAndDynamic();
| |
#endif
| |
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Clase de gestion de riesgo normal |
| |
//+------------------------------------------------------------------+
| |
class CRiskManagemetPersonal : public CRiskManagemet
| |
{
| |
public:
| |
CRiskManagemetPersonal(ulong _magic, ENUM_GET_LOT _get)
| |
: CRiskManagemet(_magic, _get) { }
| |
| |
inline ENUM_MODE_RISK_MANAGEMENT ModeRiskManagement() const override final { return risk_mode_personal_account; }
| |
void SetGeneralParameters(MqlParam ¶ms[]) override { } // No extra parameters required
| |
};
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| Clase de gestion de riesgo para propfirms que usen riesgo |
| |
//| Diario dinamico |
| |
//+------------------------------------------------------------------+
| |
//---
| |
class CRiskManagemetPropFirm : public CRiskManagemet
| |
{
| |
private:
| |
double account_balance_propfirm; // Balance incial del challenge
| |
| |
//---
| |
double GetValorWithApplied(double percentage_, int type, ENUM_APPLIED_PERCENTAGES applied) const override;
| |
FuncionLossProfitSuperate SuperateModeToFunctionLoss(ENUM_TYPE_LOSS_PROFIT type) const override;
| |
| |
public:
| |
CRiskManagemetPropFirm(ulong _magic, ENUM_GET_LOT type_get_lot_)
| |
: CRiskManagemet(_magic, type_get_lot_) { }
| |
| |
| |
//--- General
| |
void SetGeneralParameters(MqlParam ¶ms[]) override;
| |
__forceinline double GetAccountBalancePropFirm() const { return account_balance_propfirm; }
| |
| |
| |
//---
| |
inline ENUM_MODE_RISK_MANAGEMENT ModeRiskManagement() const override final { return risk_mode_propfirm_dynamic_daiy_loss; }
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
inline bool RiskMPropFirmFN_FTMO_IsSuperatedLoss(const double value, const double saved_value, void* ptr)
| |
{
| |
return AccountInfoDouble(ACCOUNT_EQUITY) < (((CRiskManagemetPropFirm*)ptr).GetAccountBalancePropFirm() - saved_value);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
FuncionLossProfitSuperate CRiskManagemetPropFirm::SuperateModeToFunctionLoss(ENUM_TYPE_LOSS_PROFIT type) const
| |
{
| |
if(type == LP_ML)
| |
return RiskMPropFirmFN_FTMO_IsSuperatedLoss;
| |
| |
return CRiskManagemet::SuperateModeToFunctionLoss(type);
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
void CRiskManagemetPropFirm::SetGeneralParameters(MqlParam & params[]) override
| |
{
| |
account_balance_propfirm = params[0].double_value;
| |
this.chosen_balance = account_balance_propfirm;
| |
}
| |
//+------------------------------------------------------------------+
| |
double CRiskManagemetPropFirm::GetValorWithApplied(double percentage_, int type, ENUM_APPLIED_PERCENTAGES applied) const override
| |
{
| |
if(type == LP_ML || type == LP_MDL)
| |
return account_balance_propfirm * (percentage_ * 0.01);
| |
| |
return CRiskManagemet::GetValorWithApplied(percentage_, type, applied);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Clase manager para poder obtener un puntero |
| |
//| En base al tipo de gestion de riesgo |
| |
//+------------------------------------------------------------------+
| |
class CRiskPointer
| |
{
| |
private:
| |
RiskParams parametros[];
| |
ulong magic;
| |
ENUM_GET_LOT type_get_lot;
| |
| |
public:
| |
CRiskPointer(ulong _magic, ENUM_GET_LOT _Get);
| |
void SetPropirm(double account_balance_propfirm);
| |
CRiskManagemet* GetRiskPointer(ENUM_MODE_RISK_MANAGEMENT mode);
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| Obtener el puntero de CRiskManagement |
| |
//+------------------------------------------------------------------+
| |
CRiskManagemet* CRiskPointer::GetRiskPointer(ENUM_MODE_RISK_MANAGEMENT mode)
| |
{
| |
CRiskManagemet *new_risk = NULL;
| |
| |
//---
| |
switch(mode)
| |
{
| |
//---
| |
case risk_mode_propfirm_dynamic_daiy_loss:
| |
{
| |
new_risk = new CRiskManagemetPropFirm(this.magic, this.type_get_lot);
| |
| |
if(ArraySize(parametros[1].params) < 1)
| |
{
| |
Print(FUNCION_ACTUAL, ": Critical error | The parameter array for prop firm mode has not been populated.");
| |
Remover();
| |
break;
| |
}
| |
| |
new_risk.SetGeneralParameters(parametros[1].params);
| |
break;
| |
}
| |
| |
//---
| |
case risk_mode_personal_account:
| |
{
| |
new_risk = new CRiskManagemetPersonal(this.magic, this.type_get_lot);
| |
break;
| |
}
| |
| |
//---
| |
default:
| |
Print(FUNCION_ACTUAL, ": Critical error | The type: ", EnumToString(mode), " It is invalid");
| |
break;
| |
}
| |
| |
//---
| |
if(CheckPointer(new_risk) == POINTER_INVALID)
| |
{
| |
Print(FUNCION_ACTUAL, ": Critical error | The pointer to CRiskManagement* is invalid");
| |
return NULL;
| |
}
| |
| |
//---
| |
return new_risk;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Constructor |
| |
//+------------------------------------------------------------------+
| |
CRiskPointer::CRiskPointer(ulong _magic, ENUM_GET_LOT _Get)
| |
{
| |
this.magic = _magic;
| |
this.type_get_lot = _Get;
| |
| |
ArrayResize(parametros, 2);
| |
| |
parametros[0].mode = risk_mode_personal_account;
| |
parametros[1].mode = risk_mode_propfirm_dynamic_daiy_loss;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Para setear el modo de gestion de riesgo propfirm |
| |
//+------------------------------------------------------------------+
| |
void CRiskPointer::SetPropirm(double account_balance_propfirm)
| |
{
| |
ArrayFree(parametros[1].params);
| |
ArrayResize(parametros[1].params, 2);
| |
parametros[1].params[0].double_value = account_balance_propfirm;
| |
}
| |
//+------------------------------------------------------------------+
| |
#endif // MQLARTICLES_RM_RISKMANAGEMENT_MQH
| |
//+------------------------------------------------------------------+
| |
| |
//+------------------------------------------------------------------+
|