Version: ml4t-backtest 0.1.8
MaxDrawdownLimit documents the actions "none", "warn", "reduce", "halt" and "liquidate", and LimitResult carries a reduction_pct for "reduce". RiskManager.update (risk/portfolio/manager.py) handles only halt, liquidate and warn. A "reduce" breach is returned to the caller and then dropped: no scaling, no halt, no warning.
from datetime import datetime
from ml4t.backtest.risk.portfolio.limits import MaxDrawdownLimit
from ml4t.backtest.risk.portfolio.manager import RiskManager
m = RiskManager(limits=[MaxDrawdownLimit(max_drawdown=0.10, action="reduce")])
m.update(equity=100.0, positions={"A": 100.0}, timestamp=datetime(2024, 1, 1))
res = m.update(equity=80.0, positions={"A": 80.0}, timestamp=datetime(2024, 1, 2))
print([(r.breached, r.action) for r in res], m.is_halted, m._warnings)
# [(True, 'reduce')] False []
A 20% drawdown against a 10% limit changes nothing. A user who configures "reduce" believes exposure is being cut.
Expected: either "reduce" scales positions by reduction_pct (and the scaling is visible in fills), or the action is rejected at construction until it is implemented. Silently accepting it is the defect.
Version: ml4t-backtest 0.1.8
MaxDrawdownLimitdocuments the actions"none","warn","reduce","halt"and"liquidate", andLimitResultcarries areduction_pctfor"reduce".RiskManager.update(risk/portfolio/manager.py) handles onlyhalt,liquidateandwarn. A"reduce"breach is returned to the caller and then dropped: no scaling, no halt, no warning.A 20% drawdown against a 10% limit changes nothing. A user who configures
"reduce"believes exposure is being cut.Expected: either
"reduce"scales positions byreduction_pct(and the scaling is visible in fills), or the action is rejected at construction until it is implemented. Silently accepting it is the defect.