//+------------------------------------------------------------------+ //| Warrior_EA | //| AnimateDread | //| | //+------------------------------------------------------------------+ #include "MoneyRiskBase.mqh" #include "..\Variables\ConfidenceBridge.mqh" // Quarter-Kelly: only a quarter of the theoretical edge-optimal fraction is ever applied. // Full Kelly is well documented as too volatile for live capital; quarter-Kelly is a // conservative institutional default, deliberately chosen here for prop-firm-evaluation-style // accounts that also carry hard daily-loss/drawdown limits (Signals\SignalRiskGuard.mqh). #define KELLY_FRACTION_MULTIPLIER 0.25 // Floor so a thin/negative-edge estimate never scales risk% all the way to zero on a trade // that already passed the signal's own entry threshold and Min_Risk_Reward_Ratio filter - // it only ever gets sized down to a minimum, never fully skipped by Money. #define KELLY_MIN_RISK_FRACTION 0.1 class CMoneyIntelligent : public CMoneyRiskBase { protected: bool m_use_ai_lot; // true: scale risk % via the Kelly criterion below int m_confidence_source; // CONFIDENCE_SOURCE underlying int (0=AI, 1=DB, 2=Blended) public: // Constructor CMoneyIntelligent() : m_use_ai_lot(false), m_confidence_source(0) {} void UseAIConfidenceLotSizing(bool value) { m_use_ai_lot = value; } void ConfidenceSource(int value) { m_confidence_source = value; } protected: //--- CMoneyRiskBase::CalculateLotSize() hook - see CMoneyRiskBase's declaration comment. virtual double AdjustRiskAmount(double riskAmount) override; }; //+------------------------------------------------------------------+ //| Kelly-criterion risk% scaling - only active when Use_AI_Lot_Sizing| //| is on. Unifies what used to be two disconnected mechanisms (a | //| linear confidence-only scale here, plus an unrelated trade- | //| history streak multiplier in a since-removed AdjustLotSize() | //| override) into a single edge-based model that uses everything | //| the NN and the trade's own risk math already know: | //| p = estimated win probability, derived from the empirically | //| calibrated AI/DB confidence magnitude (see | //| ExpertSignalAIBase::CalibratedConfidenceMagnitude()'s | //| m_confidenceCalScale - it's scaled against real OOS accuracy,| //| not a raw uncalibrated softmax value) mapped from [0,1] onto | //| [0.5,1.0] - zero confidence is a coin flip, full confidence | //| is treated as near-certain. | //| b = this specific trade's real reward:risk ratio, bridged from | //| CExpertSignalCustom::OpenParams() via g_TradeRewardRiskRatio | //| (Variables\ConfidenceBridge.mqh) - always >= Min_Risk_Reward | //| _Ratio, since OpenParams() rejects thinner setups before | //| Money is ever consulted. | //| f* = p - (1-p)/b is the Kelly-optimal fraction; only | //| KELLY_FRACTION_MULTIPLIER of it is used (see its own comment), | //| then clamped to [KELLY_MIN_RISK_FRACTION, 1.0] so this can only | //| ever scale the configured Money_Risk_Percent DOWN from its input | //| ceiling, never above it - the same invariant this method has | //| always guaranteed. | //+------------------------------------------------------------------+ double CMoneyIntelligent::AdjustRiskAmount(double riskAmount) { if(!m_use_ai_lot) return riskAmount; if(g_TradeRewardRiskRatio <= 0.0) return riskAmount * KELLY_MIN_RISK_FRACTION; // bridge not populated yet - defensive floor double confidence = CombinedConfidence(m_confidence_source); double p = 0.5 + 0.5 * confidence; double b = g_TradeRewardRiskRatio; double fKelly = MathMax(0.0, MathMin(1.0, p - (1.0 - p) / b)); double fraction = MathMax(KELLY_MIN_RISK_FRACTION, MathMin(1.0, fKelly * KELLY_FRACTION_MULTIPLIER)); return riskAmount * fraction; } //+------------------------------------------------------------------+