//+------------------------------------------------------------------+ //| MoneyRiskBase.mqh | //| AnimateDread | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "..\Expert\ExpertMoneyCustom.mqh" //+------------------------------------------------------------------+ //| Class CMoneyRiskBase. | //| Shared risk-based lot-sizing core for every money-management | //| strategy that sizes a trade off a fixed account-risk percentage | //| (CMoneyFixedRisk, CMoneyIntelligent) - CalculatePotentialLoss()/ | //| CheckOpenLong()/CheckOpenShort()/CalculateLotSize() used to be | //| duplicated near-verbatim across both. AdjustRiskAmount()/ | //| AdjustLotSize() are the two points a subclass can diverge at | //| (CMoneyIntelligent overrides AdjustRiskAmount() for its Kelly- | //| criterion, confidence-and-reward:risk-based sizing) - override | //| only those, everything else here is shared as-is. | //+------------------------------------------------------------------+ class CMoneyRiskBase : public CExpertMoneyCustom { public: virtual double CheckOpenLong(double price, double sl); virtual double CheckOpenShort(double price, double sl); virtual double CheckClose(CPositionInfo *position) { return(0.0); } protected: double CalculatePotentialLoss(ENUM_ORDER_TYPE orderType, double price, double sl); double CalculateLotSize(double loss); //--- Hook for CMoneyIntelligent's Kelly-criterion risk% scaling (see its own //--- AdjustRiskAmount() override for the rationale); default no-op keeps CMoneyFixedRisk's //--- behavior exactly as it was before this base class existed. virtual double AdjustRiskAmount(double riskAmount) { return riskAmount; } //--- Reserved extension point for a future lot-size-level adjustment (e.g. equity-curve- //--- based scaling); no current subclass overrides this - default is a no-op. virtual double AdjustLotSize(double lot) { return lot; } }; //+------------------------------------------------------------------+ //| Getting lot size for open long position. | //+------------------------------------------------------------------+ double CMoneyRiskBase::CheckOpenLong(double price, double sl) { if(m_symbol == NULL) return 0.0; double loss = CalculatePotentialLoss(ORDER_TYPE_BUY, price, sl); if(loss <= 0.0) return m_symbol.LotsMin(); double lot = AdjustLotSize(CalculateLotSize(loss)); string description; // Adjust the lot size within allowed bounds and ensure sufficient margin if(CheckAndCorrectVolumeValue(lot, description) && CheckAndAdjustMoneyForTrade(m_symbol.Name(), lot, ORDER_TYPE_BUY)) return lot; else return 0.0; // Handle as needed or inform the user } //+------------------------------------------------------------------+ //| Getting lot size for open short position. | //+------------------------------------------------------------------+ double CMoneyRiskBase::CheckOpenShort(double price, double sl) { if(m_symbol == NULL) return 0.0; double loss = CalculatePotentialLoss(ORDER_TYPE_SELL, price, sl); if(loss <= 0.0) return m_symbol.LotsMin(); double lot = AdjustLotSize(CalculateLotSize(loss)); string description; // Adjust the lot size within allowed bounds and ensure sufficient margin if(CheckAndCorrectVolumeValue(lot, description) && CheckAndAdjustMoneyForTrade(m_symbol.Name(), lot, ORDER_TYPE_SELL)) return lot; else return 0.0; // Handle as needed or inform the user } //+------------------------------------------------------------------+ //| Calculate potential loss | //+------------------------------------------------------------------+ double CMoneyRiskBase::CalculatePotentialLoss(ENUM_ORDER_TYPE orderType, double price, double sl) { if(price == 0.0) price = (orderType == ORDER_TYPE_BUY) ? m_symbol.Ask() : m_symbol.Bid(); return -m_account.OrderProfitCheck(m_symbol.Name(), orderType, 1.0, price, sl); } //+------------------------------------------------------------------+ //| Calculate the lot size based on potential loss and account balance| //+------------------------------------------------------------------+ double CMoneyRiskBase::CalculateLotSize(double loss) { double riskAmount = AdjustRiskAmount(m_account.Balance() * m_percent / 100.0); double stepvol = m_symbol.LotsStep(); return MathFloor(riskAmount / loss / stepvol) * stepvol; } //+------------------------------------------------------------------+