1
0
Derivar 0
Warrior_EA/Money/MoneyRiskBase.mqh
AnimateDread d91cabc114 refactor(MoneyIntelligent): replace streak-chasing lot sizing with fractional-Kelly criterion
Optimize() scaled lot size off account trade-history streaks with no Magic-number
filter (picked up other EAs'/manual trades) and an unconfigurable m_factor stuck at
1.0 (Factor() was never wired from an input), so a 3-trade streak could triple lot
size or send it negative. It was also entirely disconnected from what the AI model
actually knows about the current setup.

Replaced both AdjustRiskAmount()'s linear confidence-only scale and Optimize()'s
streak multiplier with one edge-based model: p from the empirically calibrated
AI/DB confidence magnitude, b from the trade's real reward:risk ratio (newly
bridged from OpenParams() via g_TradeRewardRiskRatio), quarter-Kelly applied and
clamped so risk% can only ever scale down from its configured ceiling, never above it.
2026-07-18 17:39:58 -04:00

91 linhas
4,8 KiB
MQL5

//+------------------------------------------------------------------+
//| 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;
}
//+------------------------------------------------------------------+