Logical namespace for grouping state buckets within a signal
Default value when no persisted state exists
Tuple [getState, setState] bound to the bucket and initial value
import { createSignalState } from "backtest-kit";
const [getTradeState, setTradeState] = createSignalState({
bucketName: "trade",
initialValue: { peakPercent: 0, minutesOpen: 0 },
});
// in onActivePing:
await setTradeState((s) => ({
peakPercent: Math.max(s.peakPercent, currentUnrealisedPercent),
minutesOpen: s.minutesOpen + 1,
}));
const { peakPercent, minutesOpen } = await getTradeState();
if (minutesOpen >= 15 && peakPercent < 0.3) await commitMarketClose(symbol);
Creates a bound [getState, setState] tuple scoped to a bucket and initial value.
Both returned functions resolve the active pending or scheduled signal and the backtest/live flag automatically from execution context — no signalId argument required.
Automatically detects backtest/live mode from execution context.
Intended for LLM-driven capitulation strategies that accumulate per-trade metrics (e.g. peakPercent, minutesOpen) across onActivePing ticks. Profitable trades endure -0.5–2.5% drawdown and reach peak 2–3%+. SL trades show peak < 0.15% (Feb08, Feb13) or never go positive (Feb25). Rule: if minutesOpen >= N and peakPercent < threshold (e.g. 0.3%) — exit.