---
title: "Next steps"
description: "You built your first Indicator. Here is where to go next, framed by what you will want to do. You have a working crossover and you understand the three parts…"
order: 7
section: "getting-started"
---

<!-- source: docs/indicators/getting-started/primer-next-steps.md; generated by packages/cli/scripts/gen-indicator-docs.ts, do not edit -->

# Next steps

You built your first Indicator. Here is where to go next, framed by what you
will want to do. You have a working crossover and you understand the three
parts every Indicator shares: declarations, state, and the four functions.
From here, pick the path that matches what you want to do next.

## Where to go from here

- **Want to build something real?** The [Cookbook](../cookbook/overview.md)
  has complete, copy-ready recipes for genuinely useful Indicators, each
  shown next to the kScript (legacy) recipe it came from: a volume spike
  detector, an anchored VWAP, a no-repaint regime filter, a zone tracker,
  key levels, and cumulative volume delta. Each one is a finished file you
  can read end to end and adapt.

- **Want to understand how your code actually runs?**
  [Execution model](../core-concepts/execution-model.md) explains how the
  host walks your file bar by bar, oldest bar to newest, why the first bars
  of a line are empty, and what "no lookahead" means when you write the
  code. Once this clicks, keeping a previous value in a variable instead of
  indexing `close[1]` will feel obvious.

- **Want to take it off the chart?** [Quick start](quick-start.md) is the
  same file on your machine: scaffold, build, install, and read every output
  as a metric with `om metric series`, then arm a watch condition on it. That
  is the path to alerts, screens, series, and backtests.

- **Ready for the part kScript could not do?**
  [Multi-source and aggregation](../core-concepts/multi-source.md) shows how
  a package reads other markets and other venues through pinned inputs and
  combines them with ordinary arithmetic, and
  [Data sources](../core-concepts/data-sources.md) lists every feed and
  celled class, footprints and order books included.

- **Looking for the right function?** The [TA library](../functions/ta-library.md)
  is the catalog of stateful classes, one per kScript (legacy) TA builtin
  (`Sma`, `Ema`, `Rsi`, `Macd`, `Atr`, `Supertrend`, `Vwap`, and the rest). The
  [Plotting](../functions/plotting.md) reference covers every way to draw:
  lines, bars, histograms, candles, marks, boxes, segments, labels, and
  tables.

- **Something not working?** [Common errors](../faq/common-errors.md) lists
  the messages you are most likely to hit, in the order the build produces
  them, what causes each, and how to fix it. If your file compiled but drew
  nothing, start there (it is almost always warm-up).

## Try this first

The best next step is to open the editor and change something. Take your
crossover and add the mark for crosses the other way: a second `Cross`
answer, a second gate, a second `shape` output at the bar's high. This is
the finished exercise; compare it with your own before reading it.

```typescript
import { input, line, none, ohlcv, output, overlay, param, shape } from "./sdk/declare";
import { in_close, in_high, in_low } from "./gen/inputs";
import { emitRow, out_cross_down, out_cross_up, out_fast, out_is_cross_down, out_is_cross_up, out_slow } from "./gen/outputs";
import { p_fast, p_slow } from "./gen/params";
import { Cross, Ema } from "./sdk/ta";

param("fast", 9, { min: 1, max: 200, description: "Fast EMA length" });
param("slow", 21, { min: 2, max: 400, description: "Slow EMA length" });
input("close", ohlcv.close);
input("high", ohlcv.high);
input("low", ohlcv.low);
output("fast", line, overlay, { color: "#2563eb", width: 2, description: "Fast EMA" });
output("slow", line, overlay, { color: "#f97316", width: 2, description: "Slow EMA" });
output("cross_up", shape, overlay, { color: "#16a34a", shape_where: "is_cross_up", description: "Fast crossed above slow" });
output("cross_down", shape, overlay, { color: "#dc2626", shape_where: "is_cross_down", description: "Fast crossed below slow" });
output("is_cross_up", none);
output("is_cross_down", none);

let fast = new Ema(9);
let slow = new Ema(21);
let cross = new Cross();
let fastValue: f64 = NaN;
let slowValue: f64 = NaN;
let high: f64 = NaN;
let low: f64 = NaN;
let crossed: i32 = 0;

export function init(): void {
  fast = new Ema(i32(p_fast()));
  slow = new Ema(i32(p_slow()));
  cross = new Cross();
}

export function state(): i32 {
  const close = in_close();
  high = in_high();
  low = in_low();
  fastValue = fast.update(close);
  slowValue = slow.update(close);
  crossed = cross.update(fastValue, slowValue); // +1 up, -1 down, 0 otherwise
  return isNaN(slowValue) ? 0 : 1;
}

export function finalize(): void {
  out_fast(fastValue);
  out_slow(slowValue);
  out_cross_up(low); // the up mark sits under the candle
  out_cross_down(high); // the down mark sits above it
  out_is_cross_up(crossed == 1 ? 1.0 : 0.0);
  out_is_cross_down(crossed == -1 ? 1.0 : 0.0);
  emitRow();
}

export function reset(): void {
  fast.reset();
  slow.reset();
  cross.reset();
  fastValue = NaN;
  slowValue = NaN;
  high = NaN;
  low = NaN;
  crossed = 0;
}
```

Then put the fast average in its own pane, or swap the marks for a
`position` output that stays `1` between an up cross and a down cross. You
learn Indicators by writing them, and the compiler tells you the line when
a change does not fit.
