Skip to content

MaxDrawdownLimit(action="reduce") is reported as breached but nothing happens #103

Description

@stefan-jansen

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.

Activity

  1. added
    type: bugConfirmed or reported incorrect behavior
    priority: criticalImmediate correctness, security, or release impact
    compatibility: affectedHas Python, platform, dependency, or cross-library compatibility impact
    and removed on Sep 23, 2026
  2. stefan-jansen commented on Sep 24, 2026

    @stefan-jansen
    ContributorAuthor

    Verified on PR #119 at commit 8343029. The focused tests in tests/risk/test_portfolio_manager.py and tests/risk/test_portfolio_limits.py passed locally (98 passed); the remote coverage job passed. Drawdown reduction is applied through broker orders, once per continuous breach, with recovery behavior covered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    compatibility: affectedHas Python, platform, dependency, or cross-library compatibility impactpriority: criticalImmediate correctness, security, or release impactstatus: acceptedAccepted for implementationtype: bugConfirmed or reported incorrect behavior

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions