Stock Performance Grid in JavaScript

Using ApexCharts with JavaScript

This Stock Performance Grid example uses ApexCharts.js directly in JavaScript, with no wrapper component.

Install it with npm install apexcharts, then mount the chart with new ApexCharts(element, options).render().

JavaScript installation guide
// Six tickers whose price levels differ by 40x: a shared y scale would
// flatten the cheap ones into noise, so this trellis uses
// `scales: { y: 'independent' }`. Each panel gets its own honest domain, and
// the panels are STILL pixel-aligned: the trellis measures every panel's
// axis-label gutter and pushes the widest as a shared floor, so the plot
// rectangles agree to the pixel and the shapes stay comparable.
//
// One toolbar for the grid: drag or wheel-zoom in any panel and every panel
// follows on the shared x window; reset restores all six at once.
//
// Deterministic OHLC walks so the e2e snapshot is stable.
function mulberry32(seed) {
  return function () {
    seed |= 0
    seed = (seed + 0x6d2b79f5) | 0
    var t = Math.imul(seed ^ (seed >>> 15), 1 | seed)
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296
  }
}

function ohlcWalk(seed, start, vol) {
  var rand = mulberry32(seed)
  var r2 = function (v) {
    return Math.round(v * 100) / 100
  }
  var out = []
  var ts = new Date('01 Jan 2025').getTime()
  var close = start
  for (var i = 0; i < 40; i++) {
    var open = close
    close = Math.max(vol, open + (rand() - 0.48) * vol * 2)
    var high = Math.max(open, close) + rand() * vol
    var low = Math.max(vol * 0.2, Math.min(open, close) - rand() * vol)
    out.push({ x: ts, y: [r2(open), r2(high), r2(low), r2(close)] })
    ts += 86400000
  }
  return out
}

var TICKERS = [
  { ticker: 'ANVL', seed: 3, start: 24, vol: 0.9 },
  { ticker: 'BRCK', seed: 17, start: 61, vol: 2.1 },
  { ticker: 'CDER', seed: 29, start: 142, vol: 4.5 },
  { ticker: 'DELM', seed: 41, start: 310, vol: 9 },
  { ticker: 'ELMS', seed: 53, start: 78, vol: 2.6 },
  { ticker: 'FRST', seed: 67, start: 927, vol: 24 },
]

// One series NAME across the grid (the headers already name the tickers), so
// the shared legend has nothing to add and stays hidden.
var stockSeries = TICKERS.map(function (t) {
  return {
    name: 'OHLC',
    ticker: t.ticker,
    data: ohlcWalk(t.seed, t.start, t.vol),
  }
})

var options = {
  series: stockSeries,
  chart: {
    id: 'stockTrellis',
    type: 'candlestick',
    height: 620,
    animations: {
      enabled: false,
    },
  },
  trellis: {
    by: 'ticker',
    columns: 3,
    gap: 14,
    scales: {
      y: 'independent',
    },
  },
  xaxis: {
    type: 'datetime',
  },
  yaxis: {
    labels: {
      formatter: function (val) {
        return '$' + Math.round(val)
      },
    },
  },
  dataLabels: {
    enabled: false,
  },
  tooltip: {
    x: {
      format: 'dd MMM',
    },
  },
}

var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()