Skip to content

v0.5.0#21

Merged
davison merged 28 commits intomainfrom
v0.5.0
Feb 26, 2026
Merged

v0.5.0#21
davison merged 28 commits intomainfrom
v0.5.0

Conversation

@davison
Copy link
Copy Markdown
Collaborator

@davison davison commented Feb 26, 2026

major features, refactors and breakages. But it's better

- Updates to make sure exit_reason appears in the round-trips report
- Add report module with templated analysis report created after each run
- Improve exception handling on auth failures to clean up sessions
- Commit 84eb3cc broke IG env vars by moving a lazy import to the top of the file
session_runners.py, causing settings to be instantiated before credentials are ever loaded.
- Drop @DataClass and __post_init__ so env vars are no longer captured at import time
- Make each credential a @Property that calls os.getenv(...) on every access
- Guard broker response that can have `null` return values in that are translated to `None` where a
dict is expected. Propagation up the stack to something calling `.get()` on the None
- Commit 03ac1ab fixed _request (null body → {}) but missed _handle_retry_logic which has the same
resp.json() call with body.get(...) — and AttributeError isn't in its
except (ValueError, KeyError) clause
- `_handle_retry_logic` adds `isinstance(body, dict)` guard
Fires after all SessionStartedEvent handlers complete (warmup +
reconciliation). Used to gate post_warmup_check in ReconciliationManager.
Remove run(), _run_streaming(), _run_polling(), _has_streamer() — streaming
lifecycle moves to BasePortfolio. Strategy now self-registers a
_on_session_started handler that calls warmup() when the portfolio fires
SessionStartedEvent.
BasePortfolio is the new top-level container for trading sessions.
It owns the streaming lifecycle (run, _handle_event) and fires the
session lifecycle events: SessionStartedEvent → SessionReadyEvent →
[streaming] → SessionEndedEvent.
Wraps a single BaseStrategy with no risk allocation. Strategy warmup is
handled automatically via SessionStartedEvent. Candle events are forwarded
to the strategy's on_candle_close.
Subscribe to SessionStartedEvent for reconcile_on_startup() and
SessionReadyEvent for post_warmup_check(). These no longer need to be
called imperatively from user code — the portfolio's run() fires the
events in the correct order.
The new entry point takes a portfolio_factory instead of a list of
strategy specs. The factory receives a started Client and returns an
initialised BasePortfolio. Lifecycle management (events, streaming,
shutdown) is now owned by BasePortfolio.run().
Replace strategy_factory with portfolio_factory. The portfolio's run()
now owns lifecycle events (SessionStartedEvent, SessionEndedEvent) and
order handler wiring, so those are removed from the runner.
…runner

Promotes Portfolio to the primary top-level container. Clients now extend
BasePortfolio (or use SimplePortfolio for single-strategy use cases) instead
of subclassing BaseStrategy.

Key changes:
- SessionReadyEvent fires after SessionStartedEvent handlers complete
- BaseStrategy self-subscribes to SessionStartedEvent for warmup
- BasePortfolio manages full session lifecycle (startup events, streaming,
  shutdown) and is the StreamConsumer (holds _handle_event, on_price_update,
  on_candle_close)
- SimplePortfolio wraps one strategy, delegating both price and candle events
- ReconciliationManager subscribes to SessionStartedEvent/SessionReadyEvent
  instead of being called imperatively
- run_portfolio(portfolio_factory, client_factory) replaces run_strategies()
- Backtest runner parameter renamed strategy_factory → portfolio_factory
- Exports updated: run_portfolio, BasePortfolio, SimplePortfolio,
  SessionReadyEvent added to tradedesk public API
- All tests updated to the new API; no backward-compat shims
Replace all run_strategies/strategy_specs references with the new
run_portfolio(portfolio_factory, client_factory) pattern. Rewrite
backtesting_guide.md from scratch to match the current API.
@davison davison merged commit 9d6c613 into main Feb 26, 2026
5 checks passed
@davison davison deleted the v0.5.0 branch February 26, 2026 19:28
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.

1 participant