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
| Helper | What it does | Order lifetime | Profile |
|---|---|---|---|
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 series | none | both |
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-zero | a 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 it | both |
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 alone | reads 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 gate | both |
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-safe | none: 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 itself | both |
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 it | one 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 for | both |
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 makes | none beyond the trade state’s transitions | both |
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 level | none: it rests nothing. The exit the strategy answers a breach with is a market order, so it is Flatten’s and Exiting’s | both |
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 controller | the v2 contract: it reads the attempt-indexed view and submits at the lifecycle turns, neither of which is authoritative on a legacy run | v2 |
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
| Helper | What it does | Order lifetime | Profile |
|---|---|---|---|
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) | none | both |
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) | none | both |
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) | none | both |
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 mode | none | both |
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 minimum | none | both |
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.
| Helper | What it does | Where 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 release | The 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 strategy | Missing 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 release | Three 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 them | Missing 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 over | Release-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 start | Higher 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.