Skip to content
ChartDeck ChartScript docs Account Open the terminal

Conditionals

if, else if, else and switch in ChartScript, used as statements or as expressions that return a value, and what to keep out of them.

Conditionals let a script do different things on different bars: count a streak only on up bars, pick a color by trend, choose a calculation from a setting. ChartScript has if and switch. Both can be used as statements (do this or that) and as expressions (give me this value or that one).

#if, else if, else

ChartScriptFragmentOpen in editor
state streak: int = 0
if (close > open) {
    streak += 1
} else if (close < open) {
    streak = 0
} else {
    log.info("doji on bar {0}", bar_index)
}
plot(streak)
  • The condition goes in parentheses and must be a bool. A number or a string is not a condition (CS2701), and a value that could be na is refused with CS2204. Compare explicitly: if (diff != 0), if (!na(level) && close > level).
  • The body is the block between { and }. For a single statement the braces can be left out (if (close > open) ups += 1), but with braces it is easier to add a line later.
  • You can chain as many else if as you need. The first branch whose condition is true runs; the others are skipped.
  • A comparison involving na is false, so the else path runs on bars where data is missing.

#if as an expression

An if can produce a value. Write it after const x = (or let x =); each branch's value is its last line:

ChartScriptFragmentOpen in editor
const rsi = ta.rsi(close, 14)
const zone = if (rsi > 70) {
    1
} else if (rsi < 30) {
    -1
} else {
    0
}
plot(zone)

When there is no else and no branch matches, the result is na (or false for a bool). Branches can also return several values as a tuple:

ChartScriptFragmentOpen in editor
const [bodyLow, bodyHigh] = if (close >= open) {
    [open, close]
} else {
    [close, open]
}
plot(bodyLow)
plot(bodyHigh)

For a simple two-way choice the ternary operator is shorter: const zoneColour = close > open ? color.up : color.down.

#switch

switch picks one case out of several. It comes in two forms.

With a subject, each case value is compared with the subject using ==, and default catches everything else:

ChartScriptOpen in editor
//@chartscript 1
indicator("Average of your choice", { overlay: true })
const kind = input.string("EMA", "Average", { options: ["SMA", "EMA", "WMA", "Hull"] })
const len = input.int(20, "Length", { minval: 2 })
const sma = ta.sma(close, len)
const ema = ta.ema(close, len)
const wma = ta.wma(close, len)
const hull = ta.hma(close, len)
const avg = switch (kind) {
    case "SMA": sma
    case "EMA": ema
    case "WMA": wma
    default: hull
}
plot(avg, "Average", color.accent, 2)

The four averages are calculated on every bar before the switch chooses one. That keeps each of them fed with every bar (see stateful functions below); the extra work is tiny.

Without a subject, write switch (true): each case is a condition, and the first true one wins:

ChartScriptFragmentOpen in editor
const rsi = ta.rsi(close, 14)
const tint = switch (true) {
    case rsi > 70: color.down
    case rsi < 30: color.up
    default: color.muted
}
plot(rsi, "RSI", tint)

#How cases work

  • Cases never fall through. A case ends where the next case, the default or the closing } begins; only one case runs. You do not need break.
  • A break as the last line of a case is accepted and does nothing, so code written with the habit still works. A break anywhere else in a case (outside a loop inside that case) is CS1053: use an if / else inside the case instead.
  • Several labels in a row share the body that follows: case "Sat": case "Sun": ….
  • Without a default and without a match, a switch expression gives na.
  • A case body can be a single expression after the colon, or several lines; as a value, the case gives its last line.
  • The subject can be a number, string, bool, color or enum. With an enum, a misspelled case name is caught when you compile.
ChartScriptFragmentOpen in editor
state ups: int = 0
state downs: int = 0
switch (true) {
    case close > open:
        ups += 1
        downs = 0
    case close < open:
        downs += 1
        ups = 0
}
plot(ups - downs)

#What to keep out of conditions

#Outputs

plot, plotshape, hline, fill, bgcolor, inputs and alert.on describe the script's outputs and settings once, for all bars, so they must be at the top level (CS3007, CS3201 for alert.on):

ChartScriptError: CS3007
//@chartscript 1
indicator("Plot in an if", { overlay: true })
if (close > open) {
    plot(close)
}

Put the condition into the value instead. na hides the plot on the bars where it does not apply:

ChartScriptFragmentOpen in editor
plot(close > open ? close : na, "Up closes", color.up, { style: plot.style_circles })

Drawings (label.new, line.new …), log.* and alert.send are actions, not outputs, so they are fine inside an if.

#Stateful functions

Functions that remember previous bars, such as ta.sma, ta.ema, ta.crossover or x[1] inside a function, only advance on the bars where their line actually runs. Inside an if they skip the bars where the condition was false, which is rarely what you want, so the compiler warns (CS2503):

ChartScriptWarning: CS2503Open in editor
//@chartscript 1
indicator("Average in a branch")
let avg = 0.0
if (close > open) {
    avg = ta.sma(close, 10)  // this average only sees up bars
}
plot(avg)

Calculate first, then decide:

ChartScriptFragmentOpen in editor
const sma10 = ta.sma(close, 10)
const avg = close > open ? sma10 : 0.0
plot(avg)

If you really do want an average of only the up bars, keep the call in the branch and the warning tells the next reader that it is on purpose.

#Good to know

  • Braces make the block; indentation is free. The editor indents with 4 spaces, which keeps nested blocks readable.
  • A long condition can go over several lines: break the line after && or ||, or start the next line with it (see line breaks).
  • if blocks create a new scope: a variable declared inside does not exist after the block (see Variables).
  • A deeply nested if chain often reads better as a switch (true).

The ChartScript documentation is in English for now; translations will follow.