TradingCharts

Script Structure

A ChartScript source follows this general shape:

Version annotation

The first non-comment line of a script may be a version annotation:

//@version=1
  • Any integer is accepted. The compiler's behaviour does not change by version: ChartScript shares its grammar surface with the reference v5/v6 language, and scripts written for //@version=4, 5 or 6 compile unchanged thanks to the v1–v4 compatibility aliases below. The editor's templates write //@version=1.
  • When omitted, the compiler accepts the script without warning (version is a hint, not a gate).
  • The annotation is a comment and can only appear once; placing it at the very top is strongly recommended.

Declaration statement

Every script contains exactly one declaration statement. It identifies the kind of script and sets properties that cannot change at runtime (title, overlay-vs-pane, number of drawing objects, strategy capital, etc.):

indicator("My indicator", overlay=true)
strategy("My strategy", default_qty_type=strategy.cash, default_qty_value=10_000, initial_capital=100_000)
library("MyLibrary")
  • indicator() — a visual script. Renders plots, shapes, drawings, tables.
  • strategy() — an indicator with position-management (strategy.entry/exit/close) that produces trades and a backtest report.
  • library() — a bundle of exported functions, types, and enums that other scripts can import.

A legacy alias is accepted: study("…") compiles exactly like indicator("…").

Body

The body is a sequence of statements. A statement is a declaration, an assignment, an expression (whose value is discarded), or a block-opening keyword (if, for, while, switch, once).

//@version=1
indicator("Example", overlay=true)

length = input.int(14, "Length", minval=1)
src    = input.source(close, "Source")

ma     = ta.sma(src, length)
dir    = close > ma ? 1 : -1

plot(ma, "MA", color=color.aqua, linewidth=2)

One statement per line (continuations)

A statement normally runs to the end of its line. Two cases let you spread a statement over several lines:

1. Line-leading continuation operators. When the next line begins with one of these operators (followed by a space or quote), it continues the previous statement:

==   !=   <=   >=   ?    :
+   -   *   %   /
and   or
total = volume
      + volume[1]
      + volume[2]

2. Unclosed brackets. Lines inside ( ), [ ], or { } concatenate until the matching bracket is reached. This is the preferred way to format multi-argument calls:

plot(
    series = ta.sma(close, 20),
    title  = "SMA 20",
    color  = color.aqua,
    linewidth = 2
)

Indented blocks

Blocks are introduced by if/for/while/switch/once or => and are indented. Four-space indentation is idiomatic; tabs are accepted but must be consistent inside a single block.

if close > open
    bodyColor = color.lime
    bodyAlpha = 15
else
    bodyColor = color.red
    bodyAlpha = 15

A block statement that is assigned (x = if …) yields the value of its last executed statement.

Comments

// A single-line comment.

bar = 2        // Trailing comments are allowed.

Block comments (/* … */) are not supported.

Compiler annotations

Only //@version= is parsed as an annotation. All other comments are ignored.

Idiomatic structure

Experienced authors arrange a script in the following order so readers can scan it top-to-bottom:

  1. Header comment — one-line description, author, licence.
  2. Version annotation.
  3. Declaration statement (indicator()/strategy()/library()).
  4. Constants (var color BULL = color.lime, named thresholds).
  5. Inputs — grouped with group= and arranged with inline= where it makes sense.
  6. Function definitions — pure helpers that take explicit parameters.
  7. Calculations — intermediate series.
  8. Strategy calls / Drawings — strategy.entry/exit, line.new, box.new, label.new.
  9. Visualisation — plot, plotshape, bgcolor, fill, hline.
  10. Alerts — alertcondition (indicators) or alert() (universal).
//@version=1
// Volume-weighted MACD divergence detector.
// © you · MIT.

indicator("VW-MACD divergence", overlay=false, max_lines_count=100)

// ─── Constants ─────────────────────────────────────────────────────────
color BULL = color.lime
color BEAR = color.red

// ─── Inputs ────────────────────────────────────────────────────────────
fast  = input.int(12, "Fast length",  minval=1,  group="MACD")
slow  = input.int(26, "Slow length",  minval=1,  group="MACD")
sig   = input.int(9,  "Signal length", minval=1, group="MACD")
pivot = input.int(5,  "Pivot bars",   minval=1, group="Divergence")

// ─── Helpers ───────────────────────────────────────────────────────────
vwMacd(fast, slow) =>
    fastV = ta.ema(close * volume, fast) / ta.ema(volume, fast)
    slowV = ta.ema(close * volume, slow) / ta.ema(volume, slow)
    fastV - slowV

// ─── Calculations ──────────────────────────────────────────────────────
m    = vwMacd(fast, slow)
s    = ta.ema(m, sig)
hist = m - s

// ─── Visuals ───────────────────────────────────────────────────────────
plot(hist, "Histogram", style=plot.style_histogram, color=hist >= 0 ? BULL : BEAR)
plot(m,    "MACD",      color=color.aqua, linewidth=2)
plot(s,    "Signal",    color=color.orange, linewidth=1)

// ─── Alerts ────────────────────────────────────────────────────────────
alertcondition(ta.crossover(m, s),  "MACD cross up",   "VW-MACD crossed up")
alertcondition(ta.crossunder(m, s), "MACD cross down", "VW-MACD crossed down")

See also