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 value n bars back (0 = current), or null before 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 sourceopen|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 last n bars 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 at stop, then activates a limit order at limit.
    • 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 unless reduceOnly is true. Not capped by pyramiding.
  • 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.
    • fromEntry targets a specific entry ID when the run uses closeEntriesRule: "any"; otherwise exits close FIFO.
    • trailOffset/trailPoints create an absolute trailing stop; trailPercent trails 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 explicit qty; siblings without explicit qty are 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).
  • commission with commissionType?: "percent" | "cash-per-order" | "cash-per-contract" (default "percent").
  • slippage as 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(); calling useIndicator in next() 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 from next(), and TypeScript namespace/decorators. Network/host/timer globals (fetch, setTimeout, …) are shadowed to undefined; do not rely on eval. 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.

Next: Composing Indicators & Patterns