millionchart
فارسی

Plots and drawings

Everything a script can put on the chart. Lines, levels, shapes and backgrounds from series, and lines, labels and boxes placed by price and bar.

A script shows its result in two ways. Plots are drawn from a series, one value per bar: a line, a histogram, a shape under a bar. Drawings are single objects you place at a price and a bar, like a trend line, a box around a range or a text label.

Plots#

plot(series) draws a line. The options you will use most are name, color, width and style.

Cuprel
indicator "Plot styles"
    edition = 1

let change = close - open
plot(
    change,
    name = "Body",
    style = histogram,
    color = if change >= 0 then color.green else color.red,
)
plot(tech.sma(change, 10), name = "Average body", width = 2, color = color.orange)
plot(0, name = "Zero", color = color.gray, display = none)
OptionValues
namethe name shown in the settings and the legend
colora colour, or an expression that gives a colour on each bar
widththe width of the line in pixels
styleline (default), line_break, step, step_break, step_diamond, histogram, columns, area, area_break, circles, cross
displaywhere the value is shown: all, pane, price_scale, status_line, data_window; none hides the line

Because a plot is drawn from a series, a plot call is always at the top level of the script, never inside an if, a loop or a function. The engine refuses it there: plot(…) must be called on the top level of the script. To plot only sometimes, plot a value that is na the rest of the time:

Cuprel
indicator "Plot sometimes"
    edition = 1
    display = price

let average_volume = tech.sma(volume, 20)
let strong = close > open and volume > average_volume
plot(if strong then low else na, name = "Strong bars", style = circles, width = 3)

Levels and fills#

level(price) is a horizontal level. shade(a, b) shades between two plots or two levels. Hold the result of plot or level in a name to give it to shade; the signals lesson has an example.

Shapes, characters, arrows#

These draw a mark on the bars where a condition is true, or an arrow whose size follows a value.

Cuprel
indicator "Marks on bars"
    edition = 1
    display = price

let up = close > open and close > close[1]
let down = close < open and close < close[1]
mark.shape(up, name = "Up", shape = triangle_up, place = below, color = color.green)
mark.char(down, name = "Down", char = "x", place = above, color = color.red)
mark.arrow(
    close - open,
    name = "Body",
    up_color = color.fade(color.green, 70),
    down_color = color.fade(color.red, 70),
)

place is above, below, top, bottom or absolute (at a price you give).

Backgrounds and candles#

chart.background(color) paints the background of a bar and chart.candles(color) colours the chart's own candle. A colour of na leaves the bar alone. plot_candles(open, high, low, close) draws candles of your own, for example a smoothed version of the price.

Cuprel
indicator "Candles and backgrounds"
    edition = 1
    display = price

let smooth_open = tech.ema(open, 5)
let smooth_high = tech.ema(high, 5)
let smooth_low = tech.ema(low, 5)
let smooth_close = tech.ema(close, 5)
chart.candles(
    if smooth_close > smooth_open then color.fade(color.green, 40) else color.fade(color.red, 40),
)
plot_candles(
    open = smooth_open,
    high = smooth_high,
    low = smooth_low,
    close = smooth_close,
    name = "Smoothed",
)
chart.background(if smooth_close > tech.sma(close, 50) then color.fade(color.green, 94) else na)

A colour that follows an input#

A colour that depends on an input follows the input: switch the input and the colour changes on the next run. This holds for every colour that is not written as a fixed colour in the script, so a switch that turns a background on and off does what it says:

Cuprel
indicator "A background you can switch"
    edition = 1
    display = price

input show_zone: bool = false, name = "Colour the strong bars"
let strong = close > tech.sma(close, 20) + tech.atr(14)
let zone = if strong then color.fade(color.green, 85) else na
chart.background(if show_zone then zone else na, name = "Strong bars")

With show_zone off no bar is coloured; switch it on and the bars where strong holds are coloured. A colour written in the script itself (color.red) is one colour for the whole run. A colour made only of inputs and constants (color.fade(my_colour, 80) of a colour input, or if show then color.red else na) is one colour for the run too, and the settings restyle it with the member's values. A colour that also reads the bars, as zone above does, is worked out on every bar. In chart.background, chart.candles, plot_candles and plot_bars the colour is what the bar shows, so a colour that reads an input in any way is worked out on every bar.

Drawings: lines, labels, boxes#

A drawing is made by a function that returns it: line.new, label.new, box.new. You place it with a bar number (bar.index) and a price.

Cuprel
indicator "Range of the last 20 bars"
    edition = 1
    display = price

let top = tech.highest(high, 20)
let bottom = tech.lowest(low, 20)
if bar.is_last
    box.new(
        bar.index - 19,
        top,
        bar.index,
        bottom,
        border_color = color.blue,
        background = color.fade(color.blue, 88),
    )
    line.new(
        bar.index - 19,
        close,
        bar.index,
        close,
        extend = right,
        style = dashed,
        color = color.orange,
    )
    label.new(bar.index, top, f"High {top:price}", style = label_down)
plot(close, name = "Close")

bar.is_last is true only on the newest bar, so these are drawn once. Without it the script would draw a new set on every bar.

Drawings can be changed and deleted after they are made. Keep one in a state name and delete it before you draw its replacement:

Cuprel
indicator "Latest high"
    edition = 1
    display = price

state marker: line = na
let top = tech.highest(high, 50)
if bar.is_last
    line.delete(marker)
    marker = line.new(bar.index - 49, top, bar.index, top, color = color.red)
plot(close, name = "Close")

Header options of an indicator#

The header is the first line and the indented lines under it. display = price draws on the price chart and display = pane (the default) in a pane of its own. max_lines, max_labels, max_boxes and max_polylines say how many drawings are kept (below). short_name is a shorter name for the legend, format and precision say how the values are written. edition is the edition of the language. There is no setting for how far back a script reads: the chart keeps the history a script reads.

How many drawings are kept#

The chart keeps the newest 50 lines, labels and boxes a script makes, and drops the oldest. Raise the number in the header: max_lines, max_labels, max_boxes, up to 500 on this chart (100 for max_polylines). A script that goes past its number runs, and the engine says how many it dropped:

Cuprel · warning W-OBJECT-LIMIT
indicator "A label on every bar"
    edition = 1
    display = price

label.new(bar.index, high, "bar")
plot(close)

The way out is usually to draw fewer: only at turning points, only on the last bars, or a single object that you move.

Cuprel
indicator "Labels at pivots"
    edition = 1
    display = price
    max_labels = 500

let pivot = tech.pivot_high(high, 5, 5)
if not is_na(pivot)
    label.new(bar.index - 5, pivot, f"{pivot:price}", style = label_down)
plot(close, name = "Close")

The pivot is known five bars after it happens, so the label is placed five bars back, on the pivot itself. See Results that look too good for what that means for a signal.

Text in a drawing is cut at 2,000 characters. Tables are covered in Tables.

See also: Tables, Ids, Limits and budgets.