Documentation
6. Strategy API Reference
- Created
- Jun 5, 2026
- Updated
- Jun 5, 2026
This is the full strategy API. Author a strategy as a TypeScript/JavaScript module that export defaults an object implementing the Strategy interface. The engine walks bars oldest → newest and is event-driven: orders you submit in next() on bar i are filled by the broker on bar i+1 (market orders at the next open). There is no lookahead — indicator and bar accessors can only read the current bar or earlier.
Shape
export default {
name: "My Strategy",
init(ctx) {
// Declare indicators/patterns ONCE here. Store handles on `this`.
this.fast = ctx.useIndicator("sma", { length: 10 });
this.slow = ctx.useIndicator("sma", { length: 30 });
},
next(ctx) {
const f = this.fast.at(0), s = this.slow.at(0); // current values
const fp = this.fast.at(1), sp = this.slow.at(1); // one bar back
if (f == null || s == null || fp == null || sp == null) return; // warmup
if (fp <= sp && f > s) ctx.entry("long", { side: "long" }); // golden cross
else if (fp >= sp && f < s) ctx.close("death cross"); // exit
}
};
init(ctx) — runs once before the loop
ctx.useIndicator(id, inputs?)→{ at(n=0) }— single-line indicator;at(n)is the valuenbars back (0= current), ornullbefore warmup.ctx.useMultiIndicator(id, inputs?)→{ at(field, n=0) }— multi-line indicator (e.g.macd→ fields"macd","signal","histogram").ctx.usePattern(kind, params?)→{ firedAt(n=0), recent(lookback=1) }— detected chart patterns.
A common price-source input is source ∈ open|high|low|close|hl2|hlc3|ohlc4|median|typical|weighted (default close). Supported pattern kinds: bullFlag, bearFlag, bullPennant, bearPennant, doubleTop, doubleBottom, tripleTop, tripleBottom, headShoulders, inverseHeadShoulders. The set of usable indicator ids comes from the Built-in Indicator Library. See Composing Indicators & Patterns.
next(ctx) — runs once per bar
ctx.bar— current bar{ time, open, high, low, close, volume? }.ctx.index— current bar index.ctx.bars(n)— the lastnbars up to and including the current bar.ctx.position—{ size, side: "long"|"short"|"flat", avgPrice, openPnl }.ctx.equity,ctx.cash— account state (mark-to-close).
Orders
ctx.entry(id, { side, type?, price?, stop?, limit?, qty?, percent?, cash?, ocaName?, ocaType? })- Market (default) fills at the next open; limit/stop fill only if a later bar trades through the requested price.
type: "stop-limit"triggers atstop, then activates a limit order atlimit.- Pyramiding defaults to 1 same-direction entry; an opposite-direction entry reverses.
- If a limit/stop price is crossed in the gap from prior close to current open, the fill occurs at the current open.
- Sizing precedence:
qty>cash>percent> run-config sizing.
ctx.order(id, { side, type?, price?, stop?, limit?, qty?, percent?, cash?, reduceOnly?, reason?, ocaName?, ocaType? })- Lower-level order:
side: "long"buys,side: "short"sells. Nets against an opposite position first; remaining quantity opens in the order direction unlessreduceOnlyis true. Not capped by pyramiding.
- Lower-level order:
ctx.exit(id, { fromEntry?, qty?, percent?, stop?, limit?, trailOffset?, trailPoints?, trailPercent?, reason?, ocaName?, ocaType? })- Named Pine-like exit. Omitted stop/limit/trailing fields create a market exit; stop/limit create a standing protective exit.
fromEntrytargets a specific entry ID when the run usescloseEntriesRule: "any"; otherwise exits close FIFO.trailOffset/trailPointscreate an absolute trailing stop;trailPercenttrails by a percentage of the best favorable price.
ctx.close(reasonOrOpts?)— flatten next bar at market, or pass{ stop?, limit?, trailOffset?, trailPercent?, reason? }for protective exits.ctx.closeAll(reasonOrOpts?)— flatten all open entries.ctx.cancel(id?)/ctx.cancelAll()— cancel pending unfilled orders.
OCA / OCO groups
- Any pending entry/order/exit can join a group with
ocaName. ocaType: "cancel"is one-cancels-all (OCO bracket) behavior.ocaType: "reduce"reduces sibling orders by the filled quantity when siblings have explicitqty; siblings without explicitqtyare canceled because their size cannot be safely reduced.
Advanced order examples
// Stop-limit breakout: trigger at stop, then fill only at limit or better.
ctx.entry("breakout", {
side: "long",
type: "stop-limit",
stop: ctx.bar.close * 1.02,
limit: ctx.bar.close * 1.025,
qty: 1
});
// Lower-level reduce-only sell: trim an existing long without opening short.
ctx.order("trim", {
side: "short",
qty: Math.abs(ctx.position.size) / 2,
reduceOnly: true,
reason: "trim"
});
// Trailing exit, absolute price distance.
ctx.exit("trail", { trailOffset: 2.5, reason: "trailing stop" });
// OCO bracket: whichever exit fills cancels the sibling.
ctx.exit("target", { limit: ctx.position.avgPrice * 1.08, reason: "target", ocaName: "main-bracket", ocaType: "cancel" });
ctx.exit("stop", { stop: ctx.position.avgPrice * 0.96, reason: "stop", ocaName: "main-bracket", ocaType: "cancel" });
Run config
These map to the Strategy & Test Settings:
initialCash(default 10000).commissionwithcommissionType?: "percent" | "cash-per-order" | "cash-per-contract"(default"percent").slippageas a fill-price fraction.sizing: { mode: "percent-equity" | "fixed-cash" | "fixed-qty", value }.pyramiding— maximum same-direction open entries (default 1).processOrdersOnClose— allow market orders created on a bar to fill on that bar's close.closeEntriesRule: "fifo" | "any"— whether exits close oldest entries first or can target entry IDs.
Rules
- Declare indicators only in
init(); callinguseIndicatorinnext()throws. - Author in TypeScript or JavaScript (types are stripped, not type-checked) — the same engine custom indicators use. Rejected up front:
import,async/await, returning a Promise fromnext(), and TypeScriptnamespace/decorators. Network/host/timer globals (fetch,setTimeout, …) are shadowed toundefined; do not rely oneval. See Authoring Language & Syntax. - Keep loops bounded; the run is killed after a wall-clock timeout.
Next steps
Learn how indicators and patterns are wired into a strategy.