openalgo-charts 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,12 +4,12 @@
4
4
 
5
5
  **A from-scratch, dependency-free HTML5-canvas charting engine for OpenAlgo.**
6
6
 
7
- Professional interactive charts, indicators, drawing tools, order flow, and on-chart trading six lazy-loaded tiers, zero runtime dependencies, ~37 KB Brotli for the base engine.
7
+ Professional interactive charts, indicators, drawing tools, order flow, market replay, and on-chart trading. Six lazy-loaded tiers, zero runtime dependencies, ~49 KB Brotli for the base engine.
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/openalgo-charts.svg?color=cb3837&label=npm)](https://www.npmjs.com/package/openalgo-charts)
10
10
  [![license](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](./LICENSE)
11
- [![bundle](https://img.shields.io/badge/brotli-37%20KB%20base%20%C2%B7%2088%20KB%20all%20tiers-brightgreen.svg)](#size-budget)
12
- [![tests](https://img.shields.io/badge/tests-1001%20passing-brightgreen.svg)](#develop)
11
+ [![bundle](https://img.shields.io/badge/brotli-49%20KB%20base%20%C2%B7%20106%20KB%20all%20tiers-brightgreen.svg)](#size-budget)
12
+ [![tests](https://img.shields.io/badge/tests-1543%20passing-brightgreen.svg)](#develop)
13
13
  [![dependencies](https://img.shields.io/badge/runtime%20deps-0-brightgreen.svg)](#principles)
14
14
 
15
15
  [**Documentation**](https://marketcalls.github.io/openalgo-charts/)  ·  [**Live examples**](https://marketcalls.github.io/openalgo-charts/examples)  ·  [**Getting started**](./docs/getting-started.md)  ·  [**Architecture**](./ARCHITECTURE.md)
@@ -60,14 +60,14 @@ Import only what you use. Each tier is a separate bundle that registers into the
60
60
 
61
61
  | Import | Contents | Brotli |
62
62
  |---|---|---|
63
- | `openalgo-charts` | Engine, 13 chart types, panes & scales, primitives, registries, chart state, trading overlay, OpenAlgo feeds | 37.0 KB |
64
- | `openalgo-charts/indicators` | 91 built-in indicators + the Tier-2 (external-data) contract | 24.7 KB |
63
+ | `openalgo-charts` | Engine, 13 chart types, panes & scales, primitives, registries, chart state, trading overlay, OpenAlgo feeds | 49.4 KB |
64
+ | `openalgo-charts/indicators` | 91 built-in indicators + the Tier-2 (external-data) contract | 24.9 KB |
65
65
  | `openalgo-charts/draw` | 43 drawing tools + a headless drawing controller | 11.7 KB |
66
66
  | `openalgo-charts/transform` | Heikin Ashi, Renko, Range bars, Line Break, Point & Figure, Kagi | 2.7 KB |
67
- | `openalgo-charts/profile` | Volume Profile, Market Profile (TPO), Footprint, order flow | 10.1 KB |
67
+ | `openalgo-charts/profile` | Volume Profile, Market Profile (TPO), Footprint, order flow | 10.7 KB |
68
68
  | `openalgo-charts/trade` | Order / position / bracket tools + DOM ladder | 6.6 KB |
69
69
 
70
- Everything together is **88.2 KB Brotli**. Figures are the measured `size-limit` output; the trade tier is a delta over the base, which is why base + trade (43.6 KB) is less than their listed sum.
70
+ Everything together is **105.9 KB Brotli**. Figures are the measured `size-limit` output; the trade tier is a delta over the base, which is why base + trade (56.0 KB) is less than their listed sum.
71
71
 
72
72
  ## What's built
73
73
 
@@ -101,8 +101,61 @@ draw.setTool('trend-line'); // the next two clicks place it
101
101
 
102
102
  Headless by design — no toolbar, no dialogs. Placement with live preview, selection, whole-shape and per-anchor dragging, magnet snap to O/H/L/C, undo/redo (a drag is one step), and persistence. Anchors are `{ time, price }`, never pixels, so they survive zoom and resolve inside collapsed session gaps and past the last bar.
103
103
 
104
- ### Panes & legends
105
- Draggable pane dividers, move / maximize / remove, and pane legends showing one reading per plot in that plot's own colour, with inline show-hide / settings / move / delete controls revealed on hover.
104
+ ### Panes, scales & legends
105
+ Draggable pane dividers, move / maximize / remove, and pane legends showing one reading per plot in that plot's own colour, with inline show-hide / settings / move / delete controls revealed on hover. The status line is switchable field by field (logo, title, market status, OHLC, bar change, volume, last day change, last value) over a host-supplied data source.
106
+
107
+ Each pane carries a right, a left and a hidden overlay price scale, in four modes: linear, logarithmic, and the two rebasing modes **percentage** (`+3.42%`) and **indexed-to-100** (`103.42`), which quote every price against a baseline taken from the first visible bar, so panning re-bases the axis.
108
+
109
+ ### Reference levels and axis chrome
110
+
111
+ ```ts
112
+ import { PriceLevels } from 'openalgo-charts';
113
+
114
+ const levels = new PriceLevels({
115
+ levels: { previousClose: { line: true, label: true }, sessionHigh: { line: true, label: false } },
116
+ });
117
+ chart.addPrimitive(levels, 0);
118
+ levels.available('bid'); // false until a quote is fed: render that control disabled, not hidden
119
+ ```
120
+
121
+ One primitive over ten levels: previous close, session high and low, last price, the four extended-hours opens and closes, and bid and ask. Each level's line across the plot and its tag on the price axis are two flags in the same options group, so they cannot drift apart. The session comes from the gaps in the bars rather than from a calendar midnight, and the session in view follows the viewport's right edge, so scrolling back through history moves the previous close back with it. A level with no data is `null`, never `0`: nothing draws at zero, and `available(kind)` is the signal to render that control disabled with its state visible instead of hiding it.
122
+
123
+ Axis chrome is off until a chart asks for it. `createChart(el, { axisChrome: { sessionClock: true, barCountdown: true } })` puts a live clock in the corner where the two axis strips meet, in the chart's own timezone with the zone's UTC offset under it, and a countdown to the current bar's close as a second row inside the last-price tag, with the interval read back off the bars so a timeframe switch is followed. Tick labels that the last-price tag would cover are dropped rather than drawn through it, on a priority order that puts the crosshair above the last price, above a price line, above a session level.
124
+
125
+ ### Timezones
126
+
127
+ ```ts
128
+ const chart = createChart(el, { timezone: 'America/New_York' });
129
+ chart.setTimezone('Europe/London'); // relabels and recomputes on the next frame
130
+ ```
131
+
132
+ An IANA name, never a fixed offset, so daylight saving is followed rather than approximated. The zone drives the time axis (including which ticks escalate to a day, month or year label), the crosshair time tag, and every calendar-anchored study (VWAP and TWAP anchors, CPR's weekly and monthly frames, the month a Seasonality bar counts in), and it rides along in `getState()`. Profile session windows carry their own zone, so `TRADING_HOURS['us-regular']` reads as 09:30-16:00 `America/New_York` whatever the chart is displayed in. The default is `Asia/Kolkata` on the same fixed-offset arithmetic it always used, so a chart that names no zone labels and computes exactly as before.
133
+
134
+ ### Market replay
135
+
136
+ ```ts
137
+ import { ReplayController } from 'openalgo-charts';
138
+
139
+ const replay = new ReplayController(chart, { bars, startIndex: 200, barMs: 500 });
140
+ replay.play({ speed: 2 }); // emits replay:frame per bar
141
+ ```
142
+
143
+ Headless: the controller owns the playhead and ships no DOM, so the transport bar is yours to draw from `state()` and the `replay:*` events. Each step hands the series a prefix of the session through the ordinary `setData` path, which is what makes every indicator, level, fill, marker and legend row reconstruct itself as it stood at that bar. `stop()` puts the full history and the exact viewport back.
144
+
145
+ ### Symbol comparison
146
+
147
+ ```ts
148
+ import { addComparison } from 'openalgo-charts';
149
+
150
+ const bn = addComparison(chart, { symbol: 'BANKNIFTY', bars });
151
+ ```
152
+
153
+ The comparison rides the pane's hidden overlay scale in its own real prices, the pane rebases to percentage (or indexed-to-100), and the overlay's range is mirrored from the primary's, so equal percentage moves land on equal pixels instead of each line filling the pane. Alignment is by timestamp: a comparison print with no primary bar is dropped, a primary bar with no print becomes a gap.
154
+
155
+ ### Settings & context menu
156
+ `chartSettingsSchema(chart)` describes a full settings dialog as tabs of controls, in the same descriptor vocabulary the indicator settings form already uses; `readChartSettings` and `applyChartSettings` are its round trip over flat, JSON-safe keys. Five tabs (Price, Readout, Axes, Appearance, Trading), and a bullish/bearish pair is **one** `colorPair` row carrying its switch and both swatches instead of two stacked rows. Grid, crosshair, scale text, plot margins, status-line fields, the chart timezone, trading colours and the primary series' own style are all real options behind it, so no control in the schema is inert.
157
+
158
+ `chart.on('contextmenu', ...)` reports the pane, price, time, logical index and what sits under the pointer: a drawing, an indicator instance, a legend, a primitive, a series, a price scale (with the side and the scale id it names), the time scale, or empty plot. For a menu raised on a price axis, `chart.priceAxisState(pane, scaleId)` reads back every item that menu draws (auto-fit, invert, scale mode, price-per-bar lock, whether the axis is movable) and `setPriceAxisOptions`, `setPriceAxisAutoFit`, `setPriceAxisLockRatio` and `movePriceAxis` act on it, so no row is ticked with nothing behind it.
106
159
 
107
160
  ### Trading
108
161
  Order, position, and bracket lines with live P&L, one-click and drag-to-modify, OCO, validation, an order state machine, analyzer (sandbox) mode, and a depth-of-market ladder (5 to 200 levels).
@@ -111,10 +164,10 @@ Order, position, and bracket lines with live P&L, one-click and drag-to-modi
111
164
  Volume Profile, Market Profile (TPO), Footprint, and cumulative delta.
112
165
 
113
166
  ### State
114
- `chart.getState()` / `chart.restoreState()` capture the viewport, grid, panes, price scales, indicator instances, and drawings as one JSON payload saved layouts and templates with no extra storage plumbing.
167
+ `chart.getState()` / `chart.restoreState()` capture the viewport, grid, panes, price scales, indicator instances, drawings, and the whole settings block (canvas, status line, trading colours, event filters) as one JSON payload: saved layouts and templates with no extra storage plumbing.
115
168
 
116
169
  ### Data
117
- OpenAlgo REST history + WebSocket ticks with auto-reconnect and resubscribe, live candle aggregation, tick/volume bars, a unified `chart.on(...)` event bus, markers and signals, earnings/dividend/expiry event markers, and custom price/time formatters.
170
+ OpenAlgo REST history + WebSocket ticks with auto-reconnect and resubscribe, live candle aggregation, tick/volume bars, a unified `chart.on(...)` event bus, markers and signals, earnings/dividend/expiry event markers, an IANA chart timezone, and custom price/time formatters.
118
171
 
119
172
  ## Size budget
120
173
 
@@ -122,13 +175,13 @@ Enforced in CI by [`size-limit`](./.size-limit.json) — nothing is excluded, be
122
175
 
123
176
  | Bundle | Limit | Actual |
124
177
  |---|---|---|
125
- | Base engine | 40 KB | 37.04 KB |
126
- | Base + trade | 47 KB | 43.62 KB |
127
- | Indicators tier | 21 KB | 20.09 KB |
178
+ | Base engine | 55 KB | 49.37 KB |
179
+ | Base + trade | 62 KB | 55.95 KB |
180
+ | Indicators tier | 27 KB | 24.88 KB |
128
181
  | Draw tier | 14 KB | 11.73 KB |
129
182
  | Transform tier | 5 KB | 2.66 KB |
130
- | Profile tier | 11 KB | 10.12 KB |
131
- | **Everything** | **90 KB** | **88.21 KB** |
183
+ | Profile tier | 11 KB | 10.66 KB |
184
+ | **Everything** | **120 KB** | **105.88 KB** |
132
185
 
133
186
  ## Documentation
134
187
 
@@ -151,7 +204,7 @@ Teach your AI coding assistant this library:
151
204
  npx skills add https://github.com/marketcalls/openalgo-charts
152
205
  ```
153
206
 
154
- Installs six skills from [`.github/skills/`](./.github/skills) - a reference hub with 18 deep-dive files covering the whole API surface and its foot-guns, plus task skills for scaffolding a chart, adding indicators, building a terminal, writing a plugin, and debugging. Works with Claude Code, Cursor, Codex, Copilot, Gemini CLI and the rest of the `skills` CLI's supported agents.
207
+ Installs six skills from [`.github/skills/`](./.github/skills) - a reference hub with 20 deep-dive files covering the whole API surface and its foot-guns, plus task skills for scaffolding a chart, adding indicators, building a terminal, writing a plugin, and debugging. Works with Claude Code, Cursor, Codex, Copilot, Gemini CLI and the rest of the `skills` CLI's supported agents.
155
208
 
156
209
  ## Examples
157
210
 
@@ -168,7 +221,7 @@ cd examples/yfinance && pip install -r requirements.txt && python server.py
168
221
  ```bash
169
222
  npm install # install dev toolchain
170
223
  npm run typecheck # strict TypeScript check
171
- npm test # unit tests (vitest) - 1001 across 61 files
224
+ npm test # unit tests (vitest) - 1543 across 81 files
172
225
  npm run build # Rollup -> dist/ (minified ESM per tier + types)
173
226
  npm run size # size-limit (Brotli) against the budget
174
227
  npm run e2e # Playwright Chromium smoke tests
@@ -185,14 +238,14 @@ npm run verify # typecheck + test + build + size
185
238
 
186
239
  ## Status & limitations
187
240
 
188
- Version **1.1.0**. All engine build phases are implemented with 1001 unit tests across 61 files.
241
+ Version **1.3.0**. All engine build phases are implemented with 1558 unit tests across 84 files.
189
242
 
190
243
  Known gaps, stated plainly:
191
244
 
192
245
  - **Footprint and order flow need trade-by-trade data classified bid/ask.** OpenAlgo does not store this by default, so it is live-session-only unless you add a tick recorder — `FootprintAggregator` is the live path. See [`ARCHITECTURE.md`](./ARCHITECTURE.md) §6A.
193
246
  - **Only `Footprint` is theme-aware among the profile primitives.** `VolumeProfile`, `MarketProfile` and `HorizontalProfile` never read `rc.theme`; their defaults are dark-tuned, so a light theme needs explicit colours. `HorizontalProfile` also hardcodes its POC / value-area line colours and has no `setOptions`.
194
247
  - The OpenAlgo **WS/trade adapter wire schemas** ship with injectable transports and offline tests, but the exact field names should be verified against your running OpenAlgo build.
195
- - Price-scale **`percentage`** and **`indexed-to-100`** modes are not implemented. (Hidden overlay scales *are* add a series with `priceScaleId: ''`.)
248
+ - **A pane has exactly one hidden overlay scale**, so every symbol comparison on a pane shares one baseline. That is right for a single comparison, the common case, but a second one on the same pane is quoted against the first instrument's price; put further instruments on their own pane with `paneIndex` until the overlay scales are keyed.
196
249
  - An optional **DOM chrome package** (toolbar, dialogs, command palette, objects panel) is the next planned piece; today that UI lives in the examples.
197
250
 
198
251
  See [`ARCHITECTURE.md`](./ARCHITECTURE.md) §13a for the full deferred list.