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.
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:
- the version line
wickscript 1, and - 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 optionsThe 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.
# 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,oror>. - 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 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,MYEMAandmyemaare the same variable,EMA(Close, 9)isema(close, 9)._counts:my_emaandmyemaare 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 = 5is an error ("close is built in"), and so iswhen = 5. - Words that only have a meaning at one place –
from,to,step,line,color,above,below,stop,target,long,level,hudand 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
| Literal | Meaning | Unit |
|---|---|---|
14, 0.25 | a plain number (decimal point, no thousands separator) | number |
0.3% | a percentage | percent |
2R, 1.5R | a multiple of the trade's risk | R |
5 bars, 1 bar | a number of candles | bars |
1 tick, 3 ticks | that many times the market's price step | price |
30s, 15m, 4h, 1d, 1w, 1M | a time span: seconds, minutes, hours, days, weeks, months (30 days); 1mo = 1M | duration |
"London sweep" | text in double quotes, on one line; \", \\, \n, \t inside | text |
amber, #ff8800 | a color name or #rrggbb | color |
true, false | yes / no | bool |
na | no 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.
| Unit | Examples |
|---|---|
| price | close, high, ema(close, 20), vwap, atr(14) (a price distance), 2 * tick, price(2000) |
| percent | 0.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 |
| R | 2R, position.r |
| time | time, trade.time |
| duration | 15m, 4h, time - time[1] |
| number (no unit) | 14, rsi(close, 14), mfi(14), hour, close / open, book.imbalance(10) |
| bool, text, color | close > open, session, amber |
How units combine:
| Calculation | Result |
|---|---|
| price ± price, price × number, price / number | price |
| price ± percent | price, relative to the price: close + 0.3% is close × 1.003 |
| price × percent | price: atr(14) * 50% is half the ATR |
| price / price, amount / amount (same units) | number (a ratio) |
| number × anything, anything / number | the unit of the other side |
| time − time | duration |
| time ± duration | time |
bars mod number, number mod number | bars, number |
| price + number, price + amount, price × price, number / price | error |
Comparisons (>, == …) and crosses only work between values of the same unit. Text, colors and yes/no values can only be compared with == and !=.
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 numbersConversion functions make your intent visible:
price(2000)– a fixed price level,amount(50)– a fixed volume.number(x)– drops the unit ofxon purpose, e.g.number(close) * number(volume).pct(now, before)– the change frombeforetonowin 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 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 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.
nmust be 0 or more – a negative offset would look into the future and is an error.nmust be fixed: a number, an input, a variable assigned once to a constant, or the counter of arepeatloop that starts at 0 or higher.- Before the first candle there is no history:
close[1]on the first candle isna. - History works for every built-in value, including the time values:
hour[1]is the hour of the previous candle,session[1] is Londonasks whether the previous candle was in London.
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:
| Level | Operators |
|---|---|
| 1 | or |
| 2 | and |
| 3 | not |
| 4 | comparisons == != < <= > >= and phrases: crosses above, crosses below, is, is not, is between … and …, rising, falling, for … bars, becomes true / becomes false |
| 5 | + - |
| 6 | * / mod |
| 7 | minus sign -x |
| 8 | function call f(…), history [n], field .name or ["name"], output ["Name"], on 4h, of BTCUSDT |
modis 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 < 70is an error; writer > 30 and r < 70orr is between 30 and 70. notbinds weaker than comparisons:not close > openmeansnot (close > open).onandofbind to the value directly in front of them:close - open on 4hisclose - (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.
| Phrase | True when |
|---|---|
a crosses above b | a is above b now and was at or below b on the previous candle |
a crosses below b | a is below b now and was at or above b on the previous candle |
x is y, x is not y | x == y, x != y |
x is A or B | x == A or x == B (alternatives are plain names or texts) |
x is between lo and hi | lo <= x <= hi (both ends included) |
x rising 3 bars | x is higher than each of its last 3 values |
x falling 3 bars | x is lower than each of its last 3 values |
cond for 3 bars | cond is true on this candle and the 2 candles before |
cond becomes true | cond is true now and was not on the previous candle |
cond becomes false | cond 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 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
nagivesna:na + 1isna. - Every comparison with
nais false, including!=.x == nais never true – useisna(x). - In
and,or,ifandwhen, a missing condition counts as false. nz(x)replacesnawith 0,nz(x, y)withy(which must have the same unit asx).- A line shows nothing on candles where its value is
na. sma,wma,highest,lowest,sumandstdevarenauntil their window is full, and while the window contains a missing value.emaandrmastart with the average of the firstlengthvalues and keep their last value over missing values.
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 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 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
endWith 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 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 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)andband(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)withlength = input 20 "Length"works. - Variables inside a function are local; the function can also read the script's own variables.
- All
returnvalues must have the same unit. A function can't call itself. - Inside a function you can calculate (
=,keep,if,when,repeat), but not useinput,show,level,metricor 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 (
20or20 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,.histogramandstoch(…)with.k,.d– can't be shown or compared as a whole; pick a part.
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 14is a number,input 0.3%a percentage,input 2Ran R multiple,input 5 barsa number of candles,input "day"a text. The default must be a fixed value, not a calculation. input 2 ticksis a price distance: the setting counts ticks, the script calculates with count × the market's tick size. Writefromandtoin 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 andstepthe step size, used for Step 1 / Step 2 in the strategy panel.input choiceoffers a list of texts; the first one is the default.input timeframeoffers 1m, 5m, 15m, 1h, 4h, 1d and 1w – foron tf(see Data).input true/input falseis a checkbox.- Inputs go at the top level of the script, not inside
if,whenor functions. An input can also be written inside an expression:ema(close, input 9 "Fast").
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 toneHow 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 lineandas histogramneed numbers;as eventneeds a condition and draws a dot where it is true.- Names must be unique within the script (ignoring case).
showgoes at the top level, not insideif,whenor functions. To show a value only on some candles, assign it inside the block and let it benaelsewhere.- Where the script draws (price chart or own panel) is decided by the head line; see Indicators.
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 greenmark
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 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
endhud
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 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"
endalert
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 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.