trader.daemon.loop module

The daemon loop: when to run a cycle, and how to survive one failing.

This module knows nothing about strategies, orders, or persistence. It is handed a cycle callable and decides when to call it — which is what keeps the trading rules in pipeline/run_once.py where they can be reasoned about without a scheduler in the picture.

Three things here are deliberate and easy to undo by accident:

Shutdown finishes the cycle it is in. The flag is checked between phases, never raised through one. A signal landing between “cancel the protective stop” and “submit the sell” is the interruption this app’s ordering rules exist to prevent.

Positions are carried across cycles. reconcile_fills needs the positions as they were before the fills it is reconciling. Re-reading at the start of the next cycle would already include the fill, so a newly filled position would look like one that had always been there — and a fill invisible to reconciliation is a round trip that never opens.

A `ConfigError` is fatal. Waiting does not fix a misconfiguration, and UnsafeConfigError means the safety gate refused something. Exiting non-zero is both more honest and what LaunchAgent’s throttling understands.

trader.daemon.loop.run_forever(*, broker, cycle, schedule, backoff, sleeper, shutdown, config, now=<function <lambda>>, max_cycles=None)[source]

Run cycles until stopped, and return a process exit code.

Parameters:
  • broker (BrokerAdapter) – a read-only adapter — in production the retrying wrapper. The loop only ever reads the clock and positions through it; the order-placing broker is inside cycle, where it belongs.

  • cycle (Callable[[dict[str, Position] | None], CycleReport]) – called with the previous cycle’s positions (or None), returns a CycleReport. In production this is run_once with its graph already bound.

  • max_cycles (int | None) – stop after this many successfully completed cycles. Failed cycles do not count towards it, so –max-cycles 2 means two real cycles rather than two attempts. For verification runs and tests; None means run until shutdown.

  • schedule (MarketSchedule)

  • backoff (Backoff)

  • sleeper (Sleeper)

  • shutdown (ShutdownFlag)

  • config (DaemonConfig)

  • now (Callable[[], datetime])

Returns:

0 for a clean stop, 1 for a fatal configuration or safety failure.

Return type:

int