The strategy kit

strategies/kit is the shared toolkit beside the strategies: the helpers every port of a legacy strategy was writing again by hand, kept out of sdk/strategy, which stays a lean wire-protocol SDK (the reasoning that keeps the nseries bridge in indicators). Its package comment states three conversion rules and every helper follows them: protective exits are per-bar price-level checks that the strategy answers with plain market orders, not venue-side verbs; state is derived from ctx, the position’s transitions rather than private intent flags, so it survives a restart; and equity sizing reads ctx.Account() and degrades to a caller’s floor when the run reports no balances. This chapter lists every exported helper, what it does, what it assumes about the order lifetime and which profile it serves (the order-lifetime programme’s increment I21, PR8, GLE-467). The two profiles are the legacy one, under which a Day order lives one evaluation bar and ctx.Flat is the entry gate, and lifetime v2 (--lifetime v2), under which an order rests until the strategy or the venue ends it and the SDK keeps the attempt-indexed view (Querying your own state). In the tables, both means the helper takes part in placing, sizing or gating orders and does the same under either profile; v2 means it needs lifetime v2; none means it reads data alone (bars, series, statistics, observations) and touches no order, so the profile does not reach it. A helper’s doc comment is its contract; the chapter follows it.

Orders and the position

HelperWhat it doesOrder lifetimeProfile
Series(ctx, bar) (kit.go)the bar’s own lookback series: the SDK buckets bars by SeriesID, falling back to the symbol when it is empty, and every strategy must mirror that rule or a single-symbol run reads an empty seriesnoneboth
Flatten(symbol, qty) (kit.go)the market order that closes a signed position, a sell of qty while long and a buy of -qty while short; since the constructor graduated into the SDK it delegates to algolang.Flatten and stays for source compatibility; qty must be non-zeroa Day market order consumed on its first eligible bar: the simulator fills it at the next bar’s open, before that bar’s decision; a venue can hold it across a decision, and then an exit gated on the position alone sends a second one (the duplicate-flatten window), which is why Exiting stands beside itboth
Exiting(ctx, symbol) (exiting.go)the exit-once gate: true when a working order on the symbol opposes the position, a sell while long or a buy while short; false on a nil context and while flat; each working entry counts by its side alonereads the SDK’s working view as the run’s profile makes it (the legacy map until a fill, a cancel or an expiry removes the order; the attempt-indexed view until the attempt’s terminal event) and withholds a second flatten until the first ends; see The exit-once gateboth
IDStamper (kit.go)deterministic, restart-safe client ids, <prefix>_<symbol>_<barCloseUnixNano>_<seq>; Stamp(order, bar) sets ClientID and returns the order; the per-process sequence tells apart the orders of one bar (a reversal’s close and open) and the bar’s timestamp is what makes the id restart-safenone: the id names the order and says nothing about its life. An order a Controller submits is labelled by the controller and its ClientID is not read, so the stamper is for orders a strategy submits itselfboth
Tracker (tracker.go)the position and bar state the legacy engine handed a strategy, rebuilt from ctx.Position transitions: Update(position, bar), once per primary bar, returns the signed quantity and maintains BarIdx, EntryBar, the entry snapshot (EntryPrice, EntryHigh, EntryLow, and EntryTime from Position.OpenedAt), Peak and Trough since entry, this bar’s JustEntered, JustExited, JustAdded and JustAdopted, and LastLossBar; BarsSinceEntry(), TimeInTrade(now), InCooldown(waitBars) and ReEntered() read and adjust itone assumption, in its comments and its tests (kit_test.go, openedat_test.go): an order from OnBar on bar N fills on bar N+1, so the first bar of a backtest is flat and the entry snapshot is taken one bar after the signal, when the fill is first observable. That is the simulator’s next-open fill. Live, a market order may fill later; the snapshot is then taken on the bar the fill is first seen, with that bar’s high and low, while EntryTime stays exact through the SDK’s Position.OpenedAt, and BarsSinceEntry is a per-process count that restarts after a live restart (TimeInTrade is the restart-correct measure). The SDK’s ctx.Trade(bar), which returns a TradeState, is Update graduated into the SDK with the same fields and the same caveat, and is the replacement most strategies use; one production strategy still drives the Tracker as a pure state machine, which is what its Update signature is forboth
LoserCooldown (tier2.go)the exact realized-PnL loser test over ctx.Trade and ctx.Position(sym).Realized: Observe(tradeState, realized), once per primary bar, snapshots realized PnL on an entry and records a loss when a position closes with realized below its own snapshot (on a flip bar the closed side is judged against its own entry before the new side’s snapshot is taken), and InCooldown(barIdx, waitBars) blocks entries for waitBars bars after a loss; LastLossBar() reads the anchor. It replaces the close-against-average approximation the Tracker makesnone beyond the trade state’s transitionsboth
StopSuite (stops.go)the protective-exit stack as pure price levels against the current bar: a hard stop at Entry less or plus ATR*StopMult (TightenedMult after TightenAfter bars), a break-even floor once the close has moved BreakEvenMult*ATR in favour, a target at ATR*TargetMult and a trailing stop at TrailDist from the Tracker’s Peak or Trough; a zero field disables its mechanism; Breached(mp, bar, barsSinceEntry) reports whether the bar touched any enabled levelnone: it rests nothing. The exit the strategy answers a breach with is a market order, so it is Flatten’s and Exiting’sboth
Controller (reconcile.go)the desired-order controller: at each decision the strategy declares the orders it wants resting, each under a logical key, and the controller compares the declaration with the attempt-indexed view and produces the cancel requests and the submissions; see The desired-order controllerthe v2 contract: it reads the attempt-indexed view and submits at the lifecycle turns, neither of which is authoritative on a legacy runv2

RestingSuite and RestingParams, the tier-2 counterpart to StopSuite, are gone since I21’s PR8 (2026-10-11). They built the Day orders a position re-rested every bar to protect itself, a first-touch stop (TouchSell or TouchBuy) and a profit-taking limit, OCO-joined under a tag the caller made unique per bar so that the pair retired with its one-bar Day life. That is the one-bar lifetime written into a helper: under the legacy profile the simulator expired the pair after one evaluation bar and the strategy re-emitted it, and under lifetime v2 a Day order rests to its session’s close (Calendar cancellation instants (lifetime v2)), so on an intraday grid the same call would stack a pair per bar. No strategy, demo or port called it, the legacy sources under strategies/to-migrate included, and the programme’s migrations rest an exit ladder as intents of a controller instead (the swing-breakout migration’s exit-ladder intent, I20a). The owner’s decision of 2026-10-10 (the plan’s Q4) was to delete it with its test rather than keep it as a legacy-only helper. A legacy-profile strategy that wants a per-bar resting pair builds it from the SDK’s constructors and Order.OCOGroup directly.

The account and sizing

HelperWhat it doesOrder lifetimeProfile
Equity(ctx) (kit.go)the account equity from ctx.Account(): the net liquidation in the base currency when the account reports one (a backtest does, every currency converted at the rate in force), zero or negative included; otherwise the USD balance when one is reported, otherwise the sum of every balance; 0 when the account reports nothing, and callers fall back to a fixed size (Currencies)noneboth
BuyingPower(ctx) (kit.go)what the account can still commit at initial margin: the net liquidation less the initial margin the open positions require, when the account reports both (a backtest whose simulator holds margin requirements); otherwise Equity(ctx) (Margin)noneboth
PointValue(ctx, symbol), Tick(ctx, symbol) (kit.go)the instrument’s contract multiplier, 1 when the instrument is unresolved or the value unset; its tick size, 0 when unresolved, which is safe in price-level arithmetic (the offset vanishes)noneboth
RiskPipsQty(ctx, symbol, riskPips) and its pure core RiskPipsQtyFrom(equity, pointValue, riskPips) (sizing.go)the legacy risk-parity sizer four of the migrated strategies and the legacy family share: riskPips basis points of equity over the point value, floored at one contract and capped at four; 1 when the run reports no equity, the accepted degraded modenoneboth
VolTargetConfig, VolTargetQty(ctx, symbol, price, closes, cfg) and its pure core VolTargetQtyFrom (sizing.go)the vol-target and fractional-Kelly sizer two of the market-only production strategies share: a flat fraction of equity, or the annualised volatility target over the realised log-return volatility of closes across RealisedVolLen bars, capped at MaxLeverage and scaled by KellyFraction, converted to whole contracts at price; 0 when equity is unreported or the realised volatility is degenerate, and callers floor it with their minimumnoneboth

Series arithmetic

series.go holds small pure functions over nseries vectors, with no order and no profile: Finite(x), a usable number (neither NaN nor infinite); Clip(x, lo, hi); LogReturns(s) and SimpleReturns(s), the one-bar returns of a price series, 0 where undefined, built for nseries.Series.Func; and the weekly resamplers WeeklyOHLCCompleted(prim) and WeeklyOHLC(prim), which bucket a daily lookback series into ISO weeks, oldest first, the first exposing completed weeks alone (the legacy engine’s weekly view, a week complete on its Friday session bar, the holiday-shortened week the accepted approximation) and the second including the week in progress. Resample in periods.go is the general form for any timeframe and location (Higher timeframes from base bars).

Aligned reads and release-stamped series

These are the helpers of Lining up series; each doc comment names its pairing class (as-of, same-clock or release clock). Data helpers: no order, no profile.

HelperWhat it doesWhere it is explained
AsOfClose(series, cutoff) (tier2.go)the newest close whose bar closed at or before cutoff, and true; (0, false) when there is none: the aligned read of an irregular aux series without leaking a future releaseThe clock and the “as known at” rule
AllFresh(ctx, ids...) (tier2.go)true when every named series’ newest bar closed at ctx.Now() (an empty list vacuously, an unseen id not): the all-inputs-aligned gate of a cross-series strategyMissing bars
AsOfCloses(aux, prim, n), JoinCloses(a, b, n) and ReleaseClock (NewReleaseClock, Observe, Len, Series) (align.go)the three pairing patterns: the slow series carried onto each of the last n primary closes; the closes of the last n bar pairs whose close times match; the aux value and the primary’s last close recorded at each releaseThree patterns
AgeAt(s, now), StaleLegs(now, maxAge, ids, legs), StaleSeries(ctx, maxAge, ids...), Cadence(s, loc) and CompareLegs(a, b, loc) (align.go)how long ago a series’ newest bar closed; the legs that are empty or older than maxAge; a leg’s interval and session end, and whether two legs share themMissing bars
Period (PeriodDay to PeriodYear), ShiftRef(ref, p, k), RefValue(s, ref), PeriodsAgo(s, p, k) and PairByRef(a, b, n) (periods.go)reference-period arithmetic over a release-stamped series, keyed by Ref so that a period that was not published is reported missing rather than skipped overRelease-stamped series
Timeframe (TimeframeDay to TimeframeYear), HTFBar, Resample(s, tf, loc), HTFCloses(bars), PeriodStarts(s, tf, loc) and RequireCloseStamped(s) (periods.go)true resampling of base bars into calendar periods in a location, the completed bars apart from the developing one; one flag per bar for the first bar of its period; the refusal of a series stamped at its startHigher timeframes from base bars

Positioning series

cftc.go addresses the Commitments of Traders series: CFTCCodeForSymbol(symbol) maps a futures symbol in any form (bare, @-prefixed or lake-canonical) to the CFTC contract-market code of its own contract, each code one contract market rather than a commodity-code sum; BareProduct(symbol) reduces a symbol to its bare product root; COTSymbol(code, group) builds cot:CFTC:<code>:<group>; COTLegSymbols(symbol, category) names a category’s long and short legs; LongShortRatio(long, short) is a category’s long positions over its short ones, false when the short side is not positive or a value is not finite; and TFFSymbols and NonUSFutures enumerate the markets reported in the Traders-in-Financial-Futures breakdown and the non-US contracts with no report. Data helpers, no order, no profile; see Release-stamped series: COT, FRED and RBA.

Bars built from the tape, statistics and observations

Three files hold pure helpers over the engine’s event data, each documented with its chapter: eventstats.go over a bar’s construction statistics (AggressorImbalance, AggressorCoverage, AverageTradeSize, VWAPDisplacement, StatColumn, FlowDelta; Construction statistics); marketstats.go over ctx.MarketStatistics and the definitions (OpenInterestChange, SettlementGap, DaysToExpiry; Statistics and definitions as events); and observations.go over an observation history (ObsPoint, ObsLatestKnown, ObsKnownBefore, ObsRevisionSurprise, ObsGrowth; Observations as events). Data helpers, no order, no profile.

Tests

kit_test.go covers StopSuite on both sides, the Tracker’s transitions and its reversal, the weekly resamplers, the sizers, the CFTC codes (each a contract market), Flatten and the stamper; openedat_test.go the Tracker’s adoption after a restart and OpenedAt across an add, a flip and a flat; tier2_test.go LoserCooldown and AsOfClose; tournament_tr5_spec_test.go, kit_reconcile_review_test.go, kit_reconcile_mutation_review_test.go, aa00_rollwindows_tournament_spec_test.go, rom15_rollown_mutation_review_test.go and gle409_combo_test.go the controller; aa00_cs21_exiting_tournament_spec_test.go and cs21r_exiting_review_test.go the exit-once gate; and the tournament_*_spec_test.go files with their review and fixture tests (gle406_review_test.go, gle408_observations_test.go, gle413_cotlegs_test.go among them) the alignment, period, event-statistics, market-statistics, observation and positioning helpers. go test ./strategies/kit/ runs in a few seconds and needs no engine.