Strategies

Strategies

Overview & lifecycle

Automated trading logic — managed orders, parameters, indicators, full ATM bracket management, backtest and live — all from the same class, driven by a small set of lifecycle hooks.

The strategy model

Everything in this chapter starts from one base class. A strategy subclasses Strategy in the TradeStrike.Pipeline.Strategies namespace, overrides a few lifecycle hooks, and calls the protected helpers (bars, position, orders, logging) to do its work. None of the host plumbing — data feed, trading service, runner — is ever visible: every helper delegates to an IStrategyContext the runner injects before the first callback. That is what lets the same class run unchanged against a live broker or a backtest engine.

Three invariants the runtime guarantees shape how you store state and reason about concurrency:

  • One instance = one run. Every backtest or live launch creates a fresh instance; fields hold per-run state. The runner never resets a strategy's fields — to run again, construct a new instance.
  • Single-threaded. Every On… hook runs on the run's single serialised strategy thread. No locks, no volatile — the one exception is custom chart rendering (see custom rendering and RenderingStrategy).
  • Same code, both modes. The strategy depends only on the IStrategyContext seam, so the identical class runs deterministically in a backtest and live against a real broker.

Order operations are fire-and-forget. PlaceOrder, CancelOrder, ModifyOrder and Flatten never block on a broker round-trip; the outcome arrives later through OnOrderUpdate / OnFill / OnPositionUpdate.

Lifecycle hooks

A strategy is defined entirely by the hooks it overrides. The runner calls them in a fixed order: declare once, start once, a callback per bar, with order/fill/position events interleaved as the market responds, and finally a clean-shutdown hook. Every override is optional — a hook you do not override is a no-op.

Hook When Use it for
OnInitialize() Once, first, before any bar Declare parameters & indicators, set Calculate.
OnStart() Once, after overrides applied, before bars Read final param values, warm-up, call UseAtm.
OnBar() Per bar (per Calculate mode) Your entry/exit logic.
OnOrderUpdate(Order) Order state changed React to working/filled/rejected.
OnFill(Fill) One execution Track raw executions / commission.
OnPositionUpdate(Position) Net position changed Track PnL, reconcile state.
OnStop() Clean shutdown Release external resources. (Not called on a fault.)
Declare vs. read. Declare parameters and indicators in OnInitialize, but read their final values from OnStart onward — the host applies parameter overrides between those two hooks, so a value read in OnInitialize is still the default. Declarations added later than OnInitialize are ignored: the indicator host is built once, between OnInitialize and OnStart.

How a run flows

The runner drives the lifecycle and isolates faults: an exception thrown in any hook transitions the run to Faulted and releases its subscriptions — it never escapes to crash the host. The state machine is one-way and linear, with Faulted as an off-ramp.

graph LR;
  C[Created] --> I[Initialized];
  I --> R[Running];
  R --> S[Stopped];
  R -. throws .-> F[Faulted];
  I -. throws .-> F;

Stopped and Faulted are terminal. OnStop runs on a clean stop, but not on a fault — the strategy is in an unknown state and running its teardown could compound the failure. You read the current state any time via the State property (StrategyState).

Strategies are a big surface, so the topics are split across focused pages. Start with your first strategy and walk down the list; each page builds on the model and lifecycle above.

Page What it covers
Your first strategy A complete SMA-crossover strategy, end to end.
Discovery & metadata How the catalog finds your class and what [StrategyMetadata] controls.
Parameters Optimizable and fixed inputs, and the override flow.
Using indicators Declaring SDK and built-in indicators inside a strategy.
Bars & position state Reading history, the current bar, position, account and session.
Managed orders Position-aware intent: enter/exit with reversal handling.
Raw orders & brackets Direct order requests, modifies, cancels and the enum reference.
Advanced trade management (ATM) Multi-target brackets, auto-breakeven and trailing.
Calculation cadence On-bar-close, on-price-change and on-each-tick evaluation.
Backtest & live Running the same class in the harness and in production.