Stock charts
Open-high-low-close-volume candles, market-time ranges, indicators, profiles, price levels, and markers.
Framework quickstart
Render the same stock chart six ways
Choose the imperative TypeScript API or a thin framework adapter. Every tab uses the same typed-array data and chart options.@sixtyfold/stockimport { StockChart, type TimeRange } from "@sixtyfold/stock";
const data = {
timestamp: new Float64Array([0, 60_000, 120_000, 180_000]),
open: new Float64Array([100, 102, 101, 104]),
high: new Float64Array([103, 104, 105, 107]),
low: new Float64Array([99, 100, 100, 103]),
close: new Float64Array([102, 101, 104, 106]),
volume: new Float64Array([420, 510, 470, 630]),
length: 4,
};
const canvas = document.querySelector<HTMLCanvasElement>("#chart")!;
const chart = new StockChart(canvas, {
renderMode: "auto",
timeScale: "market",
showVolume: true,
priceUnit: { prefix: "$", decimals: 2 },
});
await chart.initialize();
chart.setData(data);
// The application owns the controls: choose any labels and ranges, or none.
const controls = document.querySelector("#stock-ranges")!;
for (const range of ["1D", "1M", "ALL"] as const satisfies readonly TimeRange[]) {
const button = document.createElement("button");
button.type = "button";
button.textContent = range;
button.addEventListener("click", () => chart.setTimeRange(range));
controls.append(button);
}
window.addEventListener("pagehide", () => chart.destroy(), { once: true });@sixtyfold/stock renders ordered open, high, low, close, and volume (OHLCV)
columns with market-specific analytical layers. Its level-of-detail (LOD)
process automatically combines many visible candles into valid OHLCV periods,
then returns to finer candles as you zoom.
Exact configuration and method signatures live in the generated Stock options, StockChart methods, and OHLCV data types reference.
StockChart exposes lifecycle, viewport, appearance, overlay, renderer, and
batching methods directly. In market-time mode its viewport methods preserve
compressed observed-session coordinates while public values remain real
timestamps.
Candles and volume
Choose filled, hollow, or ohlc candle geometry. candleColors controls bullish and bearish bodies and wicks. Volume has independent colors, opacity, and pane-height ratio.
The renderer bounds display precision for OHLCV tooltips and crosshair callbacks. Supply priceUnit and volumeUnit when the application requires explicit currency, unit, decimal, or compact formatting.
Host-owned time ranges
StockChart does not create or style time-range buttons. The host application
owns the labels, number, order, layout, and accessibility of its controls—or
can render no controls at all.
Call setTimeRange() when a button maps to one of the exported convenience
presets: 1D, 5D, 1M, 3M, 6M, YTD, 1Y, 5Y, or ALL. A preset
that extends beyond the loaded history clamps to the available data.
const controls = document.querySelector<HTMLElement>("[data-stock-ranges]")!;
const ranges = [
["Day", "1D"],
["Six months", "6M"],
["Everything", "ALL"],
] as const;
for (const [label, range] of ranges) {
const button = document.createElement("button");
button.type = "button";
button.textContent = label;
button.dataset.range = range;
button.addEventListener("click", () => chart.setTimeRange(range));
controls.append(button);
}
canvas.addEventListener("sixtyfold:time-range-change", (event) => {
const detail = (event as CustomEvent).detail;
for (const button of controls.querySelectorAll("button")) {
button.setAttribute(
"aria-pressed",
String(button.dataset.range === detail.range),
);
}
});For a range that is not a named preset, send real timestamps through the ordinary viewport API:
const twoWeeks = 14 * 24 * 60 * 60_000;
let latestDataTimestamp = 0;
const chart = new StockChart(canvas, {
onVisibleRangeChange({ dataBounds }) {
latestDataTimestamp = dataBounds.xMax;
},
});
customButton.addEventListener("click", () => {
chart.setViewport({
xMin: latestDataTimestamp - twoWeeks,
xMax: latestDataTimestamp,
});
});In market time-scale mode, public viewport values remain real timestamps;
the chart converts them to compressed observed-session coordinates internally.
Constructor callbacks provide onTimeRangeChange, onCrosshairMove, and
onVisibleRangeChange. Namespaced DOM-event constants are exported for the
same state changes.
Indicators
Built-in indicators are calculated from raw candles and sampled at the active aggregation for rendering and crosshair values.
chart.setIndicators([
{ type: "sma", id: "sma-20", period: 20, color: "#ffd166" },
{ type: "ema", id: "ema-50", period: 50, color: "#64d8ff" },
{ type: "bollinger", id: "bb-20", period: 20, deviation: 2 },
{ type: "vwap", id: "vwap-day", reset: "day" },
]);Pure functions are available from @sixtyfold/stock/analytics: calculateSMA, calculateEMA, calculateBollingerBands, calculateVWAP, and computeStockIndicator. Non-finite source values break a rolling window instead of being silently interpolated.
Market layers
chart.setVolumeProfile({ rows: 48, placement: "right", valueAreaPercent: 70 });
chart.setPriceLines([
{ id: "entry", price: 182.4, label: "Entry", showAxisLabel: true },
]);
chart.setMarkers([
{ id: "earnings", timestamp, position: "above", shape: "diamond", label: "E" },
]);The volume profile is an estimated volume-by-price histogram, not a trade-by-trade order-flow reconstruction. It divides the visible price scale into rows and distributes each OHLCV candle's volume uniformly across that candle's reported low-to-high range. Wider horizontal bars represent more estimated volume around a price. Bullish and bearish portions use the candle direction, the point of control marks the row with the greatest estimated volume, and the value area expands through adjacent rows until it contains the configured percentage of visible volume.
The profile follows the visible time and price range. Long ranges use the finest completed candle aggregation that keeps the calculation at or below 4,096 source candles; zoomed-in ranges use raw candles. This keeps interaction bounded, but both paths remain candle-derived approximations because OHLCV data does not report where inside each candle's range individual trades occurred. Do not describe this layer as exact trades-at-price, footprint, or order-flow data.
Price lines are data-anchored horizontal levels. Markers are timestamp-sorted and culled to the visible range; use sparse events rather than one marker per candle.
Streaming
chart.initStreaming(250_000);
chart.addCandle(timestamp, open, high, low, close, volume);For columnar feeds, use addCandles or addCandleBatches. initialTimeRange can be applied in the same renderer turn as an initial transferred batch, avoiding a full-range frame before the intended viewport appears.
Streaming aggregation hierarchies rebuild off-screen and replace the active hierarchy atomically. The prior hierarchy remains visible until the replacement is ready.
Loading CSV
loadOHLCVFromCSV is provided for straightforward browser datasets, with an optional progress callback. For very large Parquet or proprietary feeds, decode outside the UI thread and transfer six validated typed columns directly.