AQR is part of the Arkenwell Intelligence Terminal ← Back to Terminal

AQR Docs

AQR (Arkenwell Quant Runtime) is the TypeScript scripting language of Quant Studio, the editor built into the Arkenwell terminal's chart window. Write an indicator, press Ctrl+Enter, and it is computed from the bars of the symbol and timeframe on your chart and drawn there. The same script can be armed as a server-side alert that keeps evaluating with your browser closed.

TypeScript
Full TS syntax with type hints in the Monaco editor.
Live Data
Runs on real OHLCV candles for the current symbol & timeframe.
Sandboxed
Executes in a Web Worker — never blocks the UI.

Coming from…

AQR uses TypeScript — a typed superset of JavaScript. If you already know Pine Script, Python, or any C-style language, you can start writing indicators in minutes. Below is what you need to know based on your background.

TypeScript the language
JavaScript same runtime
Monaco Editor VS Code's editor
Web Worker sandboxed execution

Coming from Pine Script (TradingView)

The concepts are the same; the syntax is TypeScript. Here is the direct mapping:

Pine Script v5
//@version=5
indicator("My Indicator")
var period = input.int(14, title="Period")
myLine = ta.sma(close, period)
plot(myLine, color=color.blue)
close, open, high, low, volume
ta.ema(src, len)
ta.rsi(src, len)
ta.macd(src, f, s, sig)
ta.bb(src, len, mult)
// Runs on every bar — implicit loop
AQR (TypeScript)
defineIndicator({ name: "My Indicator" })
period: input.number({ default: 14, label: "Period" })
const myLine = ak.technical.sma(ctx.candles, period)
return { series: { line: { type:"line", color:"#60A5FA", data:myLine } } }
ctx.candles[i].close / open / high / low / volume
ak.technical.ema(candles, len)
ak.technical.rsi(candles, len)
ak.technical.macd(candles, f, s, sig)
ak.technical.bollingerBands(candles, len, mult)
// Receives full OHLCV array — you map/filter it
The biggest mental shift from Pine Script: Pine Script runs your code on every bar one at a time (implicit loop). AQR receives the entire candle array in one call and returns a complete TimeSeries. Think of it as batch processing instead of streaming.

Pine Script → AQR: worked example

Pine Script v5
//@version=5
indicator("EMA Cross", overlay=true)

fast_len = input.int(9,  title="Fast")
slow_len = input.int(21, title="Slow")

fast = ta.ema(close, fast_len)
slow = ta.ema(close, slow_len)

plot(fast, color=color.green, title="Fast EMA")
plot(slow, color=color.orange, title="Slow EMA")
AQR (TypeScript)
import { defineIndicator, input, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "EMA Cross",
  inputs: {
    fast: input.number({ default: 9,  label: "Fast" }),
    slow: input.number({ default: 21, label: "Slow" }),
  },
  calculate(ctx) {
    const fast = ak.technical.ema(ctx.candles, ctx.inputs.fast as number);
    const slow = ak.technical.ema(ctx.candles, ctx.inputs.slow as number);
    return { series: {
      fast: { type:"line", color:"#34D399", title:"Fast EMA", data:fast },
      slow: { type:"line", color:"#F59E0B", title:"Slow EMA", data:slow },
    } };
  },
});

Coming from Python / pandas-ta / TA-Lib

If you write backtests or indicators in Python, the model is very similar — you receive a DataFrame (here an array), call indicator functions, and return the output series.

Python (pandas-ta)
df["sma20"] = ta.sma(df["close"], length=20)
df["rsi"] = ta.rsi(df["close"], length=14)
macd = ta.macd(df["close"])
# returns DataFrame with MACD_12_26_9, ...
# close prices
df["close"].values
AQR (TypeScript)
ak.technical.sma(ctx.candles, 20)
ak.technical.rsi(ctx.candles, 14)
const m = ak.technical.macd(ctx.candles)
// m.macd, m.signal, m.histogram
// close prices
ctx.candles.map(c => c.close)
Key difference from pandas-ta: AQR functions return a TimeSeries — an array of {time, value} objects, not a raw number array. This is because each value must be timestamped to align with the chart. Use .map(v => v.value) if you need raw numbers for intermediate calculations.

New to quant indicators? (general programmer)

If you know JavaScript, TypeScript, Java, C#, Go, or any C-style language, you already know the syntax. The only new concept is TimeSeries: every indicator function returns an array of timestamped values that the chart engine knows how to draw.

ConceptWhat it meansIn AQR
Candle / Bar One time period of price data { time, open, high, low, close, volume }
TimeSeries Array of (timestamp, value) pairs — what the chart plots Array<{ time, value }>
Indicator A function that transforms candle data into a TimeSeries ak.technical.sma(candles, 20)
Overlay Indicator drawn on top of the price chart All AQR series are currently overlays
Lookback How many bars back an indicator needs to produce its first value Handled automatically — output array starts where data is sufficient
Script input A user-adjustable parameter (like a period length) input.number({ default: 20, label: "Period" })

The mental model in one diagram

LIVE MARKET
NIFTY / BANKNIFTY
→
ctx.candles
CandleData[]
→
calculate(ctx)
your TypeScript
→
series { … }
TimeSeries[]
→
CHART
overlaid lines

TypeScript syntax cheatsheet

If you're new to TypeScript, here are the three patterns you need for AQR:

// 1. Variables — use const (never var)
const period = 20;
const prices = ctx.candles.map(c => c.close);   // arrow function

// 2. Type assertion — "trust me, this is a number"
ctx.inputs.period as number   // needed because inputs are typed as unknown

// 3. Array methods — filter, map, reduce (same as JavaScript)
const closes = ctx.candles.map(c => ({ time: c.time, value: c.close }));
const above = closes.filter(v => v.value > 24000);

Quick Start

From zero to a running indicator in 4 steps:

1

Open the AQR editor

On the main chart page, click AQR in the bottom toolbar to expand the editor panel. You'll see a Monaco editor pre-loaded with a default SMA script.

2

Press ▶ Run

Click the ▶ Run button (or Ctrl+Enter). The default SMA indicator plots a blue line over the price chart immediately.

3

Edit the script

Change period: 20 to period: 50 and run again — the line updates. Modify the color, add more series, or swap in a different function like ak.technical.ema.

4

Save your script

Click Save in the toolbar, give it a name, and it persists across sessions. Open it anytime from SCRIPTS (your library).

Script Structure

Every AQR script follows this exact pattern:

import { defineIndicator, input, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "My Indicator",           // shown in the toolbar

  inputs: {                          // optional — creates toolbar controls
    period: input.number({ default: 20, min: 1, max: 500, label: "Period" }),
  },

  calculate(ctx) {              // called once on every Run
    const data = ak.technical.sma(ctx.candles, ctx.inputs.period as number);

    return {
      series: {
        myLine: {
          type:  "line",
          color: "#60A5FA",
          title: "SMA",
          data:  data,
        },
      },
    };
  },
});

Three rules

  • The file must have a default export using defineIndicator(...).
  • calculate(ctx) must return an object with a series key.
  • Each series data array must be a TimeSeries: Array<{time, value}>.

Workflow

ActionHow
Run script▶ Run or Ctrl+Enter. AUTO-RUN re-runs 1 s after you stop typing.
See problemsMistakes are underlined as you type (before running). The status bar shows ✕ errors ! warnings — click it for the Problems list.
AutocorrectPut the cursor on an underline and press Ctrl+., click Fix on a Problems row, or AUTOCORRECT ALL. Every fix is one Ctrl+Z away.
Tune valuesPARAMS lists your declared inputs and the numbers/colours detected in your code. See Inputs & detected values.
TemplatesTEMPLATES — SMA, EMA cross, RSI, MACD, Bollinger, VWAP, ATR channel and more; every template passes the editor's checks.
Save / loadCtrl+S or SAVE (saved to your account, server-side); SCRIPTS opens your library.
Put it on the chartADD TO CHART after a clean run. It then appears in the chart legend like any indicator.
Resize / focusDrag the handle above the editor; the maximise button opens a fullscreen studio (Esc exits).

Where scripts run

SurfaceHow to openWhat it runs on
Terminal — chart windowOpen any chart → QUANT STUDIO in the chart headerThe chart's own bars (symbol + timeframe), in a Web Worker in your browser
Terminal — script alertsAlerts → condition "Custom script", pick a saved scriptThe same script on the Arkenwell server (quant-runtime sidecar), with the inputs frozen at arm time
One implementation, two runtimes

Both runtimes load the same ak.technical implementation, so an alert computes exactly the value you see on the chart. That is also why scripts must be deterministic: Math.random() or Date.now() would make the chart and the alert disagree (the editor flags both, AQR-051).


Context Object — ctx

The calculate(ctx) function receives one argument: the execution context.

ctx.candles

An array of OHLCV bars for the current symbol and timeframe, newest bar last.

type CandleData = {
  time:   number | string;  // Unix timestamp or YYYY-MM-DD
  open:   number;
  high:   number;
  low:    number;
  close:  number;
  volume: number;
};

Example — read the last close price:

const last = ctx.candles[ctx.candles.length - 1].close;

ctx.inputs

A key-value map of your declared inputs at runtime — keys match what you defined in inputs: {...}.

// If you declared: period: input.number({ default: 20 })
const period = ctx.inputs.period as number;  // → 20 (or whatever the user set)

ak.technical — Built-in Functions

Every function takes candles: CandleData[] first (usually ctx.candles). TimeSeries means { time, value }[], which can be passed straight to a series' data. Functions marked with an object return (macd, bollingerBands, vwapBands, stochastic) must be unpacked — data: ak.technical.macd(c).macd, not data: ak.technical.macd(c) (AQR-014 autocorrects this).

In the editor, hover any function name for this reference, and type ak.technical. for completion.

ak.technical.sma(candles, period)

Simple moving average of close over period bars. First value appears at bar period.

TimeSeries
const r = ak.technical.sma(ctx.candles, 20);

ak.technical.ema(candles, period)

Exponential moving average of close, α = 2 / (period + 1), seeded with the SMA of the first period bars.

TimeSeries
const r = ak.technical.ema(ctx.candles, 20);

ak.technical.rsi(candles, period = 14)

Wilder's Relative Strength Index. >70 is conventionally overbought, <30 oversold.

TimeSeries (0–100)
const r = ak.technical.rsi(ctx.candles, 14);

ak.technical.macd(candles, fast = 12, slow = 26, signal = 9)

MACD line = EMA(fast) − EMA(slow); signal = EMA(signal) of the MACD line; histogram = MACD − signal. Returns an OBJECT — pass .macd, .signal or .histogram as series data.

{ macd, signal, histogram }
const r = ak.technical.macd(ctx.candles, 12, 26, 9);

ak.technical.bollingerBands(candles, period = 20, stdDev = 2)

SMA(period) ± stdDev × population standard deviation of close. basis is an alias of mid.

{ upper, mid, lower }
const r = ak.technical.bollingerBands(ctx.candles, 20, 2);

ak.technical.vwap(candles)

Cumulative volume-weighted average of typical price (H+L+C)/3 from the FIRST candle passed. Bars without volume add no weight. For bands use vwapBands().

TimeSeries
const r = ak.technical.vwap(ctx.candles);

ak.technical.vwapBands(candles)

VWAP with ±1 volume-weighted standard deviation bands.

{ vwap, upper, lower }
const r = ak.technical.vwapBands(ctx.candles);

ak.technical.atr(candles, period = 14)

Average True Range (Wilder smoothing) — volatility in price units.

TimeSeries
const r = ak.technical.atr(ctx.candles, 14);

ak.technical.stddev(candles, period = 20)

Rolling population standard deviation of close.

TimeSeries
const r = ak.technical.stddev(ctx.candles, 20);

ak.technical.superTrend(candles, period = 10, multiplier = 3)

ATR-based trailing stop. Each point carries trend ("UP"/"DOWN") and a matching color; map to { time, value } for a line, or keep color for per-point colouring.

{ time, value, trend, color }[]
const r = ak.technical.superTrend(ctx.candles, 10, 3);

ak.technical.stochastic(candles, kPeriod = 14, dPeriod = 3)

%K = position of close within the kPeriod high–low range (0–100); %D = SMA(dPeriod) of %K.

{ k, d }
const r = ak.technical.stochastic(ctx.candles, 14, 3);

ak.technical.williamsR(candles, period = 14)

Williams %R: where close sits in the period range, scaled −100 (low) to 0 (high).

TimeSeries (−100–0)
const r = ak.technical.williamsR(ctx.candles, 14);

ak.technical.cci(candles, period = 20)

Commodity Channel Index: (typical − SMA) / (0.015 × mean deviation).

TimeSeries
const r = ak.technical.cci(ctx.candles, 20);

ak.technical.roc(candles, period = 10)

Rate of change: percent change of close versus period bars ago.

TimeSeries (%)
const r = ak.technical.roc(ctx.candles, 10);

ak.technical.pivotPoints(candles)

Classic floor pivots from the PREVIOUS bar (second-to-last). Returns plain numbers, not series; null with fewer than 2 bars.

{ pp, r1, r2, r3, s1, s2, s3 } | null
const r = ak.technical.pivotPoints(ctx.candles);

ak.technical.heikinAshi(candles)

Heikin-Ashi transformed bars — feed them to any other function, e.g. ema(heikinAshi(ctx.candles), 20).

CandleData[]
const r = ak.technical.heikinAshi(ctx.candles);
Changed in this version

vwap() now returns the series itself (as documented); scripts that used vwap(c).vwap keep working and the editor offers to simplify them (AQR-015). bollingerBands() now provides mid (the documented name) alongside basis. vwapBands, superTrend, stochastic, williamsR, cci, roc, pivotPoints and heikinAshi are available in scripts on the chart and in server alerts.

input — Toolbar Controls

Declare inputs inside defineIndicator({ inputs: {...} }) and they automatically appear as interactive controls in the toolbar. Users can change them and re-run without editing code.

input.number(config)

Creates a numeric input with an optional min/max/step.

period: input.number({
  default: 20,
  min:     1,
  max:     500,
  step:    1,          // optional
  label:   "Period",   // shown in toolbar
})

Read it: ctx.inputs.period as number

input.boolean(config)

Creates a checkbox toggle.

showSignal: input.boolean({
  default: true,
  label:   "Show Signal",
})

Read it: ctx.inputs.showSignal as boolean

input.select(config)

Creates a dropdown with fixed options.

source: input.select({
  options: ["close", "open", "high", "low"],
  default: "close",
  label:   "Source",
})

Read it: ctx.inputs.source as string

Output — what calculate(ctx) returns

calculate(ctx) returns an object with any of these keys. Everything you return is drawn on the chart, and every part except series styling and tables can drive an alert.

return {
  series: {                       // lines / histograms / areas
    fast: { type: "line", data: ema9, color: "#38BDF8", title: "EMA 9" },
    osc:  { type: "histogram", data: hist, pane: "new" },   // own pane below
  },
  levels:  [{ price: 23500, color: "#EF4444", label: "Resistance" }],
  zones:   [{ priceTop: 23420, priceBottom: 23380, color: "#10B981", label: "Demand" }],
  markers: [{ time: bar.time, position: "above", shape: "arrowDown", color: "#D48A1F", text: "Sell" }],
  signals: [{ type: "bullish", strength: 0.8, reason: "EMA 9 above EMA 21" }],
};

series — one entry per plotted line

FieldValuesNotes
type"line" · "histogram" · "area"Required. Anything else is AQR-040 (e.g. "lines" → "line").
data{ time, value, color? }[]Ascending by time. A per-point color colours that bar/segment.
pane"overlay" (default) · "new""new" gives the series its own pane below price — use it for oscillators (RSI, MACD, %R).
paneGroupany stringSeries with the same group share one new pane (e.g. MACD line + signal).
color#RRGGBB, #RRGGBBAA, rgba()Invalid colours fall back to the default (AQR-042).
lineWidth1–4Line/area only.
lineStyle0 solid · 1 dotted · 2 dashed · 3 large dashed · 4 sparse dottedLine/area only.
titlestringAxis label and legend name.

levels · zones · markers

KeyDrawn asAlertable
levelsDashed price line with an axis labelYes — by label (keep labels stable between runs)
zonesShaded band with dotted edges and a label chipYes — enter / exit, by label
markersShape above/below a bar: "circle", "arrowUp", "arrowDown"Yes — a marker printed on the latest bar

signals — the script's verdict

{ type: "bullish" | "bearish" | "neutral", strength: 0–1, reason }. Alerts read the last entry and fire when the verdict flips (optionally above a minimum strength). "buy" / "sell" are not signal types — AQR-043 converts them.


Example — Simple Moving Average

The simplest possible overlay. One line, one input, overlays on price.

import { defineIndicator, input, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "SMA",
  inputs: {
    period: input.number({ default: 20, min: 1, max: 500, label: "Period" }),
  },
  calculate(ctx) {
    const sma = ak.technical.sma(ctx.candles, ctx.inputs.period as number);
    return {
      series: {
        sma: { type: "line", color: "#60A5FA", title: "SMA", data: sma },
      },
    };
  },
});

Example — EMA Crossover (9 / 21)

Two EMAs. Fast above slow = bullish. Fast below slow = bearish. Both inputs are adjustable from the toolbar.

import { defineIndicator, input, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "EMA Cross",
  inputs: {
    fast: input.number({ default: 9,  min: 2, max: 100, label: "Fast" }),
    slow: input.number({ default: 21, min: 5, max: 200, label: "Slow" }),
  },
  calculate(ctx) {
    const fast = ak.technical.ema(ctx.candles, ctx.inputs.fast as number);
    const slow = ak.technical.ema(ctx.candles, ctx.inputs.slow as number);
    return {
      series: {
        fast: { type: "line", color: "#34D399", title: "EMA Fast", data: fast },
        slow: { type: "line", color: "#F59E0B", title: "EMA Slow", data: slow },
      },
    };
  },
});

Example — RSI (14)

Momentum oscillator. Values appear overlaid on the price chart — look for the purple line near the bottom.

import { defineIndicator, input, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "RSI",
  inputs: {
    period: input.number({ default: 14, min: 2, max: 100, label: "Period" }),
  },
  calculate(ctx) {
    const rsi = ak.technical.rsi(ctx.candles, ctx.inputs.period as number);
    return {
      series: {
        rsi: { type: "line", color: "#A78BFA", title: "RSI", data: rsi },
      },
    };
  },
});

Example — MACD

Classic trend-following indicator. Three series: MACD line, signal line, histogram bars.

import { defineIndicator, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "MACD",
  calculate(ctx) {
    const result = ak.technical.macd(ctx.candles, 12, 26, 9);
    return {
      series: {
        macd:      { type: "line",      color: "#60A5FA", title: "MACD",      data: result.macd      },
        signal:    { type: "line",      color: "#F59E0B", title: "Signal",    data: result.signal    },
        histogram: { type: "histogram", color: "#10B981", title: "Histogram", data: result.histogram },
      },
    };
  },
});

Example — Bollinger Bands

Three lines that form a price envelope. Price touching the outer bands can signal mean-reversion. Narrow bands = low volatility.

import { defineIndicator, input, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "Bollinger Bands",
  inputs: {
    period: input.number({ default: 20, min: 5, max: 200, label: "Period" }),
    stddev: input.number({ default: 2,  min: 1, max: 5,   label: "Std Dev" }),
  },
  calculate(ctx) {
    const bb = ak.technical.bollingerBands(
      ctx.candles,
      ctx.inputs.period as number,
      ctx.inputs.stddev as number
    );
    return {
      series: {
        upper: { type: "line", color: "#60A5FA", title: "BB Upper", data: bb.upper },
        mid:   { type: "line", color: "#94A3B8", title: "BB Mid",   data: bb.mid   },
        lower: { type: "line", color: "#60A5FA", title: "BB Lower", data: bb.lower },
      },
    };
  },
});

Example — VWAP

Volume-Weighted Average Price — used by professional traders as a fair-value benchmark.

import { defineIndicator, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "VWAP",
  calculate(ctx) {
    const vwap = ak.technical.vwap(ctx.candles);
    return {
      series: {
        vwap: { type: "line", color: "#F59E0B", title: "VWAP", data: vwap },
      },
    };
  },
});

Example — Multiple Series on One Script

You can output as many series as you like from a single script — useful for composite indicators.

import { defineIndicator, input, ak } from "@arkenwell/quant";

// SMA ribbon — three SMAs at once
export default defineIndicator({
  name: "SMA Ribbon",
  calculate(ctx) {
    const s20  = ak.technical.sma(ctx.candles, 20);
    const s50  = ak.technical.sma(ctx.candles, 50);
    const s200 = ak.technical.sma(ctx.candles, 200);
    return {
      series: {
        sma20:  { type: "line", color: "#34D399", title: "SMA 20",  data: s20  },
        sma50:  { type: "line", color: "#60A5FA", title: "SMA 50",  data: s50  },
        sma200: { type: "line", color: "#F87171", title: "SMA 200", data: s200 },
      },
    };
  },
});

Example — Custom Logic (Midpoint Line)

AQR gives you the full candle array. You can write any calculation you want — loop over bars, compute custom values, build your own indicator from scratch.

import { defineIndicator } from "@arkenwell/quant";

// Midpoint = (high + low) / 2 for each candle
export default defineIndicator({
  name: "Midpoint",
  calculate(ctx) {
    const midpoint = ctx.candles.map(c => ({
      time:  c.time,
      value: (c.high + c.low) / 2,
    }));

    return {
      series: {
        mid: { type: "line", color: "#A78BFA", title: "Midpoint", data: midpoint },
      },
    };
  },
});

Another example — percentage distance of close from VWAP:

import { defineIndicator, ak } from "@arkenwell/quant";

export default defineIndicator({
  name: "VWAP Deviation %",
  calculate(ctx) {
    const vwap = ak.technical.vwap(ctx.candles);

    // Build a lookup map for VWAP values by time
    const vwapMap = new Map(vwap.map(v => [v.time, v.value]));

    const deviation = ctx.candles
      .filter(c => vwapMap.has(c.time))
      .map(c => ({
        time:  c.time,
        value: +((c.close - vwapMap.get(c.time)!) / vwapMap.get(c.time)! * 100).toFixed(3),
      }));

    return {
      series: {
        dev: { type: "histogram", color: "#60A5FA", title: "VWAP Dev %", data: deviation },
      },
    };
  },
});


Problems & Autocorrect

Quant Studio checks your script on every keystroke — before compiling or running — and underlines each mistake where it is. Hover an underline for the explanation. Where the intent is unambiguous, the check carries a fix:

  • Ctrl+. on an underline → Autocorrect: …
  • Fix on a row of the Problems list (click the row to jump to the code)
  • AUTOCORRECT ALL — applies every fix, re-checking between fixes so they never collide; Ctrl+Z undoes it

Runtime errors (which have no line number) come with a hint naming the usual cause, e.g. reading .value of an object-returning function.

CodeWhat it catchesAutocorrect
AQR-001Import from anything other than @arkenwell/quantClose misspellings → @arkenwell/quant
AQR-002defineIndicator / input / ak used but not importedAdds them to the import (or adds the import)
AQR-003No defineIndicator({…})—
AQR-004Indicator not exportedAdds export default
AQR-005 / 006No calculate(ctx), or it never returns—
AQR-010Unknown ak.technical function (typos, Pine/TA-Lib names like bbands, supertrend, stoch)Nearest real function
AQR-011 / 012 / 013Period < 1, fractional period, missing periodValid value
AQR-014Object result (macd, bollingerBands, …) passed as dataPicks .macd / .mid / .k / .vwap
AQR-015Legacy vwap(c).vwap / .upper1 / .lower1Simplifies / switches to vwapBands
AQR-020 / 021 / 022ctx.close, ctx.candle, ctx.candles.closectx.candles.map(c => c.close) / nearest ctx field
AQR-030ctx.inputs.x read but never declared (it would be undefined)Nearest declared name, or declares x
AQR-031 / 032input.number without a default, or default outside min/maxAdds a default
AQR-040 … 045Invalid series type, pane, colour, signal type, marker shape or positionNearest valid value
AQR-050Browser/network APIs that do not exist in the sandbox (fetch, window, timers, storage…)—
AQR-051Non-deterministic code (Math.random, Date.now)—

Checks never look inside comments or strings, and every built-in template passes them.

Inputs & detected values

PARAMS shows two kinds of tunable value:

KindWhere it comes fromEditing it
Declared inputsinputs: { period: input.number({ … }) }Changes the value passed in ctx.inputs; your code is untouched. Saved with alerts at arm time.
Detected in codeNumbers you pass to ak.technical (e.g. the 9 in ema(c, 9)) and colour literals in your outputRewrites exactly that literal in the code and re-runs

→ INPUT on a detected number promotes it to a real input: the literal becomes ctx.inputs.emaPeriod as number and emaPeriod: input.number({ default: 9, … }) is added to inputs.

On the chart

Once added, a script behaves like the built-in indicators:

  • Legend (top-left of the chart): eye = hide without removing, gear or click the name = settings, × = remove.
  • Click a plotted line to select that indicator and open its settings.
  • Style tab: per-series colour (palette, hex, opacity), width and solid/dashed/dotted. These overrides are stored with your chart preferences and applied on top of the colours in your code; Defaults clears them.
  • Inputs and logic stay in the script — Open in Quant Studio from the same card.

Built-in indicators (EMA, SMA, Bollinger, VWAP, SuperTrend, Pivots, RSI, MACD, Stochastic, CCI, ROC, %R) use the same card: an Inputs tab with every parameter (length, multiplier, RSI levels, MACD fast/slow/signal …) and a Style tab.

Keyboard Shortcuts

ShortcutAction
Ctrl+EnterRun the script
Ctrl+ZUndo in editor
Ctrl+/Toggle line comment
Ctrl+DSelect next occurrence of word
Alt+↑ / ↓Move line up / down
EscapeClose Save / Help modal
Tip — Focus safety

Keyboard shortcuts on the main chart (1–5 for timeframes, etc.) are blocked while your cursor is inside the AQR editor, so typing in the editor never accidentally switches the chart view.

Run-time Error Codes

These come from compiling or executing the script and appear in the console as [ARK-008] Cannot read properties of undefined (reading 'value'), followed by a hint. Most are caught earlier by the AQR checks.

CodeMeaningUsual fix
ARK-001Import not allowedOnly @arkenwell/quant can be imported (AQR-001)
ARK-002Compile failed (syntax)The line & column are marked in the editor — usually a missing bracket or comma
ARK-003Execution timed outA loop that never ends, or O(n²) work over all bars — see limits
ARK-004No default exportexport default defineIndicator({…}) (AQR-004)
ARK-005calculate() did not return an objectReturn { series: … } (AQR-006)
ARK-006No calculate functionAdd calculate(ctx) { … } (AQR-005)
ARK-007Data unavailableThe chart has no bars loaded for this symbol/timeframe yet
ARK-008Runtime exception inside your codeRead the hint under the error
ARK-009Invalid input valueCheck min/max/options of the input
ARK-010Output too largeMore than 50 000 points in total — return fewer series or fewer bars

Runtime Limits

LimitValueNotes
Max execution time3 000 msPer Run — script is killed after this
Max output points50 000Total across all series
Max candlesDepends on timeframeThe chart sends all loaded candles
Network accessBlockedScripts run in a sandboxed Web Worker (chart) or node:vm (alerts) — no fetch
DOM accessBlockedNo document or window
Saved scriptsUnlimitedSaved to your Arkenwell account — accessible from any device, any browser
Scripts are saved to your account

Scripts are stored server-side in the Arkenwell database, tied to your user account. They persist across browsers, devices, and sessions — log in from anywhere and your scripts are there. You must be logged in to save; the editor will show an error in the console if the save fails.