# chart-live-stock-data

> Live AAPL stock chart that refreshes prices with zooming, crosshair, and tooltip tools.

**Framework:** react  **Component:** Chart  **Variant:** live-stock-data

## Get this item

**If you are an agent, fetch the JSON.** Source is inlined, so one request is enough and no tooling is required:

```
GET https://ai.syncfusion.com/r/react/js/chart-live-stock-data.json
```

**Install Package(s)**

```bash
npm install @syncfusion/ej2-react-charts
```

**Notes**

- Syncfusion release: 2026 Volume 2 (v34.1.29)
- The Syncfusion package is licensed. The composition in this file is source you own and edit. See https://ai.syncfusion.com/licensing.md

## Source files

### src/components/chart-live-stock-data/Chart.jsx

```jsx
/**
 * Sample for Candle Series
 */
import { useState, useRef } from "react";
import { ChartComponent, SeriesCollectionDirective, LastValueLabel, CandleSeries, Category, Tooltip, DateTime, Zoom, Logarithmic, ColumnSeries, Crosshair, StripLine, SeriesDirective, Inject, ChartAnnotation } from '@syncfusion/ej2-react-charts';
import { Browser } from '@syncfusion/ej2-base';

let value = 180;
let getData = () => {
    let series = [];
    let point;
    for (let i = 0; i < 30; i++) {
        value = 180 + (Math.random() * 25) * Math.sin(i * Math.PI / 8); // Adjust the function as needed
        value = Math.max(140, Math.min(260, value));
        if (value > 260) {
            value = 260;
        }
        if (value < 140) {
            value = 140;
        }
        value += Math.random() * 0.1;
        let open = value + Math.round(Math.random() * 18);
        let low = Math.min(value, open) - Math.round(Math.random() * 6);
        let high = Math.min(220, Math.max(value, open) + Math.round(Math.random() * 15));
        point = {
            x: new Date(2000, 5, 2, 2, 0, i),
            close: value,
            open: open,
            low: low,
            high: high
        };
        series.push(point);
    }
    return { series: series };
};
let data = getData().series;
let incVal = 0;
let updateVal = data.length;
let pointAdded = false;
const SAMPLE_CSS = `
    .control-fluid {
        padding: 0px !important;
    }`;
/**
 * Candle sample
 */
const LiveStock = () => {
    let [intervalId, setIntervalId] = useState(null);
    let chartInstance = useRef(null);
    const load = (args) => {
        clearIntervalFn();
        intervalId = setInterval(function () {
            var container = document.getElementById('stock');
            if (container && container.id === args.chart.element.id) {
                let newData1 = [];
                let value = 180;
                pointAdded = true;
                for (let i = 0; i < args.chart.series[0].dataSource.length; i++) {
                    newData1.push(Object.assign({}, args.chart.series[0].dataSource[i]));
                }
                if (newData1.length > 0) {
                    const lastIndex = newData1.length - 1;
                    const previousClose = newData1[lastIndex].close;
                    newData1[lastIndex].close += (Math.random() < 0.5 ? 1 : -1) * Math.random() * 25;
                    newData1[lastIndex].close = Math.min(Math.min(Math.max(newData1[lastIndex].close, newData1[lastIndex].low + 5), newData1[lastIndex].high - 5), newData1[lastIndex].open - 2);
                    if (previousClose === newData1[lastIndex].close) {
                        newData1[lastIndex].close -= 5;
                    }
                }
                if (incVal < 10) {
                    if (args.chart.series.length > 0) {
                        args.chart.series[0].setData(newData1);
                        incVal++;
                    }
                }
                else {
                    let change = (Math.random() < 0.49 ? 1 : -1) * Math.random() * 10;
                    value += change;
                    if (value > 260) {
                        value = 260;
                    }
                    if (value < 140) {
                        value = 140;
                    }
                    value += Math.random() * 0.1;
                    let open = value + Math.round(Math.random() * 12);
                    let low = Math.min(value, open) - Math.round(Math.random() * 8);
                    let high = Math.max(value, open) + Math.round(Math.random() * 15);
                    if (args.chart.series.length > 0) {
                        var lastDataPointIndex = args.chart.series[0].dataSource.length - 1;
                        if (lastDataPointIndex >= 0) {
                            var timestamp = args.chart.series[0].dataSource[lastDataPointIndex].x;
                            var lastTimestamp = new Date(timestamp).getTime();
                            args.chart.series[0].addPoint({ x: new Date(lastTimestamp + 1000), high: high, low: low, open: open, close: value });
                        }
                    }
                    incVal = 0;
                    updateVal++;
                }
            }
            else {
                clearIntervalFn();
            }
        }, 1000);
        if (intervalId)
            setIntervalId(intervalId);
    };
    const clearIntervalFn = () => {
        if (intervalId) {
            clearInterval(intervalId);
            setIntervalId(null);
        }
    };
    const axisRangeCalculated = (args) => {
        if (args.axis.name === 'primaryXAxis') {
            let lastPoint = args.axis.series[0].points[args.axis.series[0].points.length - 1].x;
            args.maximum = new Date(Number(lastPoint)).getTime() + 2500;
            let firstPoint = args.axis.series[0].points[0].x;
            args.minimum = new Date(Number(firstPoint)).getTime() + 500;
        }
    };
    const pointRender = (args) => {
        args.series.lastValueLabel.background = args.fill;
    };
    return (<div className='control-pane'>
            <style>{SAMPLE_CSS}</style>
            <div className='control-section'>
                <div className="row">
                    <ChartComponent id='stock' ref={chartInstance} style={{ textAlign: "center" }} load={load.bind(this)} primaryXAxis={{ valueType: 'DateTime', interval: Browser.isDevice ? 8 : 4, edgeLabelPlacement: Browser.isDevice ? 'None' : 'Shift', crosshairTooltip: { enable: true }, majorGridLines: { width: 0 }, labelIntersectAction: 'Hide' }} primaryYAxis={{ interval: 20, minimum: 120, opposedPosition: true, crosshairTooltip: { enable: true }, lineStyle: { width: 0 }, majorGridLines: { width: 1 }, majorTickLines: { width: 0 } }} width={Browser.isDevice ? '100%' : '90%'} chartArea={{ border: { width: 0 } }} title="AAPL Historical" crosshair={{ enable: true, dashArray: '5,5' }} pointRender={pointRender.bind(this)} axisRangeCalculated={axisRangeCalculated.bind(this)}>
                        <Inject services={[CandleSeries, StripLine, Category, Tooltip, DateTime, Zoom, ColumnSeries, Logarithmic, Crosshair, ChartAnnotation, LastValueLabel]}/>
                        <SeriesCollectionDirective>
                            <SeriesDirective type='Candle' bearFillColor='#2ecd71' bullFillColor='#e74c3d' dataSource={data} columnWidth={0.4} xName='x' low='low' high='high' open='open' close='close' lastValueLabel={{ enable: true, background: 'red', dashArray: '3,2', lineWidth: 0.5, font: { size: '10px' } }}/>
                        </SeriesCollectionDirective>
                    </ChartComponent>
                </div>
            </div>
        </div>);
};
export default LiveStock;
```
