File size: 4,193 Bytes
d53dc44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"""

ml/position_sizer.py — Probabilistic position sizing.



Sizes positions based on:

  1. ML signal confidence (P(win))

  2. Regime volatility context

  3. Rolling Sharpe-based scaling

  4. Drawdown-based reduction (from original system)

"""
from __future__ import annotations

import logging

import numpy as np
import pandas as pd

logger = logging.getLogger("trading_system.ml.position_sizer")


class ProbabilisticSizer:
    """Position sizing that scales with ML probability edge.



    Core formula:

        base_risk = equity * risk_per_trade_pct

        edge_scale = (P(win) - 0.5) * edge_mult  (capped)

        vol_scale = avg_vol / current_vol  (inverse vol)

        dd_scale = drawdown reduction

        final_risk = base_risk * (1 + edge_scale) * vol_scale * dd_scale



    Safeguards:

        - Min size: 25% of base risk (never go below this)

        - Max size: 200% of base risk (never exceed 2x)

        - Hard cap: max_risk_pct of equity per trade

    """

    def __init__(

        self,

        base_risk_pct: float = 1.0,

        edge_multiplier: float = 2.0,

        max_scale: float = 2.0,

        min_scale: float = 0.25,

        max_risk_pct: float = 2.5,

        dd_reduction_start: float = 3.0,  # start reducing at 3% DD

        dd_reduction_severe: float = 5.0,  # halve at 5% DD

    ):
        self.base_risk_pct = base_risk_pct
        self.edge_multiplier = edge_multiplier
        self.max_scale = max_scale
        self.min_scale = min_scale
        self.max_risk_pct = max_risk_pct
        self.dd_reduction_start = dd_reduction_start
        self.dd_reduction_severe = dd_reduction_severe

    def compute_position_risk(

        self,

        equity: float,

        peak_equity: float,

        ml_confidence: float,

        conf_multiplier: float,

        atr_current: float,

        atr_avg: float,

        regime_vol: float = 0.0,

        strategy_risk_scale: float = 1.0,

    ) -> float:
        """Compute dollar risk for a single trade.



        Args:

            equity: Current portfolio equity.

            peak_equity: Peak equity for DD calculation.

            ml_confidence: ML model confidence [0, 1].

            conf_multiplier: Rule-based confidence multiplier [0.5, 1.5].

            atr_current: Current ATR.

            atr_avg: Average ATR (e.g. 50-bar).

            regime_vol: Current regime volatility level.

            strategy_risk_scale: Strategy-specific scale (e.g. 0.6 for MR).



        Returns: Dollar risk amount for this trade.

        """
        base_risk = equity * (self.base_risk_pct / 100.0)

        # 1. ML edge scaling: conservative — only small bonus for high confidence
        edge = (ml_confidence - 0.5) * self.edge_multiplier  # only > 50% gets bonus
        edge = max(-0.3, min(0.5, edge))  # tight clamp
        edge_scale = 1.0 + edge

        # 2. Inverse volatility scaling
        if atr_avg > 0 and atr_current > 0:
            vol_scale = atr_avg / atr_current
            vol_scale = max(0.5, min(1.5, vol_scale))
        else:
            vol_scale = 1.0

        # 3. Drawdown-based reduction
        dd_pct = ((peak_equity - equity) / peak_equity * 100) if peak_equity > 0 else 0
        if dd_pct >= self.dd_reduction_severe:
            dd_scale = 0.5
        elif dd_pct >= self.dd_reduction_start:
            # Linear interpolation from 1.0 at start to 0.5 at severe
            frac = (dd_pct - self.dd_reduction_start) / (self.dd_reduction_severe - self.dd_reduction_start)
            dd_scale = 1.0 - 0.5 * frac
        else:
            dd_scale = 1.0

        # 4. Strategy-specific scaling + rule confidence
        final_risk = (base_risk * edge_scale * vol_scale * dd_scale
                      * conf_multiplier * strategy_risk_scale)

        # Clamp to [min, max] of base risk
        final_risk = max(base_risk * self.min_scale,
                         min(base_risk * self.max_scale, final_risk))

        # Hard cap
        hard_cap = equity * (self.max_risk_pct / 100.0)
        final_risk = min(final_risk, hard_cap)

        return max(0.0, final_risk)