MQLArticles/RM/RiskManagement.mqh

968 lines
73 KiB
MQL5

2025-09-22 09:09:20 -05:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| RiskManagement.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372/news |
//+------------------------------------------------------------------+
2025-11-10 09:33:30 -05:00
#property copyright "Copyright 2025, Niquel Mendoza."
2025-09-22 09:09:20 -05:00
2025-12-21 12:41:35 -05:00
#property link "https://www.mql5.com/es/users/nique_372/news"
2025-09-22 09:09:20 -05:00
#property strict
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
#ifndef MQLARTICLES_RM_RISKMANAGEMENT_MQH
#define MQLARTICLES_RM_RISKMANAGEMENT_MQH
#include "RM_Hooks.mqh"
/*
ADVERTENCIA al momeneto de a<EFBFBD>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.
*/
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//open_positions
2025-09-24 14:00:58 -05:00
//+-----------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
//| Clase Base CRiskManagement |
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
class CRiskManagemet : public CRiskManagemetBase
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
protected:
2025-09-22 09:09:20 -05:00
//---
2025-09-24 14:00:58 -05:00
2025-11-26 07:03:20 -05:00
CGetLote* get_lote;
2025-09-22 09:09:20 -05:00
//---
2025-11-26 07:03:20 -05:00
double chosen_balance;
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//--- Extra Variables
ENUM_GET_LOT type_get_lot;
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//-- main variables
long StopLoss; //StopLoss
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
double lote; //Last recorded lot
//--- variables to store the values of the maximum losses
2025-11-26 07:03:20 -05:00
double nmlpo; //last expected loss
2025-11-26 07:03:20 -05:00
bool is_init; //flag indicating if it is init
2025-09-22 09:09:20 -05:00
2025-12-21 12:41:35 -05:00
//--- variables that store percentages and enumeration, which will be used for the subsequent calculation of losses
CLossProfitManager* loss_profits_manager;
2026-01-07 11:00:48 -05:00
//--- Modifiers
2025-12-21 12:41:35 -05:00
CRiskManagemeHookManager* m_hooks;
2025-11-26 07:03:20 -05:00
2025-09-24 14:00:58 -05:00
bool isCachedModifier[LOSS_PROFIT_COUNT];
2025-12-21 12:41:35 -05:00
2025-11-26 07:03:20 -05:00
//--- general function to assign values to loss variables
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
virtual double GetValorWithApplied(double percentage_, ENUM_TYPE_LOSS_PROFIT type, ENUM_APPLIED_PERCENTAGES applied) const override;
2025-09-22 09:09:20 -05:00
2026-01-02 10:22:09 -05:00
//--- Update profits function
2025-09-22 09:09:20 -05:00
void UpdateProfit(const double &profit, const double& acc_total_profit);
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
virtual void OnOpenTrade() { }
virtual void OnCloseTrade() { }
//---
virtual FuncionLossProfitSuperate SuperateModeToFunctionProfit(ENUM_TYPE_LOSS_PROFIT type) const;
virtual FuncionLossProfitSuperate SuperateModeToFunctionLoss(ENUM_TYPE_LOSS_PROFIT type) const;
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//---
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
virtual void* GetPtrLossProfits() { return &this; }
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
public:
2025-11-26 07:03:20 -05:00
//--- Constructor and Destructor
2025-09-22 09:09:20 -05:00
CRiskManagemet(ulong _magic, ENUM_GET_LOT type_get_lot_);
~CRiskManagemet();
2025-09-22 09:09:20 -05:00
//--- Set
void EndAddProfitLoss();
virtual void SetGeneralParameters(MqlParam &params[]) = 0;
2025-12-21 12:41:35 -05:00
void SetLote(CGetLote* lote_ptr);
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
inline void SetStopLoss(double dist_open_sl) { this.StopLoss = (long)ConvertPriceToPoints(_Symbol, dist_open_sl); }
2025-09-22 09:09:20 -05:00
2025-12-21 12:41:35 -05:00
inline void SetStopLoss(long _sl_point_) { this.StopLoss = _sl_point_; }
2025-09-22 09:09:20 -05:00
//--- 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
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
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); }
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
// Loss
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
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
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
// Profit
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
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
2025-11-26 07:03:20 -05:00
//--- Functions inherited from CAccountGestor
2025-11-26 07:03:20 -05:00
void OnNewProfit(const ROnOpenClosePosition &profit) override;
virtual void OnOpenClosePosition(const ROnOpenClosePosition &pos) override;
2025-11-26 07:03:20 -05:00
void OnNewDay(const datetime& init_time, const datetime& curr_time) override;
2025-11-26 07:03:20 -05:00
void OnNewWeek(const datetime& init_time, const datetime& curr_time) override;
2025-11-26 07:03:20 -05:00
void OnNewMonth(const datetime& init_time, const datetime& curr_time) override;
2025-09-22 09:09:20 -05:00
void OnWithdrawalDeposit(double value) override;
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
void OnLossProfit(const double& p) override;
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//--- Get the lot using GMPLO and type_get_lot
double GetLote(ENUM_ORDER_TYPE type, double entry_price, ulong deviation, ulong stop_limit);
2025-09-24 14:00:58 -05:00
//--- Obtain the SL by risk per operation
2025-09-22 09:09:20 -05:00
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; }
//--- Magic number
inline ulong MagicNumber() const { return this.magic_number; }
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//--- Risk management type
virtual inline ENUM_MODE_RISK_MANAGEMENT ModeRiskManagement() const = 0;
};
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//| Constructor |
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
CRiskManagemet::CRiskManagemet(ulong _magic, ENUM_GET_LOT type_get_lot_)
2025-09-24 14:00:58 -05:00
2025-11-26 07:03:20 -05:00
: CRiskManagemetBase(_magic)
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//---
2025-09-22 09:09:20 -05:00
this.chosen_balance = AccountInfoDouble(ACCOUNT_BALANCE);
2025-09-24 14:00:58 -05:00
for(int i = 0 ; i < LOSS_PROFIT_COUNT; i++)
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
isCachedModifier[i] = false;
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
}
2025-11-26 07:03:20 -05:00
//---
this.type_get_lot = type_get_lot_;
2025-09-22 09:09:20 -05:00
loss_profits_manager = new CLossProfitManager();
2025-11-26 07:03:20 -05:00
m_hooks = new CRiskManagemeHookManager();
2025-11-26 07:03:20 -05:00
//---
AddLogger(loss_profits_manager);
2025-09-22 09:09:20 -05:00
AddLogger(m_hooks);
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//---
2025-09-24 14:00:58 -05:00
for(int i = PositionsTotal() - 1; i >= 0; i--)
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
ulong position_ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(position_ticket))
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
continue;
2025-09-24 14:00:58 -05:00
ulong position_magic = PositionGetInteger(POSITION_MAGIC);
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
if(position_magic == _magic || _magic == NOT_MAGIC_NUMBER)
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
{
2025-09-22 09:09:20 -05:00
Position new_pos;
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
new_pos.type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
2025-09-24 14:00:58 -05:00
new_pos.ticket = position_ticket;
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
new_pos.profit = GetTotalPositionProfitNoCurrent(new_pos.ticket);
2025-09-24 14:00:58 -05:00
new_pos.magic = _magic;
2025-09-22 09:09:20 -05:00
AddArrayNoVerification2(open_positions, new_pos, RISK_MANAGEMENT_RESERVE_POS)
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
}
}
2025-09-24 14:00:58 -05:00
}
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//| Destructor |
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
CRiskManagemet::~CRiskManagemet()
{
2025-09-22 09:09:20 -05:00
CleanItems("RiskManagement");
2025-11-26 07:03:20 -05:00
}
2025-11-26 07:03:20 -05:00
//+------------------------------------------------------------------+
//| Function to check if the maximum profit per day was exceeded |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-11-26 07:03:20 -05:00
__forceinline bool RiskMNormal_IsSuperatedProfit(const double& value, const double& saved_value, void* ptr)
{
2025-09-22 09:09:20 -05:00
return (account_status_curr_profit > value);
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| Boolean function to check if a loss was overcome |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
__forceinline bool RiskMNormal_IsSuperatedLoss(const double& value, const double& saved_value, void* ptr)
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
{
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
return (-account_status_curr_profit) > value;
}
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
//| |
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
FuncionLossProfitSuperate CRiskManagemet::SuperateModeToFunctionProfit(ENUM_TYPE_LOSS_PROFIT type) const
2025-09-24 14:00:58 -05:00
{
return RiskMNormal_IsSuperatedProfit;
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
}
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
FuncionLossProfitSuperate CRiskManagemet::SuperateModeToFunctionLoss(ENUM_TYPE_LOSS_PROFIT type) const
2025-09-24 14:00:58 -05:00
2025-12-21 12:41:35 -05:00
{
2025-09-22 09:09:20 -05:00
return RiskMNormal_IsSuperatedLoss;
2025-09-24 14:00:58 -05:00
}
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//| SetLote function |
2025-09-24 14:00:58 -05:00
2025-12-21 12:41:35 -05:00
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
void CRiskManagemet::SetLote(CGetLote *lote_ptr)
2025-09-24 14:00:58 -05:00
{
2025-09-22 09:09:20 -05:00
if(CheckPointer(lote_ptr) == POINTER_INVALID)
{
2025-09-24 14:00:58 -05:00
LogError("El puntero a CGetlote* es invalido", FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
return;
2025-12-21 12:41:35 -05:00
2025-09-24 14:00:58 -05:00
}
2025-09-22 09:09:20 -05:00
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
//---
if(CheckPointer(get_lote)) // is not equal to 0 (POINTER_INVALID)
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
{
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
if(CheckPointer(get_lote) == POINTER_DYNAMIC)
2025-12-21 12:41:35 -05:00
delete get_lote;
RemoveLogger(get_lote);
AddLogger(lote_ptr);
this.get_lote = lote_ptr;
2025-09-22 09:09:20 -05:00
return;
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
}
else //Si es null
{
AddLogger(lote_ptr);
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
this.get_lote = lote_ptr;
}
}
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
//| Function that will be executed once all the |
//| Maximum profit and loss have been added |
//+------------------------------------------------------------------+
void CRiskManagemet::EndAddProfitLoss()
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
{
if(is_init)
return;
2025-09-24 14:00:58 -05:00
LogInfo(StringFormat("The total size between maximum profit and loss is: %d", loss_profits_manager.SizeValids()), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
loss_profits_manager.SetValues();
2025-09-24 14:00:58 -05:00
this.is_init = true;
2025-09-22 09:09:20 -05:00
}
//+------------------------------------------------------------------+
//| Function to add a maximum loss |
2025-12-21 12:41:35 -05:00
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
bool CRiskManagemet::AddLoss(double _percentage, ENUM_APPLIED_PERCENTAGES _applied, ENUM_RISK_CALCULATION_MODE _mode, ENUM_TYPE_LOSS_PROFIT type, bool strict,
2025-11-26 07:03:20 -05:00
bool is_dynamic = false, string percentages_to_activate = NULL, string risks_to_be_applied = NULL)
{
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
//---
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);
2025-09-22 09:09:20 -05:00
return false;
}
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
//---
2025-12-21 12:41:35 -05:00
if(_percentage > 100.00 && _mode == percentage)
2025-11-26 07:03:20 -05:00
{
2025-09-22 09:09:20 -05:00
LogWarning(StringFormat("Percentage %.2f for %s exceeds 100%%, limiting to 100%%", _percentage, EnumToString(type)), FUNCION_ACTUAL);
2025-11-26 07:03:20 -05:00
_percentage = 100.00;
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
}
2025-09-22 09:09:20 -05:00
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
//---
2025-09-22 09:09:20 -05:00
const int index = int(type);
if(index < 3)
2025-09-24 14:00:58 -05:00
{
2025-09-22 09:09:20 -05:00
LogError(StringFormat("Invalid maximum loss type: %s (index: %d)", EnumToString(type), index), FUNCION_ACTUAL);
return false;
}
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
//--- Creamos
CLossProfit* new_loss = NULL;
if(_mode == money)
new_loss = new CLossProfitMoney(false, dynamic_cast<CRiskManagemetBase*>(&this));
else
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
new_loss = new CLossProfitPercentage(false, dynamic_cast<CRiskManagemetBase*>(&this));
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//---
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
new_loss.SetProperties(_percentage, _applied, type, SuperateModeToFunctionLoss(type), strict);
2025-09-22 09:09:20 -05:00
//---
2025-09-22 09:09:20 -05:00
if(!loss_profits_manager.Add(new_loss))
2025-12-21 12:41:35 -05:00
{
2025-09-22 09:09:20 -05:00
delete new_loss;
return false;
2025-09-22 09:09:20 -05:00
}
//---
new_loss.SetPtrSuperated(GetPtrLossProfits());
//---
2025-12-21 12:41:35 -05:00
if(is_dynamic == true && percentages_to_activate != NULL && risks_to_be_applied != NULL)
2025-09-22 09:09:20 -05:00
{
2025-09-22 09:09:20 -05:00
if(!isCachedModifier[index])
{
new_loss.SetDynamic(percentages_to_activate, risks_to_be_applied, this.chosen_balance);
2025-11-26 07:03:20 -05:00
LogInfo(StringFormat("Dynamic maximum loss %s successfully configured", EnumToString(type)), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
}
2025-09-22 09:09:20 -05:00
else
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
{
2025-11-26 07:03:20 -05:00
LogError(StringFormat("Maximum loss %s already has an active modifier", EnumToString(type)), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
}
2025-09-22 09:09:20 -05:00
}
2025-09-22 09:09:20 -05:00
else
{
2025-09-22 09:09:20 -05:00
LogInfo(StringFormat("Maximum loss %s added: %.2f%%", EnumToString(type), _percentage), FUNCION_ACTUAL);
}
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
return true;
}
//+------------------------------------------------------------------+
//| Function to add a maximum gain |
2025-09-22 09:09:20 -05:00
//+------------------------------------------------------------------+
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)
{
2025-12-21 12:41:35 -05:00
2025-09-22 09:09:20 -05:00
//---
if(_percentage <= 0.00)
2025-09-22 09:09:20 -05:00
{
2025-09-22 09:09:20 -05:00
LogWarning(StringFormat("Invalid percentage %.2f for maximum gain %s, will not be added to the main array", _percentage, EnumToString(type)), FUNCION_ACTUAL);
2025-11-26 07:03:20 -05:00
return false;
2025-09-22 09:09:20 -05:00
}
2025-09-22 09:09:20 -05:00
//---
2025-09-22 09:09:20 -05:00
if(_percentage > 100.00 && _mode == percentage)
{
2026-01-02 10:22:09 -05:00
LogWarning(StringFormat("Percentage %.2f for %s exceeds 100%%, limiting to 100%%", _percentage, EnumToString(type)), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
_percentage = 100.00;
2025-09-22 09:09:20 -05:00
2025-12-21 12:41:35 -05:00
}
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
//---
const int index = int(type);
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
if(index >= 3)
{
2026-01-02 10:22:09 -05:00
LogError(StringFormat("Invalid maximum gain type: %s (index: %d)", EnumToString(type), index), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
return false;
2025-09-22 09:09:20 -05:00
}
2025-11-26 07:03:20 -05:00
//---
CLossProfit* new_profit = NULL;
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
if(_mode == money)
new_profit = new CLossProfitMoney(false, dynamic_cast<CRiskManagemetBase*>(&this));
else
2026-01-02 10:22:09 -05:00
2025-09-22 09:09:20 -05:00
new_profit = new CLossProfitPercentage(false, dynamic_cast<CRiskManagemetBase*>(&this));
2025-09-22 09:09:20 -05:00
//---
2025-11-26 07:03:20 -05:00
new_profit.SetProperties(_percentage, _applied, type, SuperateModeToFunctionProfit(type), is_strict_);
2025-11-26 07:03:20 -05:00
//---
2025-09-22 09:09:20 -05:00
if(!loss_profits_manager.Add(new_profit))
2025-09-22 09:09:20 -05:00
{
delete new_profit;
return false;
}
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//---
new_profit.SetPtrSuperated(GetPtrLossProfits());
2025-09-22 09:09:20 -05:00
//---
2025-11-26 07:03:20 -05:00
if(is_dynamic == true && percentages_to_activate != NULL && risks_to_be_applied != NULL)
2025-09-22 09:09:20 -05:00
{
if(!isCachedModifier[index])
2025-09-22 09:09:20 -05:00
{
new_profit.SetDynamic(percentages_to_activate, risks_to_be_applied, this.chosen_balance);
2025-11-26 07:03:20 -05:00
LogInfo(StringFormat("Maximum dynamic gain %s successfully set", EnumToString(type)), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
}
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
else
{
LogError(StringFormat("Maximum gain %s already has an active modifier", EnumToString(type)), FUNCION_ACTUAL);
}
}
else
{
LogInfo(StringFormat("Maximum gain %s added: %.2f%%", EnumToString(type), _percentage), FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
}
2025-09-24 14:00:58 -05:00
return true;
}
//+------------------------------------------------------------------+
2025-09-22 09:09:20 -05:00
//| Function to add a risk modifier |
//+------------------------------------------------------------------+
bool CRiskManagemet::AddModificator(CExtraModifications *modificator)
{
//--- Check pointer
if(!CheckPointer(modificator))
2025-09-24 14:00:58 -05:00
{
2025-09-22 09:09:20 -05:00
LogError("The risk modifier is null-invalid", FUNCION_ACTUAL);
return false;
}
//--- Property to be modified is invalid ?
const ENUM_TYPE_LOSS_PROFIT loss_or_profit = modificator.MaximumProfitOrLossAModify();
2025-11-26 07:03:20 -05:00
if(loss_or_profit == WRONG_VALUE)
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
{
2025-09-22 09:09:20 -05:00
LogError("The risk modifier does not modify any risk.", FUNCION_ACTUAL);
return false;
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
}
2025-11-26 07:03:20 -05:00
//--- Property to modify is "empty" ?
2025-09-22 09:09:20 -05:00
if(loss_profits_manager[loss_or_profit].IsEmpty())
{
LogError(StringFormat("The property to be modified %s is not defined", EnumToString(loss_or_profit)), FUNCION_ACTUAL);
return false;
2025-12-21 12:41:35 -05:00
}
2025-09-22 09:09:20 -05:00
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
//--- Is the loss_or_profit already dynamic ?
2025-11-26 07:03:20 -05:00
if(loss_profits_manager[loss_or_profit].IsDynamicMode())
2025-09-22 09:09:20 -05:00
{
LogError(StringFormat("The property to be modified %s is already dynamic", EnumToString(loss_or_profit)), FUNCION_ACTUAL);
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
return false;
2025-11-26 07:03:20 -05:00
}
2025-09-22 09:09:20 -05:00
//---
const int index = int(loss_or_profit);
if(isCachedModifier[index])
2025-11-26 07:03:20 -05:00
2025-09-22 09:09:20 -05:00
{
LogWarning(StringFormat("The property to be modified %s is already being modified", EnumToString(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);
2025-09-24 14:00:58 -05:00
//--- Add
2025-09-22 09:09:20 -05:00
m_hooks.AddItemFast(modificator); // We use the fast version (we already did all the checkpointer checks etc.)
2026-01-07 11:00:48 -05:00
2025-09-22 09:09:20 -05:00
//---
isCachedModifier[index] = true;
2025-09-24 14:00:58 -05:00
return true;
2025-09-22 09:09:20 -05:00
}
//+------------------------------------------------------------------+
2026-01-07 11:00:48 -05:00
//| |
//+------------------------------------------------------------------+
bool CRiskManagemet::AddRmHook(IRiskManagementHook *hook)
{
//--- Check pointer
2025-09-22 09:09:20 -05:00
2025-09-24 14:00:58 -05:00
if(!CheckPointer(hook))
2025-09-22 09:09:20 -05:00
{
2025-09-24 14:00:58 -05:00
LogError("The RM Hook is null-invalid", FUNCION_ACTUAL);
2025-09-22 09:09:20 -05:00
return false;
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
}
//--- Add
2025-09-24 14:00:58 -05:00
2025-09-22 09:09:20 -05:00
m_hooks.AddItemFast(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);
2025-11-10 09:33:30 -05:00
2025-09-22 09:09:20 -05:00
Remover();
2025-12-21 12:41:35 -05:00
return 0;
2025-09-22 09:09:20 -05:00