JavaScript Multi-Pane Stock Charts using Sync Multi-Chart

Using the default multi-chart sync APIs, create a multi-pane stock chart example with indicator panels. Zooming, panning, cursors are synchronised between the charts. This is a simpler way to create charts than subcharts, but will have a performance hit on some browsers.

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

ExampleDataProvider.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    SciChartVerticalGroup,
3    DiscontinuousDateAxis,
4    EAxisAlignment,
5    SciChartSurface,
6    EAutoRange,
7    NumberRange,
8    NumericAxis,
9    OhlcDataSeries,
10    FastCandlestickRenderableSeries,
11    XyDataSeries,
12    calcAverageForArray,
13    FastLineRenderableSeries,
14    ZoomPanModifier,
15    ZoomExtentsModifier,
16    MouseWheelZoomModifier,
17    RolloverModifier,
18    FastBandRenderableSeries,
19    XyyDataSeries,
20    FastColumnRenderableSeries,
21    EXyDirection,
22    EFillPaletteMode,
23    EStrokePaletteMode,
24    IFillPaletteProvider,
25    IStrokePaletteProvider,
26    IRenderableSeries,
27    parseColorToUIntArgb,
28    ENumericFormat,
29    SmartDateLabelProvider,
30    XyMovingAverageFilter,
31    EDataSeriesField,
32    ELabelAlignment,
33    SeriesInfo,
34    EDataSeriesType,
35    OhlcSeriesInfo,
36    RolloverLegendSvgAnnotation,
37    SciChartOverview,
38    ESeriesType,
39    FastMountainRenderableSeries,
40    GradientParams,
41    Point,
42    TextAnnotation,
43    ECoordinateMode,
44    EHorizontalAnchorPoint,
45    EVerticalAnchorPoint,
46    EAnnotationLayer,
47} from "scichart";
48import { fetchMultiPaneData } from "../../../ExampleData/ExampleDataProvider";
49import { appTheme } from "../../../theme";
50
51const getTradingData = async (startPoints?: number, maxPoints?: number) => {
52    const { dateValues, openValues, highValues, lowValues, closeValues, volumeValues } = await fetchMultiPaneData();
53
54    if (maxPoints !== undefined) {
55        return {
56            dateValues: dateValues.slice(startPoints, startPoints + maxPoints),
57            openValues: openValues.slice(startPoints, startPoints + maxPoints),
58            highValues: highValues.slice(startPoints, startPoints + maxPoints),
59            lowValues: lowValues.slice(startPoints, startPoints + maxPoints),
60            closeValues: closeValues.slice(startPoints, startPoints + maxPoints),
61            volumeValues: volumeValues.slice(startPoints, startPoints + maxPoints),
62        };
63    }
64
65    return { dateValues, openValues, highValues, lowValues, closeValues, volumeValues };
66};
67
68// Override the standard legend displayed by RolloverModifier
69const getTooltipLegendTemplate = (seriesInfos: SeriesInfo[], svgAnnotation: RolloverLegendSvgAnnotation) => {
70    let outputSvgString = "";
71
72    // Foreach series there will be a seriesInfo supplied by SciChart. This contains info about the series under the house
73    seriesInfos.forEach((seriesInfo, index) => {
74        const y = 20 + index * 20;
75        const textColor = seriesInfo.stroke;
76        let legendText = seriesInfo.formattedYValue;
77        if (seriesInfo.dataSeriesType === EDataSeriesType.Ohlc) {
78            const o = seriesInfo as OhlcSeriesInfo;
79            legendText = `Open=${o.formattedOpenValue} High=${o.formattedHighValue} Low=${o.formattedLowValue} Close=${o.formattedCloseValue}`;
80        }
81        outputSvgString += `<text x="8" y="${y}" font-size="13" font-family="Verdana" fill="${textColor}">
82            ${seriesInfo.seriesName}: ${legendText}
83        </text>`;
84    });
85
86    return `<svg width="100%" height="100%">
87                ${outputSvgString}
88            </svg>`;
89};
90
91// Override the Renderableseries to display on the scichart overview
92const getOverviewSeries = (defaultSeries: IRenderableSeries) => {
93    if (defaultSeries.type === ESeriesType.CandlestickSeries) {
94        // Swap the default candlestick series on the overview chart for a mountain series. Same data
95        return new FastMountainRenderableSeries(defaultSeries.parentSurface.webAssemblyContext2D, {
96            dataSeries: defaultSeries.dataSeries,
97            fillLinearGradient: new GradientParams(new Point(0, 0), new Point(0, 1), [
98                { color: appTheme.VividSkyBlue + "77", offset: 0 },
99                { color: "Transparent", offset: 1 },
100            ]),
101            stroke: appTheme.VividSkyBlue,
102        });
103    }
104    // hide all other series
105    return undefined;
106};
107
108export const getChartsInitializationAPI = () => {
109    // We can group together charts using VerticalChartGroup type
110    const verticalGroup = new SciChartVerticalGroup();
111
112    const dataPromise = getTradingData();
113
114    let chart1XAxis: DiscontinuousDateAxis;
115    let chart2XAxis: DiscontinuousDateAxis;
116    let chart3XAxis: DiscontinuousDateAxis;
117    let priceChartSurface: SciChartSurface;
118    let macdChartSurface: SciChartSurface;
119    let rsiChartSurface: SciChartSurface;
120    const axisAlignment = EAxisAlignment.Right;
121
122    const upCol = appTheme.VividGreen;
123    const downCol = appTheme.MutedRed;
124    const opacity = "AA";
125
126    // CHART 1
127    const drawPriceChart = async (rootElement: string | HTMLDivElement) => {
128        const [chart, data] = await Promise.all([
129            SciChartSurface.create(rootElement, {
130                // prevent default size settings
131                disableAspect: true,
132                theme: appTheme.SciChartJsTheme,
133            }),
134            dataPromise,
135        ]);
136        const { wasmContext, sciChartSurface } = chart;
137        const { dateValues, openValues, highValues, lowValues, closeValues, volumeValues } = data;
138
139        chart1XAxis = new DiscontinuousDateAxis(wasmContext, {
140            drawLabels: false,
141            drawMajorTickLines: false,
142            drawMinorTickLines: false,
143        });
144        sciChartSurface.xAxes.add(chart1XAxis);
145
146        const yAxis = new NumericAxis(wasmContext, {
147            maxAutoTicks: 5,
148            autoRange: EAutoRange.Always,
149            growBy: new NumberRange(0.3, 0.11),
150            labelFormat: ENumericFormat.Decimal,
151            labelPrecision: 4,
152            cursorLabelFormat: ENumericFormat.Decimal,
153            cursorLabelPrecision: 4,
154            labelPrefix: "$",
155            axisAlignment,
156        });
157        sciChartSurface.yAxes.add(yAxis);
158
159        // OHLC DATA SERIES
160        const usdDataSeries = new OhlcDataSeries(wasmContext, {
161            dataSeriesName: "EUR/USD",
162            xValues: dateValues,
163            openValues,
164            highValues,
165            lowValues,
166            closeValues,
167        });
168        const fcRendSeries = new FastCandlestickRenderableSeries(wasmContext, {
169            dataSeries: usdDataSeries,
170            stroke: appTheme.ForegroundColor, // Used for legend template
171            brushUp: upCol + "77",
172            brushDown: downCol + "77",
173            strokeUp: upCol,
174            strokeDown: downCol,
175        });
176        sciChartSurface.renderableSeries.add(fcRendSeries);
177
178        // MA1 SERIES
179        const maLowDataSeries = new XyMovingAverageFilter(usdDataSeries, {
180            dataSeriesName: "MA 50 Low",
181            length: 50,
182            field: EDataSeriesField.Low,
183        });
184        const maLowRenderableSeries = new FastLineRenderableSeries(wasmContext, {
185            dataSeries: maLowDataSeries,
186        });
187        sciChartSurface.renderableSeries.add(maLowRenderableSeries);
188        maLowRenderableSeries.rolloverModifierProps.tooltipColor = "red";
189        maLowRenderableSeries.rolloverModifierProps.markerColor = "red";
190        maLowRenderableSeries.stroke = appTheme.VividPink;
191        maLowRenderableSeries.strokeThickness = 2;
192
193        // MA2 SERIES
194        const maHighDataSeries = new XyMovingAverageFilter(usdDataSeries, {
195            dataSeriesName: "MA 200 High",
196            length: 200,
197            field: EDataSeriesField.High,
198        });
199        const maHighRenderableSeries = new FastLineRenderableSeries(wasmContext, {
200            dataSeries: maHighDataSeries,
201        });
202        sciChartSurface.renderableSeries.add(maHighRenderableSeries);
203        maHighRenderableSeries.stroke = appTheme.VividSkyBlue;
204        maHighRenderableSeries.strokeThickness = 2;
205
206        // VOLUME SERIES
207        const yAxis2 = new NumericAxis(wasmContext, {
208            id: "yAxis2",
209            isVisible: false,
210            autoRange: EAutoRange.Always,
211            growBy: new NumberRange(0, 3),
212        });
213        sciChartSurface.yAxes.add(yAxis2);
214
215        const volumeRenderableSeries = new FastColumnRenderableSeries(wasmContext, {
216            yAxisId: "yAxis2",
217            dataSeries: new XyDataSeries(wasmContext, {
218                dataSeriesName: "Volume",
219                xValues: dateValues,
220                yValues: volumeValues,
221            }),
222            dataPointWidth: 0.5,
223            strokeThickness: 1,
224            paletteProvider: new VolumePaletteProvider(usdDataSeries, upCol + opacity, downCol + opacity),
225        });
226        sciChartSurface.renderableSeries.add(volumeRenderableSeries);
227
228        // Add a watermark annotation
229        const watermarkAnnotation = new TextAnnotation({
230            x1: 0.5,
231            y1: 0.5,
232            xCoordinateMode: ECoordinateMode.Relative,
233            yCoordinateMode: ECoordinateMode.Relative,
234            horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
235            verticalAnchorPoint: EVerticalAnchorPoint.Center,
236            opacity: 0.17,
237            textColor: appTheme.ForegroundColor,
238            fontSize: 48,
239            fontWeight: "Bold",
240            text: "Euro / U.S. Dollar - Daily",
241        });
242        sciChartSurface.annotations.add(watermarkAnnotation);
243
244        // MODIFIERS
245        sciChartSurface.chartModifiers.add(new ZoomPanModifier({ enableZoom: true }));
246        sciChartSurface.chartModifiers.add(new ZoomExtentsModifier());
247        sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());
248        sciChartSurface.chartModifiers.add(
249            new RolloverModifier({
250                modifierGroup: "cursorGroup",
251                showTooltip: false,
252                snapToDataPoint: true,
253                tooltipLegendTemplate: getTooltipLegendTemplate,
254            })
255        );
256
257        verticalGroup.addSurfaceToGroup(sciChartSurface);
258        priceChartSurface = sciChartSurface;
259        sciChartSurface.zoomExtentsX();
260
261        return { wasmContext, sciChartSurface };
262    };
263
264    // CHART 2 - MACD
265    const drawMacdChart = async (rootElement: string | HTMLDivElement) => {
266        const [{ wasmContext, sciChartSurface }, { dateValues, closeValues }] = await Promise.all([
267            SciChartSurface.create(rootElement, {
268                // prevent default size settings
269                disableAspect: true,
270                theme: appTheme.SciChartJsTheme,
271            }),
272            dataPromise,
273        ]);
274
275        chart2XAxis = new DiscontinuousDateAxis(wasmContext, {
276            drawLabels: false,
277            drawMajorTickLines: false,
278            drawMinorTickLines: false,
279        });
280        sciChartSurface.xAxes.add(chart2XAxis);
281
282        const yAxis = new NumericAxis(wasmContext, {
283            autoRange: EAutoRange.Always,
284            growBy: new NumberRange(0.1, 0.1),
285            axisAlignment,
286            labelPrecision: 2,
287            cursorLabelPrecision: 2,
288            labelStyle: { alignment: ELabelAlignment.Right },
289        });
290        yAxis.labelProvider.numericFormat = ENumericFormat.Decimal;
291        sciChartSurface.yAxes.add(yAxis);
292
293        const macdArray: number[] = [];
294        const signalArray: number[] = [];
295        const divergenceArray: number[] = [];
296        for (let i = 0; i < dateValues.length; i++) {
297            const maSlow = calcAverageForArray(closeValues, 12, i);
298            const maFast = calcAverageForArray(closeValues, 25, i);
299            const macd = maSlow - maFast;
300            macdArray.push(macd);
301            const signal = calcAverageForArray(macdArray, 9, i);
302            signalArray.push(signal);
303            const divergence = macd - signal;
304            divergenceArray.push(divergence);
305        }
306
307        const bandSeries = new FastBandRenderableSeries(wasmContext, {
308            dataSeries: new XyyDataSeries(wasmContext, {
309                dataSeriesName: "MACD",
310                xValues: dateValues,
311                yValues: signalArray,
312                y1Values: macdArray,
313            }),
314            stroke: downCol,
315            strokeY1: upCol,
316            fill: upCol + "77",
317            fillY1: downCol + "77",
318        });
319        sciChartSurface.renderableSeries.add(bandSeries);
320
321        const columnSeries = new FastColumnRenderableSeries(wasmContext, {
322            dataSeries: new XyDataSeries(wasmContext, {
323                dataSeriesName: "Divergence",
324                xValues: dateValues,
325                yValues: divergenceArray,
326            }),
327            paletteProvider: new MacdHistogramPaletteProvider(upCol + "AA", downCol + "AA"),
328            dataPointWidth: 0.5,
329        });
330        sciChartSurface.renderableSeries.add(columnSeries);
331
332        sciChartSurface.chartModifiers.add(
333            new ZoomPanModifier({ enableZoom: true, xyDirection: EXyDirection.XDirection })
334        );
335        sciChartSurface.chartModifiers.add(new ZoomExtentsModifier({ xyDirection: EXyDirection.XDirection }));
336        sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }));
337        sciChartSurface.chartModifiers.add(
338            new RolloverModifier({
339                modifierGroup: "cursorGroup",
340                showTooltip: false,
341                snapToDataPoint: true,
342                tooltipLegendTemplate: getTooltipLegendTemplate,
343            })
344        );
345
346        verticalGroup.addSurfaceToGroup(sciChartSurface);
347        macdChartSurface = sciChartSurface;
348
349        return { wasmContext, sciChartSurface };
350    };
351
352    // CHART 3 - RSI
353    const drawRsiChart = async (rootElement: string | HTMLDivElement) => {
354        const [{ wasmContext, sciChartSurface }, { dateValues, closeValues }] = await Promise.all([
355            SciChartSurface.create(rootElement, {
356                // prevent default size settings
357                disableAspect: true,
358                theme: appTheme.SciChartJsTheme,
359            }),
360            dataPromise,
361        ]);
362
363        chart3XAxis = new DiscontinuousDateAxis(wasmContext, {
364            autoRange: EAutoRange.Once,
365            labelProvider: new SmartDateLabelProvider(),
366        });
367        sciChartSurface.xAxes.add(chart3XAxis);
368
369        const yAxis = new NumericAxis(wasmContext, {
370            autoRange: EAutoRange.Always,
371            growBy: new NumberRange(0.1, 0.1),
372            labelPrecision: 0,
373            cursorLabelPrecision: 0,
374            axisAlignment,
375            labelStyle: { alignment: ELabelAlignment.Right },
376        });
377        yAxis.labelProvider.numericFormat = ENumericFormat.Decimal;
378        sciChartSurface.yAxes.add(yAxis);
379
380        const RSI_PERIOD = 14;
381        const rsiArray: number[] = [];
382        const gainArray: number[] = [];
383        const lossArray: number[] = [];
384
385        if (dateValues.length) {
386            rsiArray.push(NaN);
387            gainArray.push(NaN);
388            lossArray.push(NaN);
389        }
390
391        for (let i = 1; i < dateValues.length; i++) {
392            const previousClose = closeValues[i - 1];
393            const currentClose = closeValues[i];
394            const gain = currentClose > previousClose ? currentClose - previousClose : 0;
395            gainArray.push(gain);
396            const loss = previousClose > currentClose ? previousClose - currentClose : 0;
397            lossArray.push(loss);
398            const relativeStrength =
399                calcAverageForArray(gainArray, RSI_PERIOD) / calcAverageForArray(lossArray, RSI_PERIOD);
400            const rsi = 100 - 100 / (1 + relativeStrength);
401            rsiArray.push(rsi);
402        }
403        const rsiRenderableSeries = new FastLineRenderableSeries(wasmContext, {
404            dataSeries: new XyDataSeries(wasmContext, {
405                dataSeriesName: "RSI",
406                xValues: dateValues,
407                yValues: rsiArray,
408            }),
409            stroke: appTheme.MutedBlue,
410            strokeThickness: 2,
411        });
412        sciChartSurface.renderableSeries.add(rsiRenderableSeries);
413
414        sciChartSurface.chartModifiers.add(
415            new ZoomPanModifier({ enableZoom: true, xyDirection: EXyDirection.XDirection })
416        );
417        sciChartSurface.chartModifiers.add(new ZoomExtentsModifier({ xyDirection: EXyDirection.XDirection }));
418        sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }));
419        sciChartSurface.chartModifiers.add(
420            new RolloverModifier({
421                modifierGroup: "cursorGroup",
422                showTooltip: false,
423                snapToDataPoint: true,
424                tooltipLegendTemplate: getTooltipLegendTemplate,
425            })
426        );
427
428        verticalGroup.addSurfaceToGroup(sciChartSurface);
429        rsiChartSurface = sciChartSurface;
430
431        return { wasmContext, sciChartSurface };
432    };
433
434    // DRAW OVERVIEW
435    // Must be done after main chart creation
436    const drawOverview = (mainSurface: SciChartSurface) => async (rootElement: string | HTMLDivElement) => {
437        const overview = await SciChartOverview.create(mainSurface, rootElement, {
438            // prevent default size settings
439            disableAspect: true,
440            theme: appTheme.SciChartJsTheme,
441            transformRenderableSeries: getOverviewSeries,
442        });
443
444        return { sciChartSurface: overview.overviewSciChartSurface };
445    };
446
447    const configureAfterInit = () => {
448        const synchronizeAxes = () => {
449            // TODO refactor using AxisSynchroniser
450
451            // SYNCHRONIZE VISIBLE RANGES
452            chart1XAxis.visibleRangeChanged.subscribe((data1) => {
453                chart2XAxis.visibleRange = data1.visibleRange;
454                chart3XAxis.visibleRange = data1.visibleRange;
455            });
456            chart2XAxis.visibleRangeChanged.subscribe((data1) => {
457                chart1XAxis.visibleRange = data1.visibleRange;
458                chart3XAxis.visibleRange = data1.visibleRange;
459            });
460            chart3XAxis.visibleRangeChanged.subscribe((data1) => {
461                chart1XAxis.visibleRange = data1.visibleRange;
462                chart2XAxis.visibleRange = data1.visibleRange;
463            });
464        };
465
466        synchronizeAxes();
467
468        // Force showing the latest 200 bars
469        const twoHundredDaysOfSeconds = 60 * 60 * 24 * 200;
470        chart1XAxis.visibleRange = new NumberRange(
471            chart1XAxis.visibleRange.max - twoHundredDaysOfSeconds,
472            chart1XAxis.visibleRange.max
473        );
474    };
475
476    return { drawPriceChart, drawMacdChart, drawRsiChart, drawOverview, configureAfterInit };
477};
478
479/**
480 * An example PaletteProvider applied to the volume column series. It will return green / red
481 * fills and strokes when the main price data bar is up or down
482 */
483class VolumePaletteProvider implements IStrokePaletteProvider, IFillPaletteProvider {
484    public readonly strokePaletteMode: EStrokePaletteMode = EStrokePaletteMode.SOLID;
485    public readonly fillPaletteMode: EFillPaletteMode = EFillPaletteMode.SOLID;
486    private priceData: OhlcDataSeries;
487    private volumeUpArgb: number;
488    private volumnDownArgb: number;
489
490    constructor(priceData: OhlcDataSeries, volumeUpColor: string, volumeDownColor: string) {
491        this.priceData = priceData;
492        this.volumeUpArgb = parseColorToUIntArgb(volumeUpColor);
493        this.volumnDownArgb = parseColorToUIntArgb(volumeDownColor);
494    }
495
496    onAttached(parentSeries: IRenderableSeries): void {}
497
498    onDetached(): void {}
499
500    overrideFillArgb(xValue: number, yValue: number, index: number): number {
501        const open = this.priceData.getNativeOpenValues().get(index);
502        const close = this.priceData.getNativeCloseValues().get(index);
503
504        return close >= open ? this.volumeUpArgb : this.volumnDownArgb;
505    }
506
507    overrideStrokeArgb(xValue: number, yValue: number, index: number): number {
508        return this.overrideFillArgb(xValue, yValue, index);
509    }
510}
511
512// tslint:disable-next-line:max-classes-per-file
513class MacdHistogramPaletteProvider implements IStrokePaletteProvider, IFillPaletteProvider {
514    public readonly strokePaletteMode: EStrokePaletteMode = EStrokePaletteMode.SOLID;
515    public readonly fillPaletteMode: EFillPaletteMode = EFillPaletteMode.SOLID;
516    private aboveZeroArgb: number;
517    private belowZeroArgb: number;
518
519    constructor(aboveZeroColor: string, belowZeroColor: string) {
520        this.aboveZeroArgb = parseColorToUIntArgb(aboveZeroColor);
521        this.belowZeroArgb = parseColorToUIntArgb(belowZeroColor);
522    }
523
524    onAttached(parentSeries: IRenderableSeries): void {}
525
526    onDetached(): void {}
527
528    overrideFillArgb(xValue: number, yValue: number, index: number): number {
529        return yValue >= 0 ? this.aboveZeroArgb : this.belowZeroArgb;
530    }
531
532    overrideStrokeArgb(xValue: number, yValue: number, index: number): number {
533        return this.overrideFillArgb(xValue, yValue, index);
534    }
535}
536

Multi Pane Stock Charts using Sync Multi-Chart and JavaScript

Overview

This example demonstrates a multi-pane stock chart built exclusively with JavaScript and SciChart.js. It features a primary price chart along with indicator panels for MACD and RSI, plus an additional overview chart that synchronizes with the main charts.

Technical Implementation

The charts are initialized asynchronously using functions such as drawPriceChart, drawMacdChart, drawRsiChart, and drawOverview. These functions leverage the SciChartSurface.create method to establish high-performance WebGL charts. Custom palette providers are implemented for the volume and MACD histogram series by extending the IStrokePaletteProvider and IFillPaletteProvider interfaces, as detailed in The PaletteProvider API. Additionally, the charts are grouped using the SciChartVerticalGroup and synchronized by subscribing to the x-axis visibleRangeChanged events, which is explained in the Tutorial 09 - Linking Multiple Charts.

Features and Capabilities

The example supports real-time chart updates, advanced technical analysis through moving average filters (see XyMovingAverageFilter API Documentation), and interactive tooltips configured via the RolloverModifier. The integration of chart modifiers such as ZoomPanModifier, ZoomExtentsModifier, and MouseWheelZoomModifier ensures seamless navigation and interaction.

Integration and Best Practices

Built with JavaScript, this implementation follows asynchronous initialization best practices outlined in Getting Started with SciChart JS, and employs performance optimization techniques recommended in Performance Tips & Tricks. The synchronized overview chart, created using the transformRenderableSeries feature, further enhances usability by providing a compact visual summary, as described in How to Link JavaScript Charts and Synchronise zooming, panning ....

Overall, the example offers a comprehensive demonstration of chart synchronization, advanced customization, and efficient performance optimizations, making it a valuable reference for developers building high-performance financial charting applications using SciChart.js and JavaScript.

javascript Chart Examples & Demos

See Also: Financial Charts (13 Demos)

JavaScript Candlestick Chart | Online JavaScript Chart Examples

JavaScript Candlestick Chart

Discover how to create a JavaScript Candlestick Chart or Stock Chart using SciChart.js. For high Performance JavaScript Charts, get your free demo now.

JavaScript OHLC Chart | Javascript Charts | SciChart.js Demo

JavaScript OHLC Chart

Easily create JavaScript OHLC Chart or Stock Chart using feature-rich SciChart.js chart library. Supports custom colors. Get your free trial now.

JavaScript Realtime Ticking Stock Chart | SciChart.js

JavaScript Realtime Ticking Stock Charts

Create a JavaScript Realtime Ticking Candlestick / Stock Chart with live ticking and updating, using the high performance SciChart.js chart library. Get free demo now.

JavaScript Orderbook Heatmap | Javascript Charts | SciChart.js

JavaScript Orderbook Heatmap

Create a Javascript heatmap chart showing historical orderbook levels using the high performance SciChart.js chart library. Get free demo now.

JavaScript Multi-Pane Stock Chart using Subcharts | View JavaScript Charts

JavaScript Multi-Pane Stock Charts using Subcharts

Create a JavaScript Multi-Pane Candlestick / Stock Chart with indicator panels, synchronized zooming, panning and cursors. Get your free trial of SciChart.js now.

Tenor Curves Demo | Javascript Charts | SciChart.js Demo

Tenor Curves Demo

Demonstrating the capability of SciChart.js to create a composite 2D &amp; 3D Chart application. An example like this could be used to visualize Tenor curves in a financial setting, or other 2D/3D data combined on a single screen.

Financial Data Filters | Javascript Charts | SciChart.js Demo

Financial Data Filters

Shows one seeded OHLC data set toggled between no filter, Heikin-Ashi, Renko, and Point & Figure views.

JavaScript Market Depth Chart | Javascript Charts | SciChart.js

JavaScript Market Depth Chart

Create a JavaScript Depth Chart, using the high performance SciChart.js chart library. Get free demo now.

JavaScript Chart Hoverable Buy Sell Marker Annotations

JavaScript Chart Hoverable Buy Sell Marker Annotations

Demonstrates how to place Buy/Sell arrow markers on a JavaScript Stock Chart using SciChart.js - Annotations API

JavaScript User Annotated Stock Chart | SciChart.js Demo

JavaScript User Annotated Stock Chart

This demo shows you how to create a <strong>{frameworkName} User Annotated Stock Chart</strong> using SciChart.js. Custom modifiers allow you to add lines and markers, then use the built in serialisation functions to save and reload the chart, including the data and all your custom annotations.

JavaScript Trading Drawing Tools | Javascript Charts | SciChart.js

JavaScript Trading Drawing Tools

Create an interactive JavaScript trading charts for technical analysis. Trading Drawing Tools Demo, which shows how to use Polylines, Extended Lines, Rays, Channels, Pitchforks, Pitchfans, Fibonnaci Retracements, Measure, Stop Loss and Take Profit chart drawing tools for Technical Analysis.

JavaScript Custom Paired Dashed Polyline Annotation

JavaScript Custom Paired Dashed Polyline Annotation

Create a custom JavaScript stock chart annotation by extending SciChart.js PolyLineAnnotation with paired dashed connectors.

JavaScript Freehand Drawing Tools | SciChart.js Demo

JavaScript Freehand Drawing Tools

An example of using JavaScript FreehandDrawingModifier for arbitrary drawing on trading and financial charts. Can be used for drawing trends, arrow, markers, text, etc.

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.