Skip to content
ChartRiderDocs
Docs/WickScript/WickScript language guide
WickScript WickScript

WickScript language guide

The complete WickScript syntax – head line, names, numbers and units, operators, conditions, if and when blocks, functions, loops, inputs and output statements.

Updated ·Markdown

This page describes everything the WickScript language accepts. Each example is a complete script you can paste into Strategy Lab → Scripts. For strategy statements (enter, stop at, exit …) see Strategies; for other timeframes, sessions and orderflow see Data.

The head of a script

Every script starts with two lines:

  1. the version line wickscript 1, and
  2. the head line that says what the script is.
wickscript 1
indicator "Name" on chart      # draws in the price chart (the default)
indicator "Name" in pane       # draws in its own panel below the chart
strategy "Name" risk 1%        # a strategy, with options

The version line is required and must come first; only comments and blank lines may stand before it. Version 1 is the only version; a script always runs with the rules of its version, so later language versions never silently change its results.

The name in quotes becomes the script's name in the chart legend and in the indicator settings. Strategy options (risk, leverage, cooldown, minR) are described on the Strategies page.

WickScript
# comments may stand before the version line
wickscript 1
indicator "Candle range" in pane
show high - low as histogram "Range"

Lines, blocks and comments

  • One statement per line. A ; separates several statements on one line.
  • A line continues while a bracket ( or [ is open, or when it ends with an operator such as +, *, and, or or >.
  • Blocks end with end. Indentation has no meaning; Format indents blocks by four spaces for readability.
  • Comments start with # or // and run to the end of the line. /* … */ comments can span several lines. Comments may stand behind a statement.
WickScript
wickscript 1
indicator "Layout" on chart
/* a comment over
   several lines */
mid = (high + low) / 2   # a comment behind a statement
upper = mid +
    atr(14)              // the line continues after the +
a = 1; b = 2
show mid as line "Mid"
show upper as line "Upper"

A # directly followed by exactly six hex digits is a color, not a comment: #deface is the color #deface. Put a space after # when you write comments (# deface).

Names

  • Names consist of the letters A–Z and a–z, the digits 0–9 and _, and start with a letter or _. Other letters (ä, ß, é …) are not allowed.
  • Names ignore upper and lower case, for your own names, built-in names and keywords: myEma, MYEMA and myema are the same variable, EMA(Close, 9) is ema(close, 9). _ counts: my_ema and myema are different names. If you spell a name differently from its first definition, the editor shows a quiet hint and Format unifies the spelling.
  • You can't use a built-in name or a keyword for your own variable: close = 5 is an error ("close is built in"), and so is when = 5.
  • Words that only have a meaning at one place – from, to, step, line, color, above, below, stop, target, long, level, hud and similar – stay free as names. stop = lowest(low, 5) is an ordinary variable.

The reserved keywords are: wickscript indicator strategy library keep if then else end when repeat define return show alert mark use input and or not true false na mod crosses is rising falling becomes on of as.

Unknown names are errors with a suggestion: emma(close, 9) gives "There is no function emma – did you mean ema?".

Values and literals

LiteralMeaningUnit
14, 0.25a plain number (decimal point, no thousands separator)number
0.3%a percentagepercent
2R, 1.5Ra multiple of the trade's riskR
5 bars, 1 bara number of candlesbars
1 tick, 3 ticksthat many times the market's price stepprice
30s, 15m, 4h, 1d, 1w, 1Ma time span: seconds, minutes, hours, days, weeks, months (30 days); 1mo = 1Mduration
"London sweep"text in double quotes, on one line; \", \\, \n, \t insidetext
amber, #ff8800a color name or #rrggbbcolor
true, falseyes / nobool
nano value–

Lower-case m is minutes, upper-case M is months. A letter directly behind a number must be a known suffix: 14abc is an error; write a space before a name.

Color names: white, black, gray, red, green, blue, amber, orange, yellow, lime, teal, cyan, purple, violet, pink.

Units

Every number carries a unit, and the checker rejects calculations that mix units – adding a volume to a price, comparing an RSI with a price, or using a plain number where a price distance is meant. A unit problem is always an error, and the message says how to write it correctly.

UnitExamples
priceclose, high, ema(close, 20), vwap, atr(14) (a price distance), 2 * tick, price(2000)
percent0.3%, pct(close, close[1]), position.size
amount (volume)volume, buyVolume, delta, obv, book.bidVolume(10), amount(50)
bars (candles)5 bars, bars since (close > open), position.bars
R2R, position.r
timetime, trade.time
duration15m, 4h, time - time[1]
number (no unit)14, rsi(close, 14), mfi(14), hour, close / open, book.imbalance(10)
bool, text, colorclose > open, session, amber

How units combine:

CalculationResult
price ± price, price × number, price / numberprice
price ± percentprice, relative to the price: close + 0.3% is close × 1.003
price × percentprice: atr(14) * 50% is half the ATR
price / price, amount / amount (same units)number (a ratio)
number × anything, anything / numberthe unit of the other side
time − timeduration
time ± durationtime
bars mod number, number mod numberbars, number
price + number, price + amount, price × price, number / priceerror

Comparisons (>, == …) and crosses only work between values of the same unit. Text, colors and yes/no values can only be compared with == and !=.

WickScript
wickscript 1
indicator "Units" on chart
buffer = close + 0.3%                    # price + percent = price
band = ema(close, 20) + 2 * atr(14)      # price + number × price = price
ratio = close / open                     # price / price = number
bigBody = abs(close - open) > atr(14)    # price > price
loud = volume > 2 * sma(volume, 20)      # amount > amount
level2000 = close > price(2000)          # a fixed price level
show buffer as line "Buffer"
show band as line "Band"

Typical errors and their fixes:

close + 5              → Can't add a price and a plain number – write 5 * tick or 5%
close > 2000           → Can't compare a price with a plain number – write price(2000) for a fixed price level
close > volume         → Can't compare a price with an amount (volume)
bars since x >= 10     → write "10 bars"
target at 2            → Expected a target price or an R multiple like 2R, not a plain number
trade.size > 50        → write amount(50) for a fixed amount (volume)
close * close          → Can't multiply a price by a price – use number(…) if you really mean plain numbers

Conversion functions make your intent visible:

  • price(2000) – a fixed price level, amount(50) – a fixed volume.
  • number(x) – drops the unit of x on purpose, e.g. number(close) * number(volume).
  • pct(now, before) – the change from before to now in percent: pct(close, close[1]).

A variable keeps the unit of its first assignment: y = close followed by y = volume is an error. A sum of prices starts with price(0), a sum of volumes with amount(0):

WickScript
wickscript 1
indicator "Sum of closes" in pane
total = price(0)
repeat i from 0 to 4
    total = total + close[i]
end
show total / 5 - sma(close, 5) as line "Difference"

Variables

name = expression creates or changes a variable. A normal variable starts every candle with na and gets its value when the assignment runs on that candle. A variable assigned only inside an if therefore has no value (na) on candles where the if didn't run – which is how you show a line only on some candles.

keep name = value creates a variable that keeps its value from candle to candle (like var in Pine Script). The value after keep is used once, on the first candle; later candles start with the value of the previous candle. Use keep only on the first assignment; change the variable afterwards with a normal =.

WickScript
wickscript 1
indicator "Green candle streak" in pane
keep streak = 0
if close > open then
    streak = streak + 1
else
    streak = 0
end
show streak as histogram "Streak"

History: [n]

x[n] is the value of x n candles ago: close[1] is the previous close, ema(close, 20)[3] the EMA three candles ago, and myVar[1] the value your variable had at the end of the previous candle. [0] is the current value.

  • n must be 0 or more – a negative offset would look into the future and is an error.
  • n must be fixed: a number, an input, a variable assigned once to a constant, or the counter of a repeat loop that starts at 0 or higher.
  • Before the first candle there is no history: close[1] on the first candle is na.
  • History works for every built-in value, including the time values: hour[1] is the hour of the previous candle, session[1] is London asks whether the previous candle was in London.
WickScript
wickscript 1
indicator "Momentum" in pane
len = input 10 "Length"
show close - close[len] as histogram "Momentum"
show (close - close[len])[1] as line "Previous"

Operators

From the weakest to the strongest binding:

LevelOperators
1or
2and
3not
4comparisons == != < <= > >= and phrases: crosses above, crosses below, is, is not, is between … and …, rising, falling, for … bars, becomes true / becomes false
5+ -
6* / mod
7minus sign -x
8function call f(…), history [n], field .name or ["name"], output ["Name"], on 4h, of BTCUSDT
  • mod is the remainder: hour mod 4 == 0. There is no % operator; % only follows a number (0.5%).
  • Division by zero gives na.
  • Compare two values at a time: 30 < r < 70 is an error; write r > 30 and r < 70 or r is between 30 and 70.
  • not binds weaker than comparisons: not close > open means not (close > open).
  • on and of bind to the value directly in front of them: close - open on 4h is close - (open on 4h). Use brackets for a whole calculation: (close - open) on 4h.
  • Text comparisons ignore upper and lower case: session == "london" is true in the London session.

Conditions and phrases

Conditions are yes/no values. Store them in variables, combine them with and, or, not, and use them in if, when, show … as event and strategy statements.

PhraseTrue when
a crosses above ba is above b now and was at or below b on the previous candle
a crosses below ba is below b now and was at or above b on the previous candle
x is y, x is not yx == y, x != y
x is A or Bx == A or x == B (alternatives are plain names or texts)
x is between lo and hilo <= x <= hi (both ends included)
x rising 3 barsx is higher than each of its last 3 values
x falling 3 barsx is lower than each of its last 3 values
cond for 3 barscond is true on this candle and the 2 candles before
cond becomes truecond is true now and was not on the previous candle
cond becomes falsecond is false now and was true on the previous candle
bars since (cond)the number of candles since cond was last true (0 on that candle, na before the first time)

crossover(a, b) and crossunder(a, b) are the same as a crosses above b and a crosses below b. The number of candles after rising, falling and for is written with bars and must be fixed (a number or an input).

bars since takes the value right after it, so put a condition in brackets: bars since (close > open). In strategies, bars since entry counts the candles since the entry of the open position.

WickScript
wickscript 1
indicator "Phrases" in pane
r = rsi(close, 14)
show r crosses above 50 as event "RSI up"
show r is between 40 and 60 as event "RSI neutral"
show ema(close, 20) rising 5 bars as event "EMA rising"
show close > open for 3 bars as event "Three green"
show (volume > 2 * sma(volume, 20)) becomes true as event "Volume spike"
show bars since (r > 70) as line "Since overbought"
show weekday is Saturday or Sunday as event "Weekend"

x for 3 bars applies to the comparison directly in front of it: close > open for 3 bars means (close > open) for 3 bars. With and/or, use brackets: (close > open and volume > volume[1]) for 3 bars.

Missing values: na

na means "no value": the first candles of a moving average, close[1] on the first candle, a variable that wasn't assigned on this candle, or orderflow data where none was recorded.

  • Calculating with na gives na: na + 1 is na.
  • Every comparison with na is false, including !=. x == na is never true – use isna(x).
  • In and, or, if and when, a missing condition counts as false.
  • nz(x) replaces na with 0, nz(x, y) with y (which must have the same unit as x).
  • A line shows nothing on candles where its value is na.
  • sma, wma, highest, lowest, sum and stdev are na until their window is full, and while the window contains a missing value. ema and rma start with the average of the first length values and keep their last value over missing values.
WickScript
wickscript 1
indicator "Warm-up" in pane
slow = sma(close, 50)
ready = not isna(slow)
show ready as event "Ready"
show nz(delta) as histogram "Delta or 0"

if … then … else … end

if is a state: its block runs on every candle on which the condition is true. then is optional. else if continues the chain, and the whole chain is closed by one end. A short if fits on one line.

WickScript
wickscript 1
indicator "Candle type" in pane
kind = 0
if close > open then
    kind = 1
else if close < open then
    kind = -1
else
    kind = 0
end
big = 0
if high - low > 2 * atr(14) then big = 1 end
show kind as histogram "Type"
show big as line "Big"

when … end

when is an event: its block runs only on the candle on which the condition becomes true – it was false (or na) on the previous candle. While the condition stays true, the block doesn't run again; it runs again after the condition has been false for at least one candle.

WickScript
wickscript 1
indicator "Above the EMA" on chart
e = ema(close, 50)
show e as line "EMA 50" color amber
when close > e
    mark "up" below color green      # once, when the close gets above the EMA
end
when close < e
    mark "down" above color red
end

With if close > e instead, the mark would be written on every candle above the EMA. For conditions that are already events, like crosses above, if and when behave the same. Alerts, marks, levels and strategy entries normally belong in a when block; the checker warns when they would run on every candle.

Functions keep counting inside blocks. Built-in functions with a history (ema, rsi, highest, crosses …) update on every candle, even inside an if or when block that doesn't run on that candle, and even on the side of an and/or that isn't evaluated. lowest(low, 10) inside a when block is always the lowest low of the last 10 candles.

Loops: repeat

repeat i from a to b … end runs its block with i = a, a + 1, … b. The bounds are plain numbers; the counter can't be changed in the loop. A loop runs at most 500 times, and one candle can run at most 10,000 loop steps over all loops together – beyond that, the loops stop for that candle and the Scripts tab shows a message with the line of the loop.

WickScript
wickscript 1
indicator "Green candles of the last 10" in pane
count = 0
repeat i from 0 to 9
    if close[i] > open[i] then count = count + 1 end
end
show count as histogram "Green"

The counter can be used as a history offset (close[i]) when the loop starts at 0 or higher.

Functions: define

Define your own functions at the top level of the script. A one-line function returns its expression; a multi-line function ends with end and returns its result with return.

WickScript
wickscript 1
indicator "Own functions" on chart
length = input 20 "Length"
define mid(a, b) = (a + b) / 2
define band(src, mult)
    basis = sma(src, length)
    return basis + mult * stdev(src, length)
end
show mid(high, low) as line "Mid"
show band(close, 2) as line "Upper band"
show band(hl2, 3) as line "Wide band"
  • Functions may be called before their definition. Arguments are passed in order, without names.
  • Units are worked out per call: mid(high, low) returns a price, mid(volume, volume[1]) an amount. A unit error inside the function is reported at the call.
  • Every call has its own state: band(close, 2) and band(hl2, 3) keep separate moving averages.
  • Lengths and history offsets inside a function must be fixed numbers or the script's inputs, not parameters: define f(src, len) = sma(src, len) is an error, define f(src) = sma(src, length) with length = input 20 "Length" works.
  • Variables inside a function are local; the function can also read the script's own variables.
  • All return values must have the same unit. A function can't call itself.
  • Inside a function you can calculate (=, keep, if, when, repeat), but not use input, show, level, metric or strategy statements.

Built-in functions

The full list of built-in functions and values, with parameters and units, is in the Reference. The most used are the moving averages sma, ema, rma, wma, dema and the window functions highest, lowest, sum, stdev – all (source, length) and returning the unit of source – plus change, rsi, atr, mfi, chop, macd, stoch, vwap, abs, min, max, round, nz, pct, crossover, crossunder and isna. Built-in values per candle include open, high, low, close, volume, hl2, hlc3, ohlc4, truerange, vwap, obv, time and tick (the market's price step), plus the time, session and orderflow values.

  • Lengths must be fixed whole numbers of at least 1: a number (20 or 20 bars), an input, or a variable assigned once to a constant. A length that changes per candle is an error.
  • Named arguments are allowed for built-in functions: stoch(14, smoothK: 3, smoothD: 3), ema(source: hl2, length: 21).
  • Results with several parts – macd(…) with .line, .signal, .histogram and stoch(…) with .k, .d – can't be shown or compared as a whole; pick a part.
WickScript
wickscript 1
indicator "MACD and Stochastic" in pane
m = macd(close, 12, 26, 9)
s = stoch(14, 3, 3)
show m.histogram as histogram "MACD histogram"
show s.k - 50 as line "Stoch %K - 50"

Inputs

input declares a value the user can change in the indicator settings without editing the code. Inputs are constants: their value is the same on every candle.

name = input <default> ["Label"] [from <min> to <max>] [step <step>]
name = input choice "Label" of ["option 1", "option 2", …]
name = input color <color> ["Label"]
name = input timeframe <time span> ["Label"]
name = input true ["Label"]
  • The default sets the unit: input 14 is a number, input 0.3% a percentage, input 2R an R multiple, input 5 bars a number of candles, input "day" a text. The default must be a fixed value, not a calculation.
  • input 2 ticks is a price distance: the setting counts ticks, the script calculates with count × the market's tick size. Write from and to in ticks as well (input 2 ticks "Offset" from 1 tick to 10 ticks).
  • The label is the name in the settings; without one, the variable name is used.
  • from … to … sets the range and step the step size, used for Step 1 / Step 2 in the strategy panel.
  • input choice offers a list of texts; the first one is the default.
  • input timeframe offers 1m, 5m, 15m, 1h, 4h, 1d and 1w – for on tf (see Data).
  • input true / input false is a checkbox.
  • Inputs go at the top level of the script, not inside if, when or functions. An input can also be written inside an expression: ema(close, input 9 "Fast").
WickScript
wickscript 1
indicator "Inputs" on chart
length = input 20 "Length" from 5 to 50 step 5
mult = input 2 "Width (ATR)" from 1 to 4 step 0.5
source = input choice "Source" of ["close", "hl2"]
tone = input color amber "Color"
showBands = input true "Show bands"
src = close
if source == "hl2" then src = hl2 end
basis = ema(src, length)
upper = na
if showBands then upper = basis + mult * atr(length) end
show basis as line "Basis" color tone
show upper as line "Upper" color tone

How inputs become settings and backtest parameters is described on the Indicators page.

Output statements

show

show <value> as line|histogram|event "Name" [color <color>] [width <number>] [in pane]

show draws a value on every candle and makes it an output that the Trade Setup and other scripts can read by its name.

  • as line and as histogram need numbers; as event needs a condition and draws a dot where it is true.
  • Names must be unique within the script (ignoring case).
  • show goes at the top level, not inside if, when or functions. To show a value only on some candles, assign it inside the block and let it be na elsewhere.
  • Where the script draws (price chart or own panel) is decided by the head line; see Indicators.
WickScript
wickscript 1
indicator "Outputs" on chart
e = ema(close, 21)
show e as line "EMA" color #3987e5 width 2
show close crosses above e as event "Cross up"
swingHigh = na
if high == highest(high, 20) then swingHigh = high end
show swingHigh as line "New 20-bar high" color green

mark

mark "Text" [above|below] [color <color>]

Writes a short text at the candle: above (the default) above its high, below under its low. At most 500 marks per run.

level

level <price> "Name" [color <color>] [until killed | until killed or <N> bars | until <N> bars | until <condition>]

level starts a horizontal line at the given price on the candle where the statement runs, usually inside a when block. The level stays active until:

  • until killed – price trades through it, checked from the next candle: a level above the close of its candle is killed when a high goes above it, a level below when a low goes under it;
  • until 20 bars – it expires after 20 candles; until killed or 20 bars – whichever comes first;
  • until <condition> – it ends at the close of the candle on which the condition is true.

Without until, a level stays active. Active levels are drawn solid to the right edge with their name; ended levels are drawn faded and dashed. At most 500 levels per run (the oldest ended ones are dropped first). Levels draw in the price chart.

WickScript
wickscript 1
indicator "Swing levels" on chart
when high == highest(high, 20)
    level high "Swing high" color red until killed or 100 bars
end
when low == lowest(low, 20)
    level low "Swing low" color green until killed
end

hud

hud "Text {expression} more text"

Adds a line to the HUD stack under the script's title. Each {…} holds one expression; it shows the value on the last candle, formatted by its unit (yes/no, candles as whole numbers, %, R, other numbers with 2 to 6 decimals depending on their size, – for na). Only HUD lines that ran on the last candle are shown – a hud inside an if shows only while its condition is true.

WickScript
wickscript 1
indicator "Status" on chart
r = rsi(close, 14)
hud "RSI {r} · ATR {atr(14)} · change {pct(close, close[1])}"
if r > 70 then
    hud "Overbought for {bars since (r <= 70)} bars"
end

alert

alert "Text"

Raises an alert with a fixed text. In the chart, an alert on the newest live candle appears as a notification, once per candle. The text is shown as written (no {…} values). Put alerts inside when … end; outside, the checker warns that the alert would fire on every candle.

log

log "Text {expression}"

Writes a line for every candle on which the statement runs. The Scripts tab shows the lines of the candle at the crosshair and the most recent lines; the last 2,000 lines of a run are kept. Use it to debug a script.

WickScript
wickscript 1
indicator "Debug" in pane
gap = open - close[1]
when abs(gap) > atr(14)
    log "gap {gap} at RSI {rsi(close, 14)}"
    alert "Big gap"
end
show gap as histogram "Gap"

Note the difference: log "text" writes a log line, log(x) is the natural logarithm.

How a script runs

The script runs once per candle, from the oldest loaded candle to the newest, and gives the same values in the chart, the Strategy Lab, replay and backtests. In the chart, the still running candle is recalculated with every price update, so its values can change until it closes; strategies only decide on closed candles. Limits per run: 500 iterations per repeat, 10,000 loop steps per candle, 500 marks, 500 levels, 2,000 log lines.

Generated from the ChartRider source code on every release – settings, outputs and the WickScript reference always match the app.

Imprint·Privacy·Contact·Changelog·llms-full.txt

Paper trading uses play money only. Nothing in these docs is investment advice.