Appearance

Personalize your experience

Mode
Accent Color
Direction
All Docs/QuaScript//
QuaScript logo

QuaScript Documentation

Language guide, engine API, 601 builtins and the preset library · v3.0.0-phase1

Colors

The palette

color.<family>.<shade> names 44 families with 11 shades each: 50, 100, 200 … 900, 950 (light to dark). Families include slate gray zinc neutral stone red orange amber yellow lime green emerald teal cyan sky blue indigo violet purple fuchsia pink rose and more. color.black, color.white and color.transparent are also defined. Hex literals #rrggbb work anywhere a color does.

The explorer below lists every family in rainbow order, with the neutral families last. Select a swatch (or use the arrow keys) to see its values, its contrast on dark and light backgrounds and its translucent variants. Switch "Click sets" to B (or shift-click) to pick a second color and build a gradient between the two; the example script under the explorer uses both.

Click sets
50
100
200
300
400
500
600
700
800
900
950
red
tomato
coral
brown
bronze
copper
coffee
orange
sand
amber
yellow
gold
chartreuse
olive
lime
green
emerald
mint
teal
aqua
cyan
sky
navy
slate
blue
indigo
violet
lavender
purple
plum
fuchsia
magenta
pink
ruby
crimson
rose
neutral
zinc
stone
sage
gray
charcoal
mauve
silver
color.sky.400#38bdf8
namecolor.sky.400hex#38bdf8rgb56, 189, 248hsl198°, 93%, 60%
Aa 123.45
on black: 9.80 · AAA
Aa 123.45
on white: 2.14 · fail
Transparency (color.translucent(c, t), 0 = opaque)
Gradient A → Bcolor.sky.400 → color.rose.500
Use the selection
selection.qs
analysis "Palette: sky" { overlay = false }

m = ta.rsi(close, 14) - 50
heat = color.gradient(m, -20, 20, color.rose.500, color.sky.400)
render.histogram(m, "Momentum", color = heat)
render.line(ta.ema(m, 9), "Signal", color = color.sky.400, width = 2)
render.area(m, "Area", base = 0, color = color.translucent(color.sky.400, 85))
Rainbow at shade
rainbow_ribbon.qs
analysis "Rainbow ribbon" { overlay = true }

// one moving average per family, in rainbow order
render.line(ta.ema(close, 8), "EMA 8", color = color.red.400)
render.line(ta.ema(close, 14), "EMA 14", color = color.coral.400)
render.line(ta.ema(close, 20), "EMA 20", color = color.bronze.400)
render.line(ta.ema(close, 26), "EMA 26", color = color.coffee.400)
render.line(ta.ema(close, 32), "EMA 32", color = color.sand.400)
render.line(ta.ema(close, 38), "EMA 38", color = color.yellow.400)
render.line(ta.ema(close, 44), "EMA 44", color = color.chartreuse.400)
render.line(ta.ema(close, 50), "EMA 50", color = color.lime.400)
QuaScriptengine result
Loading the engine result…
palette.qs
analysis "Palette" { overlay = true }

render.line(ta.ema(close, 9), "Fast", color = color.sky.400, width = 2)
render.line(ta.ema(close, 21), "Mid", color = color.amber.500, width = 2)
render.line(ta.ema(close, 50), "Slow", color = #8b5cf6, width = 2)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Choosing shades

ShadeUse it for
50 – 200text and thin lines on dark backgrounds; fills on light ones
300 – 500the main lines and marks: readable on both themes
600 – 800histogram columns, candle colors, table cell backgrounds
900 – 950backgrounds and panels; fills on dark themes

A pair from the same family (teal.400 line, teal.800 fill) always looks related. For up / down pairs, keep the shade equal (emerald.500 / rose.500) so neither side looks louder.

Color functions

FunctionResult
color.rgb(r, g, b, transparency = 0)a color from channels 0 .. 255
color.translucent(c, transparency)c with 0 (opaque) .. 100 (invisible) transparency
color.gradient(x, lo, hi, c1, c2)c1 at lo blending to c2 at hi (also a two-color mix: color.gradient(t, 0, 1, a, b))
color.lighten(c, amount) / color.darken(c, amount)lighter / darker by 0 .. 100
color.hsv(h, s, v)from hue 0 .. 360, saturation and value 0 .. 100
color.complement(c) / color.invert(c) / color.grayscale(c)
color.harmonics(c, scheme)a harmonic partner of c
color.contrast(a, b)WCAG contrast ratio of two colors
color.readable(c)black or white, whichever reads better on c
color.alpha(c)the transparency of c
color.ramp(x, min, max, palette = "viridis", transparency = 0)x on a multi-stop palette, from its first stop at min to its last at max

Multi-stop palettes

color.ramp maps a value onto a palette with many stops, which reads far better on heatmaps than a two-color blend. Swap min and max to reverse a palette.

PaletteKindUse it for
viridis, cividissequential, perceptually uniformany 0 .. high quantity; cividis is safe for color-blind readers
magma, inferno, plasmasequential, dark to brightintensity, power, heat, volatility
turborainbow, high contrastdense heatmaps where fine steps matter
spectral, coolwarmdivergingsigned values around a centre (z-scores, correlation)
terrainsequentialsmooth (low) to rough (high), e.g. fractal dimension
pnldiverging, dark centregains and losses
QuaScriptengine result
Loading the engine result…
ramp.qs
analysis "Ramp palettes" { overlay = false }

z = stat.zscore(close, 50)
render.histogram(z, "Z-score", color = color.ramp(z, -2.5, 2.5, "coolwarm"))
render.line(ta.rsi(close, 14) / 25 - 2, "RSI scaled", color = color.ramp(ta.rsi(close, 14), 20, 80, "plasma"), width = 2)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

viridis, magma, inferno, plasma and cividis are CC0 (van der Walt, Smith and Nunez); turbo is Apache-2.0 (Mikhailov, Google); spectral comes from ColorBrewer and coolwarm from Moreland (2009).

Calls with constant arguments are folded at compile time, so color.translucent(color.red.500, 80) costs nothing per bar. A color that depends on the bar (an expression with close, an if, a gradient over a series) is computed per bar and drawn per bar.

Transparency

QuaScriptengine result
Loading the engine result…
transparency.qs
analysis "Transparency steps" { overlay = true }

m = ta.sma(close, 40)
s = ta.atr(40)
for k in [1, 2, 3] {
    pu = render.line(m + k * s, "Upper " + str.of(k), color = color.translucent(color.cyan.400, 20 * k))
    pd = render.line(m - k * s, "Lower " + str.of(k), color = color.translucent(color.cyan.400, 20 * k))
    render.band(pu, pd, color = color.cyan.500, opacity = 0.05)
}
render.line(m, "SMA 40", color = color.cyan.300, width = 2)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Transparency is 0 (opaque) to 100 (invisible). Stacked translucent bands add up: three bands at 5 % opacity give a darker core and lighter edges.

Heat maps

QuaScriptengine result
Loading the engine result…
heat.qs
analysis "RSI heat" { overlay = false }

r = ta.rsi(close, 14)
heat = r >= 50 ? color.gradient(r, 50, 100, color.slate.400, color.rose.500) : color.gradient(r, 0, 50, color.sky.500, color.slate.400)
render.line(r, "RSI", color = heat, width = 2)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Two gradients joined at the midpoint give a diverging scale: cool below 50, neutral at 50, warm above. The same idea works for any oscillator with a natural center.

Three-stop gradients

QuaScriptengine result
Loading the engine result…
three_stop.qs
analysis "Three-stop heat" { overlay = false }

z = stat.zscore(close, 60)
c = z < 0 ? color.gradient(z, -2.5, 0, color.blue.500, color.amber.300) : color.gradient(z, 0, 2.5, color.amber.300, color.red.500)
render.histogram(z, "Z-score", color = c)
render.level(2, "+2", color = color.red.700, stroke = style.dashed)
render.level(-2, "-2", color = color.blue.700, stroke = style.dashed)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Gradient by volume

QuaScriptengine result
Loading the engine result…
volume_heat.qs
analysis "Relative volume heat" { overlay = false }

rv = volume / ta.sma(volume, 50)
render.histogram(volume, "Volume", color = color.gradient(rv, 0.5, 3, color.slate.700, color.yellow.300))
render.line(ta.sma(volume, 50), "Average", color = color.slate.400)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Rainbows

color.hsv(h, s, v) walks the color wheel: 0 is red, 60 yellow, 120 green, 180 cyan, 240 blue, 300 magenta. Mapping a value to the hue gives a rainbow scale.

The palette in rainbow order
The palette in rainbow order
QuaScriptengine result
Loading the engine result…
rainbow_bands.qs
analysis "Rainbow Bollinger" { overlay = true }

basis = ta.sma(close, 30)
dev = stat.stdev(close, 30)
for k in [0.5, 1.0, 1.5, 2.0, 2.5, 3.0] {
    render.line(basis + k * dev, "+" + str.of(k), color = color.hsv(k * 40, 75, 95))
    render.line(basis - k * dev, "-" + str.of(k), color = color.hsv(k * 40, 75, 95), stroke = style.dotted)
}
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)
QuaScriptengine result
Loading the engine result…
rainbow_oscillator.qs
analysis "Rainbow stochastic" { overlay = false }

for len in [9, 14, 21, 34, 55] {
    (k, d) = ta.stoch(close, high, low, len, 3, 3)
    render.line(k, "%K " + str.of(len), color = color.hsv((len - 9) * 5.5, 70, 95), width = 1.5)
}
render.level(80, "80", color = color.slate.600, stroke = style.dashed)
render.level(20, "20", color = color.slate.600, stroke = style.dashed)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Palette families as a rainbow

Using the named shades instead of color.hsv keeps the colors consistent with the rest of the terminal's theme:

QuaScriptengine result
Loading the engine result…
family_rainbow.qs
analysis "Family rainbow" { overlay = true }

render.line(ta.ema(close, 8), "8", color = color.red.400)
render.line(ta.ema(close, 13), "13", color = color.orange.400)
render.line(ta.ema(close, 21), "21", color = color.amber.400)
render.line(ta.ema(close, 34), "34", color = color.lime.400)
render.line(ta.ema(close, 55), "55", color = color.emerald.400)
render.line(ta.ema(close, 89), "89", color = color.cyan.400)
render.line(ta.ema(close, 144), "144", color = color.blue.400)
render.line(ta.ema(close, 233), "233", color = color.violet.400)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Readable text

color.readable(bg) picks black or white text for a background, and color.contrast(a, b) gives the WCAG ratio (4.5 or more is comfortable for small text). Use them for table cells whose background follows the data:

QuaScriptengine result
Loading the engine result…
readable.qs
analysis "Readable cells" { overlay = true }

r = ta.rsi(close, 14)
bg = color.gradient(r, 20, 80, color.sky.300, color.rose.700)
persist t = draw.table.create(anchor.top_right, 1, 2)
if bar.is_last {
    draw.table.cell(t, 0, 0, "RSI", text_color = color.slate.400)
    draw.table.cell(t, 0, 1, str.format("{:.1f}", r), bg_color = bg, text_color = color.readable(bg))
}
render.candle_color(bg)
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

Colors as parameters

param.color lets the user pick a color in the settings dialog; the value is a normal color.

QuaScriptengine result
Loading the engine result…
color_param.qs
analysis "Configurable colors" { overlay = true }

up = param.color(color.emerald.400, title = "Up color")
dn = param.color(color.rose.400, title = "Down color")
fade = param.int(90, title = "Background transparency", min = 0, max = 100)
f = ta.ema(close, 10)
s = ta.ema(close, 30)
render.line(f, "Fast", color = f > s ? up : dn, width = 2)
render.line(s, "Slow", color = color.slate.400)
render.background(color.translucent(f > s ? up : dn, fade))
quatick-charts · QuaScript engine on synthetic 1-minute bars · drag to pan · scroll to zoom · Run executes the script on the engine (⌘/Ctrl+Enter while editing)

A band's fill color is part of the chart layout and must be a constant; per-bar colors work on lines, histograms, dots, marks, candles and backgrounds.


© 2026 Quatick Technologies. All rights reserved.