Skip to content

Indicators

Indicators are drawing layers hosted inside a Panel. They receive DrawState with priceRange injected by CandlePanel, so they can convert prices to pixel coordinates.

Toggle visibility: indicator.visible = false.

Built-in Indicators

SMAIndicator

Simple Moving Average line.

ts
import { SMAIndicator } from 'chartgpu';

const sma = new SMAIndicator(20, { color: '#f59e0b' });
candlePanel.addIndicator(sma);

// Toggle
sma.visible = false;
chart.redraw();
ArgumentTypeDescription
periodnumberNumber of candles to average.
options.colorstringLine color. Default: #f59e0b

EMAIndicator

Exponential Moving Average line.

ts
import { EMAIndicator } from 'chartgpu';

const ema = new EMAIndicator(50, { color: '#a78bfa' });
candlePanel.addIndicator(ema);
ArgumentTypeDescription
periodnumberEMA period.
options.colorstringLine color. Default: #a78bfa

BollingerBandsIndicator

Upper band, lower band, and middle SMA.

ts
import { BollingerBandsIndicator } from 'chartgpu';

const bb = new BollingerBandsIndicator(20, 2);
bb.visible = false;  // off by default
candlePanel.addIndicator(bb);
ArgumentTypeDescription
periodnumberSMA period. Default: 20
stdDevnumberStandard deviation multiplier. Default: 2

Custom Indicators

Extend Indicator:

ts
import { Indicator, type DrawState } from 'chartgpu';

class VWAPIndicator extends Indicator {
  draw(state: DrawState): void {
    if (!state.priceRange) return;
    const { ctx, candles, viewport, section, chartWidth, paddingX, priceRange } = state;
    const { top, height } = section;
    const { min, range } = priceRange;
    const vp = viewport;
    const viewLen = vp.end - vp.start;

    // Compute VWAP
    let cumPV = 0, cumV = 0;
    const values = candles.map(c => {
      const typical = (c.high + c.low + c.close) / 3;
      cumPV += typical * (c.volume ?? 1);
      cumV  += (c.volume ?? 1);
      return cumPV / cumV;
    });

    ctx.save();
    ctx.strokeStyle = '#f472b6';
    ctx.lineWidth = 1.5;
    ctx.beginPath();
    let started = false;
    for (let i = 0; i < values.length; i++) {
      const x = paddingX + ((i + 0.5 - vp.start) / viewLen) * chartWidth;
      if (x < paddingX - 5 || x > paddingX + chartWidth + 5) { started = false; continue; }
      const y = top + height * (1 - (values[i] - min) / range);
      if (!started) { ctx.moveTo(x, y); started = true; } else ctx.lineTo(x, y);
    }
    ctx.stroke();
    ctx.restore();
  }
}

Released under the MIT License.