Candlestick
Candlestick chart is used to represent stock price movements. This example uses Bar and ErrorBar to render a candlestick chart with custom Tooltip.
import { generateMockMarketData, RechartsDevtools } from '@recharts/devtools';
import {
Bar,
BarChart,
BarShapeProps,
CartesianGrid,
DefaultZIndexes,
ErrorBar,
Rectangle,
Tooltip,
TooltipContentProps,
TooltipIndex,
XAxis,
YAxis,
useRechartsTheme,
} from 'recharts';
import { MarketCandle } from '@recharts/devtools/dist/generateMockMarketData';
const data: ReadonlyArray<MarketCandle> = generateMockMarketData(100, 1337, 100, 1768145757834);
const barDataKey: (entry: MarketCandle) => [number, number] = entry => [
Math.min(entry.close, entry.open),
Math.max(entry.close, entry.open),
];
const whiskerDataKey: (entry: MarketCandle) => [number, number] = entry => {
const highEnd = Math.max(entry.close, entry.open);
return [highEnd - entry.low, entry.high - highEnd];
};
const timestampToMinutes = (timestamp: number) => {
const date = new Date(timestamp);
return `${date.getUTCHours()}:${String(date.getUTCMinutes()).padStart(2, '0')}`;
};
const formatDollars = (value: number) => `${value.toFixed(2)}`;
const Candlestick = (props: BarShapeProps) => {
// @ts-expect-error Recharts does spread MarketCandle on the props but the types don't reflect that
const color = props.open < props.close ? 'green' : 'red';
return <Rectangle {...props} fill={color} stroke="none" />;
};
const TooltipContent = (props: TooltipContentProps) => {
const theme = useRechartsTheme();
const { active, payload } = props;
if (active && payload && payload.length) {
const firstPayload = payload[0];
if (firstPayload == null) {
return null;
}
const entry: MarketCandle = firstPayload.payload;
return (
<div
style={{
...theme?.typography,
...theme?.tooltip?.contentStyle,
padding: '0 1em',
}}
>
<p style={{ margin: 0 }}>{`Time: ${timestampToMinutes(entry.time)}`}</p>
<p style={{ margin: 0 }}>{`Open: ${formatDollars(entry.open)}`}</p>
<p style={{ margin: 0 }}>{`Close: ${formatDollars(entry.close)}`}</p>
<p style={{ margin: 0 }}>{`Low: ${formatDollars(entry.low)}`}</p>
<p style={{ margin: 0 }}>{`High: ${formatDollars(entry.high)}`}</p>
</div>
);
}
return null;
};
export default function CandlestickExample({ defaultIndex }: { defaultIndex?: TooltipIndex }) {
return (
<BarChart
data={data}
style={{ width: '100%', maxWidth: '700px', maxHeight: '70vh', aspectRatio: 1.618 }}
responsive
>
<XAxis dataKey="time" tickFormatter={timestampToMinutes} />
<YAxis domain={['dataMin - 1', 'dataMax + 1']} tickFormatter={formatDollars} />
<CartesianGrid vertical={false} />
<Bar dataKey={barDataKey} shape={Candlestick}>
<ErrorBar dataKey={whiskerDataKey} width={0} zIndex={DefaultZIndexes.bar - 1} />
</Bar>
<Tooltip content={TooltipContent} defaultIndex={defaultIndex} />
<RechartsDevtools />
</BarChart>
);
}