React Candlestick Chart

Demonstrates how to create a React Candlestick Chart using SciChart.js, High Performance JavaScript Charts

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

binanceRestClient.ts

ExampleDataProvider.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
1// SCICHART EXAMPLE
2import {
3    CursorModifier,
4    CursorTooltipSvgAnnotation,
5    DateTimeNumericAxis,
6    DiscontinuousDateAxis,
7    EAutoRange,
8    EDataSeriesType,
9    EFillPaletteMode,
10    ENumericFormat,
11    ESeriesType,
12    FastCandlestickRenderableSeries,
13    FastColumnRenderableSeries,
14    FastLineRenderableSeries,
15    FastMountainRenderableSeries,
16    FastOhlcRenderableSeries,
17    GradientParams,
18    IFillPaletteProvider,
19    IPointMetadata,
20    IRenderableSeries,
21    MouseWheelZoomModifier,
22    NumberRange,
23    NumericAxis,
24    OhlcDataSeries,
25    OhlcSeriesInfo,
26    parseColorToUIntArgb,
27    Point,
28    SciChartOverview,
29    SciChartSurface,
30    SeriesInfo,
31    XyDataSeries,
32    XyMovingAverageFilter,
33    ZoomExtentsModifier,
34    ZoomPanModifier,
35} from "scichart";
36import { appTheme } from "../../../theme";
37import { simpleBinanceRestClient } from "../../../ExampleData/binanceRestClient";
38import { ExampleDataProvider, TPriceBar } from "../../../ExampleData/ExampleDataProvider";
39import {
40    DEFAULT_LABEL_THRESHOLDS,
41    ETradeChartLabelFormat,
42} from "scichart/Charting/Visuals/Axis/LabelProvider/SmartDateLabelProvider";
43
44const Y_AXIS_VOLUME_ID = "Y_AXIS_VOLUME_ID";
45
46export const drawExample = (dataSource: string) => async (rootElement: string | HTMLDivElement) => {
47    // Create a SciChartSurface
48    const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
49        theme: appTheme.SciChartJsTheme,
50    });
51
52    // We have a hybrid DiscontinuousDateAxis which 'magically' solves problems of different # of points in stock market datasetd with gaps
53    const xAxis = new DiscontinuousDateAxis(wasmContext, {
54        // autoRange.never as we're setting visibleRange explicitly below. If you dont do this, leave this flag default
55        autoRange: EAutoRange.Never,
56        cursorLabelFormat: ENumericFormat.Date_HHMM,
57        // Increase this threshold as the default value is right on our default range
58        labelThresholds: { [ETradeChartLabelFormat.Minutes]: 60 * 60 * 24 * 10 },
59    });
60    sciChartSurface.xAxes.add(xAxis);
61
62    // Create a NumericAxis on the YAxis with 2 Decimal Places
63    sciChartSurface.yAxes.add(
64        new NumericAxis(wasmContext, {
65            growBy: new NumberRange(0.1, 0.1),
66            labelFormat: ENumericFormat.Decimal,
67            labelPrecision: 2,
68            labelPrefix: "$",
69            autoRange: EAutoRange.Always,
70        })
71    );
72
73    // Create a secondary YAxis to host volume data on its own scale
74    sciChartSurface.yAxes.add(
75        new NumericAxis(wasmContext, {
76            id: Y_AXIS_VOLUME_ID,
77            growBy: new NumberRange(0, 4),
78            isVisible: false,
79            autoRange: EAutoRange.Always,
80        })
81    );
82
83    const xValues: number[] = [];
84    const openValues: number[] = [];
85    const highValues: number[] = [];
86    const lowValues: number[] = [];
87    const closeValues: number[] = [];
88    const volumeValues: number[] = [];
89
90    // Fetch data from now to 300 1hr candles ago
91    const endDate = new Date(Date.now());
92    const startDate = new Date();
93    startDate.setHours(endDate.getHours() - 300);
94    let priceBars: TPriceBar[];
95    if (dataSource !== "Random") {
96        priceBars = await simpleBinanceRestClient.getCandles("BTCUSDT", "1h", startDate, endDate, 500, dataSource);
97    } else {
98        priceBars = ExampleDataProvider.getRandomCandles(300, 60000, startDate, 60 * 60, true);
99    }
100
101    // Maps PriceBar { date, open, high, low, close, volume } to structure-of-arrays expected by scichart
102    priceBars.forEach((priceBar: any) => {
103        xValues.push(priceBar.date);
104        openValues.push(priceBar.open);
105        highValues.push(priceBar.high);
106        lowValues.push(priceBar.low);
107        closeValues.push(priceBar.close);
108        volumeValues.push(priceBar.volume);
109    });
110    // Zoom to the latest 100 candles
111    const lastBar = priceBars[priceBars.length - 1];
112    const firstVisiblebar = priceBars[priceBars.length - 100];
113    xAxis.visibleRange = new NumberRange(firstVisiblebar.date, lastBar.date);
114
115    // Create and add the Candlestick series
116    // The Candlestick Series requires a special dataseries type called OhlcDataSeries with o,h,l,c and date values
117    const candleDataSeries = new OhlcDataSeries(wasmContext, {
118        xValues,
119        openValues,
120        highValues,
121        lowValues,
122        closeValues,
123        dataSeriesName: dataSource === "Random" ? "Random" : "BTC/USDT",
124    });
125    const candlestickSeries = new FastCandlestickRenderableSeries(wasmContext, {
126        dataSeries: candleDataSeries,
127        stroke: appTheme.ForegroundColor, // used by cursorModifier below
128        strokeThickness: 1,
129        brushUp: appTheme.VividGreen + "77",
130        brushDown: appTheme.MutedRed + "77",
131        strokeUp: appTheme.VividGreen,
132        strokeDown: appTheme.MutedRed,
133    });
134    sciChartSurface.renderableSeries.add(candlestickSeries);
135
136    // Add an Ohlcseries. this will be invisible to begin with
137    const ohlcSeries = new FastOhlcRenderableSeries(wasmContext, {
138        dataSeries: candleDataSeries,
139        stroke: appTheme.ForegroundColor, // used by cursorModifier below
140        strokeThickness: 1,
141        dataPointWidth: 0.9,
142        strokeUp: appTheme.VividGreen,
143        strokeDown: appTheme.MutedRed,
144        isVisible: false,
145    });
146    sciChartSurface.renderableSeries.add(ohlcSeries);
147
148    //Add some moving averages using SciChart's filters/transforms API
149    // when candleDataSeries updates, XyMovingAverageFilter automatically recomputes
150    sciChartSurface.renderableSeries.add(
151        new FastLineRenderableSeries(wasmContext, {
152            dataSeries: new XyMovingAverageFilter(candleDataSeries, {
153                dataSeriesName: "Moving Average (20)",
154                length: 20,
155            }),
156            stroke: appTheme.VividSkyBlue,
157        })
158    );
159
160    sciChartSurface.renderableSeries.add(
161        new FastLineRenderableSeries(wasmContext, {
162            dataSeries: new XyMovingAverageFilter(candleDataSeries, {
163                dataSeriesName: "Moving Average (50)",
164                length: 50,
165            }),
166            stroke: appTheme.VividPink,
167        })
168    );
169
170    // Add volume data onto the chart
171    sciChartSurface.renderableSeries.add(
172        new FastColumnRenderableSeries(wasmContext, {
173            dataSeries: new XyDataSeries(wasmContext, { xValues, yValues: volumeValues, dataSeriesName: "Volume" }),
174            strokeThickness: 0,
175            // This is how we get volume to scale - on a hidden YAxis
176            yAxisId: Y_AXIS_VOLUME_ID,
177            // This is how we colour volume bars red or green
178            paletteProvider: new VolumePaletteProvider(
179                candleDataSeries,
180                appTheme.VividGreen + "77",
181                appTheme.MutedRed + "77"
182            ),
183        })
184    );
185
186    // Optional: Add some interactivity modifiers
187    sciChartSurface.chartModifiers.add(
188        new ZoomExtentsModifier(),
189        new ZoomPanModifier({ enableZoom: true }),
190        new MouseWheelZoomModifier(),
191        new CursorModifier({
192            crosshairStroke: appTheme.VividOrange,
193            axisLabelFill: appTheme.VividOrange,
194            tooltipLegendTemplate: getTooltipLegendTemplate,
195        })
196    );
197
198    // Add Overview chart. This will automatically bind to the parent surface
199    // displaying its series. Zooming the chart will zoom the overview and vice versa
200
201    //Exporting at the bottom by an object-
202    // const overview = await SciChartOverview.create(sciChartSurface, divOverviewId, {
203    //     theme: appTheme.SciChartJsTheme,
204    //     transformRenderableSeries: getOverviewSeries,
205    // });
206
207    return { sciChartSurface, candlestickSeries, ohlcSeries };
208};
209
210class VolumePaletteProvider implements IFillPaletteProvider {
211    fillPaletteMode: EFillPaletteMode = EFillPaletteMode.SOLID;
212    private ohlcDataSeries: OhlcDataSeries;
213    private upColorArgb: number;
214    private downColorArgb: number;
215
216    constructor(masterData: OhlcDataSeries, upColor: string, downColor: string) {
217        this.upColorArgb = parseColorToUIntArgb(upColor);
218        this.downColorArgb = parseColorToUIntArgb(downColor);
219        this.ohlcDataSeries = masterData;
220    }
221    onAttached(parentSeries: IRenderableSeries): void {}
222    onDetached(): void {}
223
224    // Return up or down color for the volume bars depending on Ohlc data
225    overrideFillArgb(
226        xValue: number,
227        yValue: number,
228        index: number,
229        opacity?: number,
230        metadata?: IPointMetadata
231    ): number {
232        const isUpCandle =
233            this.ohlcDataSeries.getNativeOpenValues().get(index) >=
234            this.ohlcDataSeries.getNativeCloseValues().get(index);
235        return isUpCandle ? this.upColorArgb : this.downColorArgb;
236    }
237
238    // Override stroke as well, even though strokethickness is 0, because stroke is used if column thickness goes to 0.
239    overrideStrokeArgb(
240        xValue: number,
241        yValue: number,
242        index: number,
243        opacity?: number,
244        metadata?: IPointMetadata
245    ): number {
246        return this.overrideFillArgb(xValue, yValue, index, opacity, metadata);
247    }
248}
249
250// Override the standard tooltip displayed by CursorModifier
251const getTooltipLegendTemplate = (seriesInfos: SeriesInfo[], svgAnnotation: CursorTooltipSvgAnnotation) => {
252    let outputSvgString = "";
253
254    // Foreach series there will be a seriesInfo supplied by SciChart. This contains info about the series under the house
255    seriesInfos.forEach((seriesInfo, index) => {
256        const y = 20 + index * 20;
257        const textColor = seriesInfo.stroke;
258        let legendText = seriesInfo.formattedYValue;
259        if (seriesInfo.dataSeriesType === EDataSeriesType.Ohlc) {
260            const o = seriesInfo as OhlcSeriesInfo;
261            legendText = `Open=${o.formattedOpenValue} High=${o.formattedHighValue} Low=${o.formattedLowValue} Close=${o.formattedCloseValue}`;
262        }
263        outputSvgString += `<text x="8" y="${y}" font-size="13" font-family="Verdana" fill="${textColor}">
264            ${seriesInfo.seriesName}: ${legendText}
265        </text>`;
266    });
267
268    return `<svg width="100%" height="100%">
269                ${outputSvgString}
270            </svg>`;
271};
272
273// Override the Renderableseries to display on the scichart overview
274const getOverviewSeries = (defaultSeries: IRenderableSeries) => {
275    if (defaultSeries.type === ESeriesType.CandlestickSeries) {
276        // Swap the default candlestick series on the overview chart for a mountain series. Same data
277        return new FastMountainRenderableSeries(defaultSeries.parentSurface.webAssemblyContext2D, {
278            dataSeries: defaultSeries.dataSeries,
279            fillLinearGradient: new GradientParams(new Point(0, 0), new Point(0, 1), [
280                { color: appTheme.VividSkyBlue + "77", offset: 0 },
281                { color: "Transparent", offset: 1 },
282            ]),
283            stroke: appTheme.VividSkyBlue,
284        });
285    }
286    // hide all other series
287    return undefined;
288};
289
290export const overviewOptions = {
291    theme: appTheme.SciChartJsTheme,
292    transformRenderableSeries: getOverviewSeries,
293};
294

Candlestick Chart Example (React)

Overview

This example demonstrates how to implement a high performance candlestick chart using SciChart.js within a React framework. The chart is designed to render financial data, visualize candlestick and OHLC series, and integrate advanced features such as moving average filters and a custom volume palette provider. Additionally, it leverages a chart overview component to provide users with a synchronized miniature view of the main chart.

Technical Implementation

The chart is initialized by asynchronously creating a SciChartSurface and its associated WebAssembly context using the SciChartSurface.create method. DateTime and Numeric axes are set up with precise configuration of visible ranges and auto-ranging options. Data is mapped into an OhlcDataSeries and rendered with a FastCandlestickRenderableSeries. Moving average filters are applied with the XyMovingAverageFilter to dynamically update trend lines as new data arrives. A custom palette provider is implemented to automatically color volume bars based on candle data. Interactivity is enhanced through modifiers such as ZoomPanModifier and CursorModifier, providing users with responsive zooming, panning, and tooltip capabilities.

Features and Capabilities

  • Real-time Data Updates: The example supports dynamic data sources, toggling between random and external API data, which demonstrates best practices for handling live data in a React state workflow. Learn more about real-time update techniques in the Realtime Updates Tutorial.
  • Moving Average Filtering: Automatic recomputation of moving averages when the underlying data changes ensures a smooth visual transition and accurate trend analysis.
  • Custom Volume Palette Provider: A custom implementation dynamically assigns colors to volume bars based on individual candle performance, enhancing visual insights into trading volumes.
  • Interactive Modifiers: The integration of various modifiers such as zoom, pan, and custom tooltips allows users to explore the chart data interactively.
  • Overview Chart Integration: The use of SciChartNestedOverview from scichart-react provides a synchronized, miniature view of the main chart, making navigation through large datasets more intuitive.

Integration and Best Practices

The example is built with React using components like <SciChartReact/> for chart rendering and Material-UI’s ToggleButtonGroup for user interaction. React hooks manage dynamic state changes, such as toggling between candlestick and OHLC series and switching data sources. For instance, the Material-UI ToggleButtonGroup is employed to change series visibility, enhancing the user interface. Refer to the Material UI ToggleButtonGroup documentation for more details on its configuration.

Performance optimizations are achieved through efficient WebAssembly integration and the use of optimized data structures, as highlighted in the Why SciChart High Performance Realtime Big Data Charts article. Overall, this example provides a comprehensive guide for developers looking to build interactive, high-performance financial charts in React using SciChart.js.

react Chart Examples & Demos

See Also: Financial Charts (9 Demos)

React OHLC Chart | React Charts | SciChart.js Demo

React OHLC Chart

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

React Realtime Ticking Stock Chart | SciChart.js Demo

React Realtime Ticking Stock Charts

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

NEW!
React Orderbook Heatmap | React Charts | SciChart.js Demo

Order Book Heatmap

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

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

React Multi-Pane Stock Charts using Subcharts

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

Tenor Curves Demo | React 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.

React Multi-Pane Stock Chart | View JavaScript Charts

React Multi-Pane Stock Charts using Sync Multi-Chart

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

React Market Depth Chart | React Charts | SciChart.js Demo

React Market Depth Chart

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

React Chart Hoverable Buy Sell Marker Annotations | SciChart

React Chart Hoverable Buy Sell Marker Annotations

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

React User Annotated Stock Chart | React Charts | SciChart.js

React 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.

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