//+------------------------------------------------------------------+ //| RiskManagementBases.mqh | //| Copyright 2025, Niquel Mendoza. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, Leo." #property link "https://www.mql5.com" #property strict #ifndef MQLARTICLES_RM_RISKMGMTBASES_MQH #define MQLARTICLES_RM_RISKMGMTBASES_MQH //+------------------------------------------------------------------+ //| Include | //+------------------------------------------------------------------+ #include "AccountStatus.mqh" //+------------------------------------------------------------------+ //| Defines\Enums | //+------------------------------------------------------------------+ //--- Risk management classes class CRiskManagemetBase; // Base class class CRiskManagemet; // Parent class class CRiskManagemetPersonal; // Class for personal risk management class CRiskManagemetPropFirm; // Class for prop firm risk management class CRiskPointer; // Class to obtain a pointer based on the selected risk management //--- class CLossProfit; // Class to handle maximum losses or gains class CLossProfitManager; // Container class to manage CLossProfit objects //--- #define RISK_MANAGEMENT_RESERVE_POS 10 //--- #ifndef RISK_MANAGEMENT_BASES_MAX_POS_OPEN #define RISK_MANAGEMENT_BASES_MAX_POS_OPEN (64) #endif // RISK_MANAGEMENT_BASES_MAX_POS_OPEN //--- // m_positions aamcena posiciones directamente en el array de m_positioncs de las posiciones de la cuenta // No amcena hashes ni nada //+------------------------------------------------------------------+ //| Base Class CRiskManagement | //+------------------------------------------------------------------+ class CRiskManagemetBase : public CAccountGestor { protected: //--- CTrade trade; //Instancia de ctrade int m_positions[RISK_MANAGEMENT_BASES_MAX_POS_OPEN]; //--- ulong magic_number; //Numero magico double daily_profit, weekly_profit, monthly_profit, gross_profit; //Profits de la cuenta datetime last_day_time; datetime last_weekly_time; datetime last_monthly_time; datetime init_trade_time; double account_profit; //Ganancia de la cuenta NETA, no confundir con ganancia BRUTA desde que inicio la cuenta int m_positions_size; bool positions_open; //--- bool TryRemoveFromArrayOfPos(const int global_pos_index); //--- void GetPositionsProfit(); // Function to get total profit from open positions public: CRiskManagemetBase(const ulong magic_); ~CRiskManagemetBase(); //--- double m_pos_current_profit; //--- virtual double GetValorWithApplied(double percentage_, int type, ENUM_APPLIED_PERCENTAGES applied) const = 0; // Function to get value based on max loss or gain type //--- Function to set general class parameters virtual void SetGeneralParameters(MqlParam ¶ms[]); //--- Getters //- Magic number inline ulong MagicNumber() const { return this.magic_number; } //--- General profit retrieval inline double GrossProfit() const { return this.gross_profit; } inline double WeeklyProfit() const { return this.weekly_profit; } inline double DailyProfit() const { return this.daily_profit; } inline double MontlyProfit() const { return monthly_profit; } //--- Functions to work with open positions __forceinline int GetPositions(uint flags) const; // Get total open positions filtered by flags __forceinline int GetPositionsTotal() const { return m_positions_size; } __forceinline void CloseAllPositions(uint flags = FLAG_CLOSE_ALL_LOSS | FLAG_CLOSE_ALL_PROFIT | FLAG_POSITION_TYPE_BUY | FLAG_POSITION_TYPE_SELL); void CloseAllOrders(uint flags); //--- __forceinline void CalcProfit() { m_pos_current_profit = g_account_open_positions.GetProfitMask(m_positions, m_positions_size); } //--- static __forceinline bool WraperIsSupertedLoss(const double value, const double saved_value, void *ptr) { return ((CRiskManagemetBase*)ptr).m_pos_current_profit > value; } static __forceinline bool WraperIsSupertedProfit(const double value, const double saved_value, void *ptr) { return -(((CRiskManagemetBase*)ptr).m_pos_current_profit) > value; } }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CRiskManagemetBase::CRiskManagemetBase(const ulong magic_) : daily_profit(0.00), weekly_profit(0.00), monthly_profit(0.00), gross_profit(0.00), last_day_time(0), last_weekly_time(0), last_monthly_time(0) , init_trade_time(0), account_profit(0.00), positions_open(false) { //--- m_positions_size = 0; //--- trade.SetExpertMagicNumber(magic_); if(magic_ == NOT_MAGIC_NUMBER) LogWarning("No magic number has been chosen, taking into account all the magic numbers and the user's trades", FUNCION_ACTUAL); this.magic_number = magic_; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CRiskManagemetBase::~CRiskManagemetBase() { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CRiskManagemetBase::CloseAllOrders(uint flags) { for(int i = OrdersTotal() - 1; i >= 0; i--) { const ulong ticket = OrderGetTicket(i); //--- ResetLastError(); if(OrderSelect(ticket)) { ENUM_ORDER_TYPE type_order = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); const ulong magic = OrderGetInteger(ORDER_MAGIC); const int bandera = OrderTypeToFlag(type_order); if((bandera & flags) != 0 && (magic == this.magic_number || this.magic_number == NOT_MAGIC_NUMBER)) { if(type_order == ORDER_TYPE_BUY || type_order == ORDER_TYPE_SELL) trade.PositionClose(ticket); else trade.OrderDelete(ticket); } } else { LogError(StringFormat("Error al selecionar la order %I64u, ultimo error = %d", ticket, GetLastError()), FUNCION_ACTUAL); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRiskManagemetBase::TryRemoveFromArrayOfPos(const int global_pos_index) { //--- Find int index = -1; for(int i = 0; i < m_positions_size; i++) { if(m_positions[i] == global_pos_index) { index = i; break; } } //--- Check is invalid if(index == -1) return false; //--- Reduce size m_positions_size--; //--- Move for(int i = index; i < m_positions_size; i++) { m_positions[i] = m_positions[i + 1]; // Move the elements } //--- return true; } //+------------------------------------------------------------------+ //| Function to obtain the number of open positions | //+------------------------------------------------------------------+ __forceinline int CRiskManagemetBase::GetPositions(uint flags) const { return g_account_open_positions.GetPositionsMask(m_positions, m_positions_size, flags); } //+---------------------------------------------------------------------------+ //| Function to close all positions opened by the magic number or by the user | //+---------------------------------------------------------------------------+ __forceinline void CRiskManagemetBase::CloseAllPositions(uint flags = FLAG_CLOSE_ALL_LOSS | FLAG_CLOSE_ALL_PROFIT | FLAG_POSITION_TYPE_BUY | FLAG_POSITION_TYPE_SELL) { g_account_open_positions.CloseAllPositionMask(m_positions, m_positions_size, trade, flags); } //+------------------------------------------------------------------+ #endif // MQLARTICLES_RM_RISKMGMTBASES_MQH //+------------------------------------------------------------------+