Indicator outputs and styles

An indicator returns one number per output on each bar (or None for “nothing here”). Everything about how that number looks on a chart is declared once, in the indicator’s outputs and levels. A chart reads it from describe().

This keeps the math simple and the data small: the per-bar values never carry colors or text, so the same indicator works in a backtest, in a live strategy and on any chart that understands these options.

Quick reference

Option

What it does

kind

How the values draw: line, step, area, histogram, columns, circles, cross, scatter, markers, shape, fill, background, bar_color, candle.

color

#RRGGBB, #RRGGBBAA (opacity in the last two digits) or a theme color, chart.fg or chart.bg.

line_width

Pixels, above 0 and at most 10. For circles, cross and scatter it is the mark size. Default 1.

line_style

solid (default), dashed or dotted.

palette, color_by, gradient

A color per bar, picked by another output’s value.

offset

Shift the drawing left (negative) or right (positive) by whole bars.

display

all (default), pane, status_line, data_window, none.

precision

Decimals shown for the value, 0 to 10.

pane

price or own: overrides the indicator’s overlay for this output.

track_price

A dotted line across the pane at the newest value.

shape, location, size, text, text_color

Markers for shape outputs.

between

The two outputs or levels a fill shades between.

candle

The open, high, low and close outputs a candle output draws.

Every option is checked when the class is defined (for a single output) or when the indicator is created (for references between outputs). A typo raises ValueError that names the output and the allowed values.

Kinds

line

A line. Where the value is None the line breaks; it never joins across a gap.

step

A line that moves in steps: flat until the next bar, then straight up or down.

area

A line with the space under it filled in the line’s color. Use a color with opacity (#2962FF33) for a light fill.

histogram

Bars from zero, thin.

columns

Bars from zero, full bar width.

circles, cross

A dot or a cross on each bar with a value. line_width sets the size.

scatter

Dots, like circles, kept for older indicators.

markers

Reserved for marker-only outputs some charts read separately; prefer shape.

shape

A mark on every bar whose value is set and not 0. See Markers.

fill

Shades the space between two outputs or two levels. See Fills.

background

Colors the bar’s whole column of its pane. See Background zones.

bar_color

Recolors the price candles. See Candle colors.

candle

Draws candles from four other outputs. See Candles of your own.

Width and line style

outputs = [
    OutputSpec("fast", "Fast", "line", "#2962FF", line_width=2),
    OutputSpec("slow", "Slow", "line", "#FF6D00", line_width=1, line_style="dashed"),
    OutputSpec("signal", "Signal", "step", "#AB47BC", line_style="dotted"),
]

Colors and opacity

A color is #RRGGBB or #RRGGBBAA. The last pair is opacity in hex: FF is solid, 80 is half, 1A is about a tenth, 00 is invisible:

OutputSpec("cloud", "Cloud", "area", "#26A69A33")     # a light green area

Theme colors

chart.fg is the chart’s text color and chart.bg its background color. They change with the chart’s light or dark theme, so a line drawn in chart.fg is always readable:

OutputSpec("basis", "Basis", "line", "chart.fg")

A person viewing the chart can still choose their own color, width and style for each output in the chart’s settings; their choice wins over the class.

A color per bar

Give the output a palette and name another output in color_by. On each bar, that output’s value picks the color:

  • without gradient, the value is an index into the palette (0 is the first color, 1 the second…). Values are rounded and kept inside the palette.

  • with gradient=(low, high), the value is a position: low gets the first color, high the last, and values in between are blended across the palette.

  • None on a bar uses the output’s own color.

Hide the helper output with display="none". A four-color histogram:

outputs = [
    OutputSpec("hist", "Histogram", "histogram", line_width=4,
               palette=("#26A69A", "#B2DFDB", "#FF5252", "#FFCDD2"),
               color_by="hist_color"),
    OutputSpec("hist_color", "Histogram color", "line", display="none"),
]

def step(self, state, bar):
    ...
    return {"hist": value, "hist_color": 0 if rising_above_zero else 1}

A line colored by its own value:

outputs = [
    OutputSpec("rsi", "RSI", "line", palette=("#FF5252", "#7E57C2", "#00E676"),
               color_by="rsi_shade", gradient=(0, 100)),
    OutputSpec("rsi_shade", "RSI shade", "line", display="none"),
]
# step(): return {"rsi": rsi, "rsi_shade": rsi}

Fills

A fill output shades between two things. Each side is an output id or a level value. Its color (and palette / color_by) works like any other output. step does not need to return a value for it.

Between two outputs:

OutputSpec("cloud", "Cloud", "fill", "#2962FF26", between=("upper", "lower"))

Between two levels, like a shaded 30 to 70 band:

OutputSpec("band", "Band", "fill", "#7E57C21A", between=(70.0, 30.0))

Where either side is None on a bar, that bar is not shaded.

Background zones

A background output colors the whole height of its pane on bars where its value is set. With a palette, the value picks the color; without one, any value uses color. An indicator that overlays the price colors the price chart’s background:

OutputSpec("zone", "Zone", "background", palette=("#FF525226", "#00E67626"), display="pane")

# step(): return {"zone": 0 if overbought else 1 if oversold else None}

Candle colors

A bar_color output recolors the price candles on bars where its value is set, the same way as a background:

OutputSpec("trend", "Trend color", "bar_color", palette=("#00C853", "#FF1744"), display="pane")

Markers

A shape output puts a mark on each bar whose value is set and not 0.

shape

circle, square, diamond, cross, xcross, triangle_up, triangle_down, arrow_up, arrow_down, label_up, label_down (a tag pointing at the bar, with the text inside it) and flag.

location

above_bar, below_bar, absolute (at the output’s value), top or bottom of the pane.

size

auto, tiny, small, normal, large, huge.

text, text_color

Up to 40 characters drawn with the mark. One character with a small shape works like a character marker:

OutputSpec("buy", "Buy", "shape", "#00C853", shape="label_up",
           location="below_bar", text="Buy", text_color="#FFFFFF", size="small")
OutputSpec("pivot", "Pivot", "shape", "#FFB74D", shape="circle",
           location="absolute", size="tiny")   # step() returns the pivot price

Candles of your own

A candle output draws candles from four other outputs (usually hidden with display="none"). palette and color_by color each candle:

outputs = [
    OutputSpec("o", "Open", display="none"),
    OutputSpec("h", "High", display="none"),
    OutputSpec("l", "Low", display="none"),
    OutputSpec("c", "Close", display="none"),
    OutputSpec("dir", "Direction", display="none"),
    OutputSpec("candles", "Candles", "candle", candle=("o", "h", "l", "c"),
               palette=("#26A69A", "#EF5350"), color_by="dir", pane="own"),
]

Panes

The indicator’s overlay decides where its outputs draw: True on the price chart, False in a pane of its own under it. One output can go the other way with pane:

class Trend(Indicator):
    overlay = False                      # oscillator in its own pane
    outputs = [
        OutputSpec("osc", "Oscillator"),
        OutputSpec("flip", "Flip", "shape", shape="triangle_up",
                   location="below_bar", pane="price"),   # marks on the candles
    ]

What shows where

display controls where an output appears:

all

Drawn, and its value is shown in the chart’s status line.

pane

Drawn, value not shown. Good for fills, zones and markers.

status_line

Value shown, nothing drawn.

data_window

Only in a chart’s data window, where it has one.

none

Not shown at all. Use it for helper outputs such as the one color_by reads.

precision sets how many decimals the value shows.

Shift and price line

offset moves an output by whole bars: offset=-5 draws each value five bars earlier, offset=5 five bars later. A chart only draws the part that falls on bars it has.

track_price=True draws a dotted line across the pane at the output’s newest value, so the latest reading is easy to see.

Levels

A Level is a fixed horizontal guide line. style is solid, dashed (default) or dotted. color and line_width are optional; without a color the chart uses its own:

levels = [
    Level(70, "Upper", "dashed", color="#787B86"),
    Level(50, "Middle", "dotted", color="#787B8680"),
    Level(30, "Lower", "dashed", color="#787B86"),
]

Shade between two levels with a fill (see Fills).

Complete examples

These ship with LumiBot in lumibot/example_indicators/ and run in the test suite. Each is small and shows several options together.

momentum_histogram.py

Four-color histogram (palette + color_by), cross marks on the zero line colored by a second helper, a dotted zero level.

trailing_band.py

Two lines that break where the trend flips, half-transparent fills between the price middle and the band, Buy / Sell tag markers, and candle colors.

oscillator_zones.py

A line colored by a gradient, a fill between two levels, background zones, track_price and precision.

smoothed_candles.py

Candles of its own in a separate pane (candle + pane="own") and a dashed step line on the price chart.

Load one and look at its schema:

from lumibot.example_indicators import oscillator_zones
oscillator_zones.OscillatorZones.describe()

What is not an output

Some charting tools also let a script create free-standing objects: lines between two points, text labels, boxes, tables pinned to a corner of the chart, or horizontal bars growing from the side of the chart (volume at each price). These are not one number per bar, so they are not outputs. They are not part of the indicator contract yet.