Skip to content

Clear stale orders on bankruptcy - #1392

Open
OllyNewport wants to merge 2 commits into
kernc:masterfrom
OllyNewport:fix/issue-1318-bankruptcy-typehints-repr
Open

Clear stale orders on bankruptcy#1392
OllyNewport wants to merge 2 commits into
kernc:masterfrom
OllyNewport:fix/issue-1318-bankruptcy-typehints-repr

Conversation

@OllyNewport

Copy link
Copy Markdown

Addresses three remaining items from #1318 (following #1389 and the earlier docs PR for #5/#17/#20).

#6 — Bankruptcy leaves stale orders

_Broker.next() already force-closes every open Trade when equity drops to <= 0
(which also cleans up their SL/TP orders), but any still-pending, unfilled order
(e.g. a limit order that never triggered) was left dangling in Strategy.orders /
_Broker.orders, even though the simulation has stopped and it can never execute.
self.orders.clear() is now called alongside the rest of the bankruptcy cleanup.

Covered by a new regression test that drives an over-leveraged position into a 99%
crash and asserts stats._strategy.orders == () afterward.

#18 — Type hints polish (Trade, Order, Backtest.optimize)

Filled in missing return-type (and a couple of parameter-type) annotations across
Order's and Trade's properties/methods, and tightened Backtest.optimize's
method parameter to Literal['grid', 'sambo'].

  • Trade.sl / Trade.tp setters were typed float but the docstring always allowed
    None to cancel the order — retyped to Optional[float].
  • Annotating the sl / tp getters as -> Optional[float] surfaced a real mypy
    ambiguity in self.__sl_order and self.__sl_order.stop (mypy can't prove Order
    is always truthy). Rewrote both as an equivalent ternary — no behavior change,
    just type-checker-friendly.

No logic changes elsewhere.

#19Order.__repr__ verbosity

Order.__repr__ always printed contingent=... even when is_contingent was
False — and rendered it as contingent=0 rather than contingent=False, because
round(False, 5) == 0. Falsy contingent is now omitted like any other unset
field, while a genuinely contingent order still shows it (e.g.
<Order size=-1.0, stop=90.0, contingent=1>).

Covered by a new test asserting 'contingent' is absent from a plain order's repr
and present on a contingent SL order's repr.

Testing

  • python -m backtesting.test — 83 passed, 1 skipped (unrelated)
  • flake8 backtesting — clean
  • mypy backtesting — same 9 pre-existing errors as master (all in unrelated
    files: _stats.py, _plotting.py, lib.py); zero new errors, two errors in
    Trade actually fixed as a side effect of the sl/tp rewrite above

🤖 Generated with Claude Code

OllyNewport-UEA and others added 2 commits August 10, 2026 14:34
…ints; clean up Order.__repr__

Addresses three remaining items from kernc#1318:

- kernc#6: `_Broker.next()` now clears `self.orders` when equity drops to
  <=0. Trades were already force-closed on bankruptcy, but any
  still-pending, unfilled order (e.g. a limit order that never
  triggered) was left dangling in `Strategy.orders`/`_Broker.orders`,
  even though it can never execute once the simulation has stopped.

- kernc#18: Added missing return-type (and a couple of parameter-type)
  annotations across `Order` and `Trade` properties/methods, and
  tightened `Backtest.optimize`'s `method` parameter to
  `Literal['grid', 'sambo']`. `Trade.sl`/`Trade.tp` setters were
  typed `float` but the docstring always allowed `None` to cancel the
  order, so retyped to `Optional[float]`. Annotating the `sl`/`tp`
  getters as `-> Optional[float]` surfaced a real mypy ambiguity in
  `self.__sl_order and self.__sl_order.stop` (mypy can't prove `Order`
  is always truthy); rewrote as an equivalent ternary with no
  behavior change.

- kernc#19: `Order.__repr__` always printed `contingent=...` even when
  `is_contingent` was `False` (rendered as `contingent=0`, since
  `round(False, 5) == 0`). Falsy `contingent` is now omitted like any
  other unset field, while a genuinely contingent order still shows
  it.

Verified against CONTRIBUTING.md: flake8 clean; mypy shows the same
9 pre-existing, unrelated errors as master (in _stats.py, _plotting.py,
lib.py) with zero new errors; full suite (python -m backtesting.test)
passes, 83 tests, 1 unrelated skip.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants