Warrior_EA/Money/MoneyIntelligent.mqh

74 lines
4.4 KiB
MQL5
Raw Permalink Normal View History

//+------------------------------------------------------------------+
//| 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
feat: remove Min_Risk_Reward_Ratio - a guess was overriding a measurement The barrier geometry is derived from the instrument's own excursion distribution (stop at q75 of adverse travel, target at q50 of favourable), and then a 1:2 floor was applied on top, raising the target to twice whatever the stop happened to be. On SP500 H1 that pushed the target to 6.66*ATR, reached on 3.3% of bars inside the horizon - so the label became "almost never a win" and every topology was trained to predict an event that essentially does not occur. A measured target has to stay measured. The ratio never bought what it was believed to buy. A reward:risk floor does not create expectancy; it trades hit rate against payoff at a break-even the geometry already fixes - which this project has separately MEASURED (payoff 0.92 -> 5.72 with expectancy flat). What it did buy was two outages: four consecutive Market validation rejections for "no trading operations" when it rejected 100% of setups, and the label corruption above. Removed: - the input and the RISK_REWARD_RATIO enum (deleted, not left dangling - a live enum with no input behind it is the shape of the stale-.set incident that trained ~250 eras on the wrong target) - the forced target raise in the label geometry - the rrOK eligibility gate in the barrier-geometry scan, so every unclamped pairing now competes on the measurement alone. Clamping stays disqualifying for its own unrelated reason. - the reward < minRR*risk veto in OpenParams Kept: g_TradeRewardRiskRatio still computed and still bridged to Kelly sizing in MoneyIntelligent - the ratio as a SIZING input was always the sound use. Risk stays bounded where it actually is - account risk % and CRiskBudget. The low-reachability warning survives but is re-aimed: with nothing inflating the target, a target the market rarely reaches can only mean the horizon is truncating the excursions the geometry is derived from. Both build variants compile 0 errors / 0 warnings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 14:51:59 -04:00
// that already passed the signal's own entry threshold -
// 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 - always on for the Intelligent MM |
//| strategy (Warrior_EA.mq5 sets m_use_ai_lot=true; the old |
//| Use_AI_Lot_Sizing toggle was removed as redundant). |
//| 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;
}
//+------------------------------------------------------------------+