Learn ThetaScript
The guided walkthrough from the script editor, in order. Each snippet is a complete script you can run as-is.
Your first script
A script runs once per bar, top to bottom, oldest bar first. Sources like close read the current bar, indicator calls update as the bars stream through them, and draw calls contribute that bar’s slice of the output. Start with a study() declaration and one plot:
study("My First Script", overlay=true)
plot(ema(close, 20), color="#22d3ee", width=2)
overlay=true draws on the price chart; leave it off and the script gets its own pane below — right for oscillators like RSI. Save the script and add it to the chart like any other study.
Series and history
Every expression produces one value per bar. A plain assignment is recomputed each bar, and square brackets look back: spread[1] is the previous bar’s value. Values that don’t exist yet — the lookback before bar 0, an sma still filling its window — read as na, and na stays quiet: plots skip it, comparisons against it are 0.
study("Range", overlay=false)
spread = high - low
widening = spread > spread[1]
plot(sma(spread, 10), title="avg range")
plot(spread, style="histogram", color="#7d8590")
Remembering state
var declares a variable once, on the first bar, and keeps its value from bar to bar — use := to update it. Together with if blocks (indentation-delimited, like Python) this is how you count, latch, and accumulate:
study("Up Bars", overlay=false)
var upBars = 0
if close > open
upBars := upBars + 1
infopanel(upBars, title="up bars")
plot(100 * upBars / (bar_index + 1), title="% up")
Signals
crossover(a, b) is 1 on the exact bar a crosses above b — the building block of most entries. plotbuy/plotsell drop buy and sell markers on the chart, and plotshape marks any condition:
study("Cross Signals", overlay=true)
fast = ema(close, 9)
slow = ema(close, 21)
plot(fast, color="#22d3ee")
plot(slow, color="#f59e0b")
plotbuy(crossover(fast, slow), 10)
plotsell(crossunder(fast, slow), 10)
Inputs
input.* declarations surface as controls in the study’s settings, so one script serves many configurations. The call returns the chosen value; defaults apply until the user changes them:
study("Tunable RSI", overlay=false)
len = input.int(14, "RSI length", minval=2)
level = input.float(30, "Band", minval=5, maxval=45)
r = rsi(close, len)
plot(r, color="#a78bfa", width=2)
hline(level)
hline(100 - level)
Backtesting
strategy.buy and strategy.sell turn signals into a simulated position: fills at the close of the signal bar, netted long/short, with optional protective exits (stop_loss, take_profit, trailing — all price offsets from entry). strategy.config sets capital and costs, and the result carries a full trade ledger with equity metrics:
study("Golden Cross", overlay=true)
strategy.config(initial_capital=10000, commission_percent=0.1)
fast = sma(close, 20)
slow = sma(close, 50)
plot(fast, color="#22d3ee")
plot(slow, color="#f59e0b")
strategy.buy(crossover(fast, slow), 25, qty_type="percent_of_equity", stop_loss=2)
strategy.sell(crossunder(fast, slow), 25, qty_type="percent_of_equity")
Read the live position from strategy.position_size, strategy.equity and friends — e.g. gate re-entries on strategy.position_size == 0.
Going further
From here the Reference tab documents everything: higher-timeframe data with security("1h", …), alerts with {{close}}-style message placeholders, arrays, drawing objects (line.new, label.new, box.new), and the full indicator set. The Examples tab has complete scripts you can import into the editor and dissect.