Documentation

7. Composing Indicators & Patterns

Created
Jun 5, 2026
Updated
Jun 5, 2026

Both strategies and custom indicators can build on existing studies and pattern detectors. You declare a handle once in init(ctx) and read it per bar in next(ctx). The handles are cursor-bound — they can only read the current bar or earlier, so there is no lookahead.

Consuming an indicator

ctx.useIndicator(id, inputs?) returns a handle with at(n = 0) — the indicator's value n bars back (0 is the current bar), or null before warmup:

init(ctx) {
  this.rsi = ctx.useIndicator("rsi", { length: 14 });
},
next(ctx) {
  const rsi = this.rsi.at(0);     // this bar
  const prev = this.rsi.at(1);    // one bar back
  // ...
}

Use any built-in indicator id (see the Built-in Indicator Library). A common price-source input is source, one of open|high|low|close|hl2|hlc3|ohlc4|median|typical|weighted (default close).

Multi-line indicators

For indicators with several outputs (such as MACD), use ctx.useMultiIndicator(id, inputs?), whose handle takes a field name:

init(ctx) {
  this.macd = ctx.useMultiIndicator("macd", { fastLength: 12, slowLength: 26, signalLength: 9 });
},
next(ctx) {
  const line = this.macd.at("macd", 0);
  const signal = this.macd.at("signal", 0);
  const hist = this.macd.at("histogram", 0);
}

Consuming patterns

ctx.usePattern(kind, params?) returns a handle with firedAt(n = 0) (a pattern became known exactly n bars back) and recent(lookback = 1) (within the last lookback bars). A pattern is only visible once the current bar has reached its breakout bar, so no future geometry leaks into a decision:

init(ctx) {
  this.flag = ctx.usePattern("bullFlag");
},
next(ctx) {
  if (this.flag.recent(2) && ctx.position.side === "flat") {
    ctx.entry("long", { side: "long" });
  }
}

Supported pattern kinds: bullFlag, bearFlag, bullPennant, bearPennant, doubleTop, doubleBottom, tripleTop, tripleBottom, headShoulders, inverseHeadShoulders. See Chart Patterns.

Rules

  • Declare handles only in init(). Calling useIndicator inside next() throws.
  • Composition works the same in custom indicators and in strategies — an indicator can plot a value derived from another indicator, and a strategy can trade on it.
  • A composition cycle resolves to na and terminates safely (no infinite recursion).

Next steps

You have completed the Authoring section. Head to the reference material.

Next: Glossary