Angular Candlestick Chart

Demonstrates how to create an Angular Candlestick Chart using SciChart.js, High Performance JavaScript Charts

Fullscreen

Edit

 Edit

Docs

drawExample.ts

angular.ts

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

Angular Candlestick Chart

Overview

This example demonstrates an Angular integration of SciChart.js to create a high-performance candlestick chart. It fetches financial price data and displays it using both candlestick and OHLC series, alongside moving average filters and volume rendering. The implementation leverages Angular standalone components as outlined in Angular Standalone Components.

Technical Implementation

The chart is initialized via a dedicated function passed as an input property to a SciChart Angular component, illustrating the use of Angular input binding as described in Accepting Data with Input Properties. The initialization function (drawExample) creates a SciChartSurface with WebAssembly-enabled rendering for optimal performance, an approach further detailed in Leveraging WebAssembly in Angular. The implementation configures axes, multiple series, and interactive modifiers to deliver a responsive charting experience.

Features and Capabilities

Key features include dynamic series toggling between candlestick and OHLC views using SciChart.js’ visibility APIs as outlined in the Series isVisible and isVisibleChanged API. The example also applies advanced financial data filters such as moving averages, a technique described in the Moving Average Filter documentation, to assist with trend analysis and data smoothing.

Integration and Best Practices

Integration with Angular Material is evident through the use of toolbars and toggle buttons for interactive chart control. In addition, careful management of Angular’s change detection with external libraries is addressed, helping to optimize performance as discussed in Angular Change Detection with External Libraries. This example serves as a practical guide for developers seeking to integrate high-performance financial charting into Angular applications while adhering to best practices in component design and performance optimization.

angular Chart Examples & Demos

See Also: Financial Charts (9 Demos)

Angular OHLC Chart | Angular Charts | SciChart.js Demo

Angular OHLC Chart

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

Angular Realtime Ticking Stock Chart | SciChart.js Demo

Angular Realtime Ticking Stock Charts

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

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

Angular Orderbook Heatmap

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

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

Angular Multi-Pane Stock Charts using Subcharts

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

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

Angular Multi-Pane Stock Chart | View JavaScript Charts

Angular Multi-Pane Stock Charts using Sync Multi-Chart

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

Angular Market Depth Chart | Angular Charts | SciChart.js

Angular Market Depth Chart

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

Angular Chart Hoverable Buy Sell Marker Annotations

Angular Chart Hoverable Buy Sell Marker Annotations

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

Angular User Annotated Stock Chart | SciChart.js Demo

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