Charts
Series types
Candlesticks, bars, line, area, baseline, histogram, Heikin-Ashi and your own.
The Six Built-In Types
Every series is created through chart.addSeries(type, options) and returns a SeriesModel.
Three of the types hold OHLCV bars and three hold single values; the difference matters,
because a value series cannot be redrawn as candles.
| Type | Kind | Data | Draws |
|---|---|---|---|
candlestick |
bars | Bar[] |
Body between open and close, wicks to high and low. Hollow and Heikin-Ashi are options on this type, not separate types. |
bar |
bars | Bar[] |
A vertical high-low line with an open tick left and a close tick right. |
line |
values | points | A polyline, optionally curved, optionally with point markers. |
area |
values | points | A line with a vertical gradient fill beneath it. |
baseline |
values | points | A line whose halves above and below a base value are colored and filled separately. |
histogram |
values | points | Columns from a base value, colored fixed, by sign, or by the main series direction. |
const price = chart.addSeries("candlestick", { title: "AAPL" });
price.setData(bars);
const ma = chart.addSeries("line", { title: "EMA 21", color: "#F5A524", lineWidth: 1.5 });
ma.setData(emaPoints);@ortex-charts/financialOptions Every Series Has
These come from SeriesOptionsBase and apply to all six types and to any type you register
yourself.
| Option | Type | Default | What it does |
|---|---|---|---|
id |
string |
generated | Stable identity, useful when you restore a saved chart. |
title |
string |
"" |
Name in the legend and in the layout. Placement is keyed by it. |
pane |
string |
first pane | Which pane the series lives on. |
priceScaleId |
string |
"right" |
right, left, or any other id for an undrawn overlay scale. |
visible |
boolean |
true |
Hides the series without removing it; it keeps updating. |
color |
string |
next palette color | Line, area and histogram color. |
lineWidth |
number |
2 |
Stroke width in CSS pixels. |
lineStyle |
"solid" | "dashed" | "dotted" |
"solid" |
Stroke pattern. |
priceFormat |
PriceFormat |
price, 2 decimals | Number formatting for the axis, legend and labels. |
lastValueVisible |
boolean |
true |
Value label on the price axis. |
priceLineVisible |
boolean |
false |
Dashed horizontal line at the last value. The bar and candlestick types default it to true. |
align |
AlignMode |
"forwardFill" |
How timestamps map onto the main timeline. |
zIndex |
number |
0 |
Draw order within a pane. |
legendVisible |
boolean |
true |
Whether the series appears in the legend. |
crosshairMarkerVisible |
boolean |
true |
Dot on the series at the crosshair index. |
color left unset takes the next color from the theme palette, so several overlays added in
a row are distinguishable without any color management on your side.
Candlesticks
chart.addSeries("candlestick", {
title: "AAPL",
upColor: "#22C08A",
downColor: "#EF4E5A",
wickUpColor: "#22C08A",
wickDownColor: "#EF4E5A",
borderVisible: true,
hollowUp: false,
heikinAshi: false,
bodyWidthRatio: 0.7,
});
hollowUp draws up candles with a transparent body, which is the classic hollow-candle
style. bodyWidthRatio is the fraction of the bar spacing a body occupies; bodies never
grow wider than the gap allows and never shrink below one pixel, so a chart at maximum zoom
out still reads as candles rather than as mush.
Colors left unset fall back to the theme up, down, upWick and downWick tokens, which
is what makes a theme switch repaint candles correctly without touching the series.
Heikin-Ashi
Heikin-Ashi is an option rather than a type, so it can be toggled without recreating the series or losing the indicators computed from it.
price.applyOptions({ heikinAshi: true });
The transform runs over the raw bars whenever the data or the flag changes. Note the limitation: on a live chart the transform currently re-runs over all bars on every tick, which is measurable on very long intraday histories. Indicators still read the raw columns, so an EMA over Heikin-Ashi candles is an EMA of the real closes.
OHLC Bars
chart.addSeries("bar", { title: "AAPL", thin: false, openVisible: true });
thin drops the open and close ticks and draws only the high-low line, which is what most
people want below about four pixels of bar spacing. openVisible: false keeps the close
tick and drops the open one.
Line
chart.addSeries("line", {
title: "Cost to borrow",
curve: "linear", // "linear" | "step" | "monotone" | "smooth"
pointMarkers: false,
pointRadius: 2.5,
align: "forwardFill",
});
curve: "step" is the right choice for anything that holds a value until it changes, such
as a rating, a threshold or a daily statistic drawn on an intraday chart. monotone is a
shape-preserving spline; smooth is a basis spline that does not pass through its points,
so avoid it where the exact values matter.
Line series decimate when they are denser than the pixels available: one minimum and one maximum per pixel column. The visual result is identical and the cost stops growing with the data.
Area
chart.addSeries("area", {
title: "Estimated Short Interest",
color: "#7C5CE6",
topColor: "rgba(124, 92, 230, 0.30)",
bottomColor: "rgba(124, 92, 230, 0.02)",
baseValue: 0,
});
topColor and bottomColor are the ends of a vertical gradient; unset, they come from the
theme areaTop and areaBottom tokens. baseValue fills down to a value instead of to the
bottom of the pane, which is what you want for a series that can go negative.
Baseline
chart.addSeries("baseline", {
title: "Relative performance",
baseValue: 0, // or "first" for the first visible value
topLineColor: "#22C08A",
bottomLineColor: "#EF4E5A",
topFillColor: "rgba(34, 192, 138, 0.18)",
bottomFillColor: "rgba(239, 78, 90, 0.18)",
});
baseValue: "first" re-bases on every pan, which turns the series into "performance since
the left edge of the view" without any recomputation on your side.
Histogram
chart.addSeries("histogram", {
title: "Volume",
colorMode: "mainDirection", // "fixed" | "sign" | "mainDirection"
base: 0,
widthRatio: 0.7,
upColor: "rgba(34, 192, 138, 0.45)",
downColor: "rgba(239, 78, 90, 0.45)",
priceFormat: { type: "volume", precision: 0, minMove: 1 },
});
The three color modes cover the three things histograms are used for. fixed is one color
for a count. sign colors above and below base differently, which is what a MACD histogram
or a delta pane wants. mainDirection colors each column by whether the main series bar at
the same index closed up or down, which is what a volume pane wants — and it is why
createFinancialChart does not need you to precompute colored volume rows.
Setting and Updating Data
setData replaces everything. update handles one row and is the path live data takes.
series.setData(rows);
const appended = series.update({ time, open, high, low, close, volume });
// true when a new bar was appended, false when the last bar was replaced in place
The rules update follows are worth knowing, because the fast paths depend on them:
- A
timeequal to the last bar replaces that bar in place. - A later
timeappends into a capacity-doubling backing store, so no column is copied. - An earlier
timetakes a slower rebuild path; feeds that emit out of order pay for it.
series.holdUpdates() and series.releaseUpdates() queue updates and apply them in order
later. Bar replay uses this so a live feed can keep running while the user
replays history.
Switching Type Without Losing State
price.setType("line", { lineWidth: 2 });
setType keeps the data, the id, the pane, the scale, the title, the alignment and every
base option, and swaps only the renderer and its type-specific defaults. Indicators, markers
and drawings attached to the chart are untouched. This is what the toolbar's chart-type
buttons call, and it is why switching from candles to a line does not flash.
A value series cannot become a bar series, because it has no open, high or low. The call throws with a message that says exactly that.
Reading Values
series.valueAt(index); // { open, high, low, close, volume } or { value } or null
series.primaryValue(index); // the number the axis label and price line use
series.lastIndex(); // index of the last finite value, or -1
series.rawLength; // rows as given, before alignment
series.raw; // the struct-of-arrays form, or null before setData
series.columns; // aligned columns — a view, never hold it across a data change
Price Lines
A price line is a horizontal line at a fixed value on the series' scale, with an axis label. It belongs to the series, so it moves with the scale and disappears with it.
const id = chart.addPriceLine(series.id, {
price: 182.5,
title: "Entry",
color: "#F5A524",
lineStyle: "dashed",
lineWidth: 1,
axisLabelVisible: true,
});
chart.removePriceLine(series.id, id);
For lines the user can drag, and for crossing notifications, use alerts instead.
Writing Your Own Series Type
A series type is four functions and a defaults object. Register it once and
chart.addSeries("your-type", …) works, including in saved layouts and the legend.
import { registerSeriesType, pixelColumns, type SeriesOptionsBase, type SeriesTypeDef } from "@ortex-charts/core";
import { valueExtent } from "@ortex-charts/math";
interface DotOptions extends SeriesOptionsBase {
radius: number;
}
const dotSeries: SeriesTypeDef<DotOptions> = {
kind: "values",
defaults: { radius: 3 },
draw(ctx, view) {
const { xs, ys } = pixelColumns(view, "value");
ctx.fillStyle = view.options.color;
for (let i = 0; i < xs.length; i++) {
if (ys[i] !== ys[i]) continue; // NaN is a gap
ctx.beginPath();
ctx.arc(xs[i], ys[i], view.options.radius, 0, Math.PI * 2);
ctx.fill();
}
},
extent: (columns, from, to) => valueExtent(columns.value, from, to),
valueAt: (columns, i) => (columns.value[i] === columns.value[i] ? { value: columns.value[i] } : null),
primaryValue: (columns, i) => columns.value[i],
};
registerSeriesType("dot", dotSeries);
chart.addSeries<DotOptions>("dot", { title: "Signals", color: "#F472B6", radius: 4 }).setData(points);
The SeriesView handed to draw carries aligned columns, the visible index bounds from
and to, the mappings x(index) and y(value), the bar spacing, the resolved theme, the
device pixel ratio, the plot rectangle, the hovered index and the main series columns. Draw
only between from and to; the engine has already clipped to the pane.
Four rules keep a custom type well behaved:
- Return
nullfromextentwhen the series should not affect autoscale. - Return
nullfromvalueAtwhere there is no data, so the legend shows nothing rather thanNaN. - Treat
NaNas a gap in every column rather than as a zero. - Add an optional
colorAtwhen the series is drawn in more than one color, so the last-value label matches what is on screen.
What Is Not Here
Renko, Kagi, Point and Figure, line break, step-line bars, scatter and HLC area are not built in. They are transforms plus a renderer on the same interfaces shown above, and they are on the roadmap, but today writing one is your work rather than a configuration flag.