Skip to content

Parameters and strategy state

Keep tunable values in params and values remembered between bars in state.

symbol = "TCS"

def on_start():
    return {"lookback": 20, "qty": 10}, {"signals_seen": 0}

def on_tick():
    if len(close) < params.lookback:
        return
    if position.is_flat and close[0] > mean(close, params.lookback):
        state.signals_seen += 1
        long(params.qty)

on_start() returns parameters first, initial state second. Parameters are read-only during a run. State is mutable; initialise a value before reading it. It persists between bars within a run. Persistence across restarts requires the runtime's state-restoration support, so do not assume a new run inherits the previous one.

For prices use price data; for holdings use positions. See state reference for access methods.

Separate configuration, memory and observations

Value Role Can your strategy change it?
params.lookback A configured input. No, parameters are read-only during a run.
state.signals_seen Memory you initialise and update. Yes.
close[0] Current market observation. Read it; do not assign to it.
position.qty Current holding view. Change holdings through order actions.

Ordinary local variables inside on_tick() are recreated each call. Use state when the value must survive to the next observation, and params when you want a setting rather than mutable memory.

Access and initialisation

Return (parameters, initial_state) from on_start() in that order. params.lookback and params["lookback"] read the same configured value. params.get("lookback", 20) supplies a fallback when the key is absent. A missing required attribute raises an error rather than inventing a value.

Read known attributes to inspect state, and use "signals_seen" in state to check whether a key exists. State uses attribute assignment, for example state.signals_seen = 0; initialise numeric counters before incrementing them.

In broadcast per-instrument mode, state is scoped to the current symbol. A count observed for TCS is not automatically the shared portfolio count. For a parameter snapshot, dict(params.items()) uses the public mapping interface. Although the Python proxy types expose to_dict(), the current strategy validator rejects that method name (TS005), so do not use it in a validated draft. Persistence across bars, across instruments and across process restarts are separate requirements. Check restoration support before relying on a restart to preserve state; checkpoint coordination is a runtime concern rather than a method to call on the public state proxy.

Continue a broadcast run

When your runner saves and resumes a current Atom checkpoint, it restores each broadcast member's state as well as the shared strategy state. For example:

universe = ["TCS", "INFY"]

def on_start():
    return {}, {"observations": 0}

def on_tick():
    state.observations += 1
    if state.observations == 1:
        long(1)

After two observations for each member, resuming makes each counter three on its next observation. It does not repeat the first-observation entry. This applies to full and differential checkpoints. Starting without a checkpoint is a new run and starts both counters at zero.

Older checkpoints contain only shared state, so missing per-member counters cannot be recovered from them. Broadcast, pair, shared-budget and forecast resume rejects those old snapshots rather than repeating initial entries. Rebuild those runs from their original data. Keep serializable remembered values in state; ordinary module globals and local variables are not checkpoints.