Changelog

Depth is pre-1.0. Minor versions may break the public API; 1.0 is the freeze. Anything not exported from @christtrade/depth is internal and can change in a patch without a note here.

Format follows Keep a Changelog.

Unreleased

0.19.0 - 2026-10-19

Added

  • ChartModel.onPluginsRemoved(fn), and setPlugins takes the ids you removed as an optional second arg.
  • after-background overlay phase: over the background, under grid and candles. before-base got painted over by the background fill, so chart backgrounds had nowhere to go
  • Top toolbar buttons active color
  • Background canvas layer under base, made by the engine so the RenderEngine constructor doesn't change. markDirty('background') repaints it alone, so an animated background doesn't redraw every candle with it.
  • Draw hooks get a 4th arg, DrawInfo: canvas size, dpr, the main plot rect, every pane's box, the resolved background color and the frame time, all css px. No more getTransform() maths to find the canvas size, and a hook can stay clear of the price axis.
  • DrawInfo and DrawPhase exported.
  • ctx.schedule.frames(fps, (time, dt) => ...), an animation loop. fps 0 runs every frame. Skips frames while the chart is off screen, and the first call back gets one interval as dt so motion doesn't jump. raf only ever ran once, so a loop meant a hand-rolled requestAnimationFrame and cleaning it up yourself.
  • Extension params, edited from a gear on the extension's row in the Plugin Manager. Same field types as indicators. ctx.params reads them, ctx.onParamsChange(fn) hears changes, and an extension with no listener gets reinstalled instead, debounced 300ms so typing doesn't reload it per key. Values persist per plugin, in the getSettings store.
  • DepthChart.getExtensionParams(id) and setExtensionParams(id, patch), for hosts with their own settings UI.
  • DrawInfo.cell and DrawInfo.focused, so a hook can draw on one chart of a layout only.
  • DepthChart.getRenderEngines(), every cell's engine by cell id, and DepthChart.addOverlay.
  • RenderEngine.cellId, RenderEngine.transformer, and a render-engine:destroyed event.
  • --sunken and --raised theme tokens (bg-sunken, bg-raised), a step under the page and a step over a card.
  • brand-50 to brand-950, the accent as a theme token scale (--brand-<shade>, rgb channels so /60 works). Blue by default, so nothing changes unless the host sets its own.
  • Themes: chart.registerTheme(), setTheme(), getTheme() and getThemes(), and a theme chart option to start on. Registering an id again replaces it, and unregistering the theme the chart is on falls back to dark. BUILTIN_THEMES and DEFAULT_THEME_ID exported.
  • ThemeDef.dark, defaults to true.
  • ThemeDef.chart: the canvas colors a theme draws with - candles, grid, background, crosshair, price line, heatmap. A color still at its default follows the theme, one the user picked wins, so switching theme never overwrites a choice. themedSettings(), CHART_COLOR_KEYS and ChartColors exported for hosts with their own settings UI.
  • Built-in themes: One Dark, Midnight, Nord, Catppuccin, Tokyo Night, Gruvbox, Dracula and Rosé Pine, each with its own UI tokens, accent and canvas colors. dark stays the default and sets nothing, so the host's CSS and the chart defaults are untouched until another theme is picked.
  • Light built-ins: Light, Catppuccin Latte, Rosé Pine Dawn, Gruvbox Light and Solarized Light, canvas included.
  • A theme's vars are applied to depth's own elements (.depth-root, portaled panels and tooltips included), so an app with no CSS of its own still gets themed toolbars and dialogs. A theme with no vars leaves the host's CSS in charge. Names and values that could break out of the rule are dropped.
  • Chart settings for the colors that were fixed in the renderer: axisTextColor, axisBorderColor, crosshairLabelColor, crosshairLabelTextColor, priceLabelTextColor, bidLineColor and askLineColor. Themes color them too, so a light theme no longer gets grey-on-dark axis labels.
  • ctx.registerTheme(theme) works now. Gated on theme:register, removed on uninstall, and an extension's theme survives a hot reload without the chart dropping to the default.
  • theme:list event, every theme, fired when one's registered, replaced or unregistered. Pickers can follow plugin themes without polling getThemes().
  • BASE_DARK_VARS, the vars every built-in dark theme starts from. Spread it and override what's different, instead of copying 30-odd tokens to change the accent.
  • pure-white color, for text on a colored fill that stays white on every theme.

Changed

  • white is a theme token now, --white as rgb channels: white on dark themes, dark ink on light ones. text-white/55 and every other white overlay flip with the theme instead of going invisible on a light one. Dark themes set white: '255 255 255', so nothing changes there.
  • gray, slate, zinc and neutral read --<name>-<shade> too, falling back to Tailwind's own values. The light built-ins set them to the scale run backwards, so text-slate-300 stays readable on a light page.
  • theme:change carries the whole ThemeDef instead of 'light' | 'dark'.
  • lifecycle.onThemeChange callbacks get the theme as a second arg, after the mode.
  • The chart settings dialog shows the colors the chart draws with, theme included.
  • "Plugins" title becomes "Plugin Manager" in the plugin manager dropdown.
  • Adding or removing an overlay repaints the chart.
  • after-background hooks draw on the background layer, and only repaint when it's dirty, on resize or on a background color change. Not on pan or zoom.
  • The base layer is transparent where nothing's drawn. An after-base hook reading it gets the candles without the background.
  • toDataURL and captureComposite include the background layer.
  • Every draw phase runs inside save/restore with the ctx. Before, only after-background did, and the rest got whatever transform the renderer left behind.
  • DepthChart.renderEngine is the focused cell's. It used to be whichever cell mounted last.
  • Dropdown panels open over 200ms with an ease-out curve and a 3% zoom instead of 5%, and close in 150ms
  • Toolbars, dropdowns and dialogs color their surfaces from theme tokens instead of hex, so a host theme reaches them. They were stuck on the default dark.
  • Selected, focused and checked states use brand-* instead of blue-*, so the accent follows the host's theme.

Deprecated

  • TransformedDrawHook, use DrawHook. It was typed (ctx, transformer), which no hook was ever called with. It's an alias of DrawHook now.

Fixed

  • The order panel, symbol switcher rows, active indicator row and layout picker icon were hardcoded dark hex, so they stayed dark on every theme. They use theme tokens now.
  • Tooltip text was invisible on themes with a dark primary-foreground, like Rosé Pine. Tooltips took their text color from the primary button ink while nearly every caller swapped the background for a surface. They're a bordered popover surface by default now.
  • lifecycle.onThemeChange never fired. Nothing emitted theme:change.
  • Tick-data playback painted the base layer outside the render loop on every tick, skipping overlays, so plugin overlays flickered. It goes through the render loop now.
  • The console manifest was missing render-engine:destroyed and the extension-params events, so npm run dist failed its manifest check.
  • The order panel's tab indicator ignored its easing. An arbitrary ease-[..] is ambiguous with tailwindcss-animate and generates nothing.
  • Hot reloading an extension left its old overlays painting unless the teardown removed them. Overlays still registered at teardown get removed for you now.
  • ctx.schedule timers from an extension script kept running across hot reloads. Only uninstall cancelled them. Hot reload does now too.
  • Editor typings had overlay hooks taking a RenderContext. They get (ctx, view, transformer).
  • Sub-panes painted the default background over a custom backgroundColor.
  • A draw hook that threw stopped the render loop causing the chart to freeze. It's logged once and skipped now.
  • Extension overlays in multi-chart layouts. The chart kept one render engine, whichever cell mounted last, so going from one chart to two left the overlay on chart 1 while markDirty went to chart 2 - an animated background froze, and reinstalling moved it to chart 2 for good. Overlays now go on every cell, cells added later and remounted ones included, and markDirty repaints all of them.
  • ctx.schedule.frames watched the first chart container it saw, forever. A layout switch that remounted it left frames paused for good, since a detached element never counts as on screen. It follows the current cells now, and runs while any is on screen.
  • The plugin manager flashed its empty state for a frame on open, then jumped to full height mid-animation.
  • ctx.transformer was never updated by any chart, so pointer maths with it - like the Price Alerts example's click to place - landed on the wrong price. It's the focused chart's now.
  • Indicators removed from a saved chart came back on every reload if their plugin was set to active in the plugin manager. A restored chart's panes win now, and removing a plugin's last instance turns activate off so new charts don't get it either. Autostart stays on.

0.18.0 - 2026-10-16

Added

  • Momentum panning on touch. Flinging the chart during a pan keeps it gliding on release. With a toggle in settings.

Changed

  • Touch now doesn't move drawings when trying to pan. Select first, then drag to move them
  • Touch: trade lines need a tap to arm first, in order to move or drag, so pans that start on an order no longer move it.
  • Touch: panning keeps the selected drawing selected, tap elsewhere to deselect it
  • TradeLine.afterMove isn't called when a drag ends at the price it started from.
  • Bigger tap targets on touch in the drawing settings bar and color picker.

Fixed

  • Slow pans counted as clicks, selecting drawings, trade lines and trade dots on release.
  • Clicking a tp/sl ghost pill without dragging could add a tp/sl at an old price, or right next to the entry on the slightest finger move.
  • Taps with a little finger wobble didn't register as taps.
  • Pinch zoom did nothing while playback was running.

0.17.0 - 2026-10-15

Changed

  • Improved touch to be more familiar. Panning has no crosshair, long press brings it up, and while it's up drags move it around instead of panning the chart.
  • Drawing on touch - arming a tool spawns the crosshair, drag to aim and tap to place anchor at the crosshair rather than under the finger.
  • Long press no longer opens the context menu, a + on the crosshair line does instead.
  • Bottom bar quick settings fold into a popover button, and the timezone label hides, when the width is too narrow and a plugin has registered items on it, so those items get some room.
  • Legend hides the timeframe and exchange when narrow instead of truncating them. The symbol truncates after that (if needed).
  • Double-clicking the time axis threw on ohlcv data. Now it does the same reset as in the context menu instead of the super old fixed 800s window.
  • Trade line pills' right padding scales with chart width (capped at 70px).

Fixed

  • Auto scale used the previous step's forming bar, so a big move could push the current price off screen until the next step.
  • Indicator buttons in the legend couldn't be reached on touch, and hidden ones could still be tapped. Tap an indicator to show them now, they're bigger on touch screens too.
  • Zoom/pan menu at the bottom of the chart is gone on touch screens. It popped up on any tap near it, and its invisible buttons could be hit while panning.
  • Context menu price was off with indicator panes open. Used full chart height instead of main pane height, and opening it on an indicator pane now drops the price and order items.
  • Remove the auto price axis fitting when dragging the time axis.
  • Dragging or double-clicking the time axis during playback fought the follow-scroll.
  • Horizontal wheel scroll during playback drifted the view and dropped the scroll easing.
  • Market entries didn't show their line or fill arrow until playback moved - a 0 pnl hid the line, and the engine filled off the next candle's first sub-bar when stopped on a bar boundary.

0.16.2 - 2026-10-14

Fix

  • Dragging the time axis won't push the last bar off screen anymore, switches to scaling from the left edge instead.

0.16.1 - 2026-10-14

Changed

  • Settings dialogs go fullscreen when the screen is too narrow for them
  • Dragging the time axis keeps the time you pressed under the cursor, instead of scaling from however far you've moved. Also scales by bar in gap-free mode now, like scrolling does

Fixed

  • Drawing settings tabs overflowing the dialog on narrow screens, they scroll now
  • Drawing settings bar couldn't be dragged on touch.

0.16.0 - 2026-10-13

Added

  • Touch support. Works as you’d expect: one finger pans, scales, and drags; two fingers zoom; double tap acts as a double click; and long press opens the context menu).

Fixed

  • Chart drawn too big, with the price axis eating half the inputs, after the dpr changed.
  • Gradient on the left on the top toolbar wasnt fully fixed to the left side

Known issues

  • Drawing handles are too small for fingers

0.15.1 - 2026-10-10

Added

  • Added a minimum width to the chart to prevent bad ui

Changed

  • The default strategy plugin trade arrows on the chart look nicer
  • A nicer tooltip when hovering locked timeframes
  • Bottom bar uses the same scroll strip as the toolbar

Fixed

  • Dropdowns overflowing the chart when its small. they flip up and stay inside the window now
  • Top toolbar not overflowing properly when items dont fit, scrolls like the others now
  • Time labels in the time axis overlapping when the chart width was small
  • Legends overflowing under the price scale, they truncate now
  • Layout resizer highlight covering the whole grid height instead of just the divider
  • Double borders on the outer edges of multi-chart layouts

0.15.0 - 2026-10-07

Added

  • A console. It's sick and youll love it. chart.console creates it on first use. every bus command and setting is already in it. Aliases, binds, cfgs and history is saved through the chart's storage layer.
  • console.register / registerCvar to add your own commands and cvars. You also get scope, capture, suggest, highlight and complete to build a ui around it.
  • Plugins also get ctx.console.register/registerCvar to make their own commands.
  • Scripted plugins can declare commands: {} or call p.command(name, def). Commands run in the worker with the plugins params and state. each param also shows up as a cvar, slug.param
  • chart.getData() like the plugins ctx.getData(), returns the same snapshot.
  • chart.renderEngine, with container, plotSize, paintStats
  • executionEngine.getDepth(levels) - the resting book from the built in matching engine (best lvls first)
  • eventBus.tap(fn) to see every event before its handlers & interceptors run, and eventBus.emitCounts

Changed

  • PluginContext has a required console, and L3MatchingEngine has a required getDepth. this only matters if you implement either one yourself.

0.14.1 - 2026-10-04

Added

  • Animated dropdowns for the ones that didnt already. Makes it look nicer. thats all, simple patch

0.14.0 - 2026-09-29

Whoops. been a while... anyways, lets get on with the changes:

Added

  • New drawings start with the style of the last one you edited of that tool. Plugin tools too, for the keys they declare in defaultData
  • Templates menu on the drawing settings bar. Checks the template the drawing currently matches and saving under an existing name overwrites it.

Fixed

  • Drawing previews were hardcoded to use gray/blue lines before, now they render correctly, showing what the drawing will look like when placed. Plugin previews gets the tool's data too. Used to be undefined until the plugin seti ts own
  • Templates didnt save the right keys but intead used hardcoded ones, so rect borders, fib opts, position colors etc etc and all plugin settings were dropped
  • Reset style left behind keys the defaults don't set, and on plugin drawings wiped any state the plugin left in data.
  • setDraft(null) from a plugin tool left an empty draft instead of clearing it.

0.13.1 - 2026-08-23

Fixed

  • Single-stepping playback moved the chart like one pixel forward instead of a bar.
  • Default playback settings were not optimized for the average user. Used to be default realtime mode with a 5s step. It's now step mode with a 1m step, with step snapping enabled.

0.13.0 - 2026-08-22

Added

  • Auditing a plugin's performance. Opt-in - normal runs aren't touched, but a run under audit wraps and timing every line and function call. plugin:audit-run ({ id }) starts it; plugin:audit-result returns { id, result } (result: AuditResult) unless it failed, in which case plugin:audit-error reports { id, error }. Took one test strategy from ~20k to 70k+ bars/s once the slow parts were visible. Auditing only works for indicator, strategy, and chart type plugins.

0.12.26 - 2026-08-21

Added

  • Intrabar fill resolution in the strategy engine. beginBar(bar, index, sub?) takes an optional third argument: the same period at a finer resolution. Pending orders and bracket exits resolve against each sub-bar in turn instead of the aggregate, so a bar holding both a stop and a target can say which came first. The script still gets one update() per chart bar - it was written for that tf, and calling it 60x more often would change what the strategy is, not just how precisely it fills.

  • reconcileIntrabar(bar, sub, tolerance) guards it: a sub-bar whose open/high/low/close/timestamp ordering disagrees with the aggregate is rejected and that bar falls back to the aggregate, rather than resolving a stop against a range that's missing the second the price actually traded through.

  • StrategyStats gains intrabarBars, intrabarFallbacks and ambiguousExits; StrategyTrade gains ambiguousExit. A trade log that hides which exits were guessed is how a backtest ends up better than the account.

  • A run range for strategies. plugin:strategy-range ({ id, range }) bounds a strategy to a span of time and re-runs it; range: null clears it. Runs, sweeps and walk-forward all use the same range, which is a sibling of the parameters, never one of them - a server runner keys its chunk cache on hash(script + params) + chunkIndex, so folding range into params would turn every range change into a total cache miss.

  • clipRange, hasRange, emptyRangeReason, StrategyRange, ClippedRange - a host can resolve a range against bars it already holds and say "that range holds no data" without a worker round trip.

  • plugin:strategy-updated now reports the range a run actually covered, and a run whose range holds no bars is refused with a reason rather than an empty result - so a strategy that took no trades doesn't look the same as one given no bars.

  • A strategy can now run over a range the chart has never loaded. plugin:strategy-range's fetch flag walks the span a chunk at a time, feeding each through the engine and dropping it - progress on plugin:strategy-progress, result on plugin:strategy-updated. Nothing ever holds the whole span, and the walk follows the adapter's coveredTo rather than assuming it got what it asked for, so chunks can't be skipped silently. Opt-in, since clipping to loaded bars is free and covers almost every range anyone picks, while this one goes to the network.

  • PluginContext.fetchRange (behind data:read) and DataEngine.fetchRangeBars do that fetch without joining it to the chart's loaded range - it won't scroll the view or make the next pan believe it already has history it doesn't.

  • A date ParamDef type, rendered as a native date/datetime-local control. Value is an ISO 8601 string rather than a nanosecond number, since params persist as JSON with the chart and a bigint doesn't survive that.

  • planChunks and streamRangeChunks in strategy-stream.ts, walking a span in order with several requests on the wire at once. Boundaries are decided up front since a request has to be issued before its predecessor answers; bars still reach the engine strictly in order, and a failure is raised in plan order rather than when it happened, so a later chunk failing can't skip the bars an earlier, still-outstanding one owns. Concurrency depth is 4 - a few MB for roughly a 4x cut in wall clock, where 40 would be most of a tab for little more. No DOM, no chart imports, same as the rest of the strategy core.

Changed

  • plugin:strategy-progress now describes the whole run, not just the fetch. phase gains running (every chunk's at the worker, engine finishing up and computing stats) and analysing (host turning the result into whatever it draws); done now fires when the numbers exist, not when the last chunk was sent. The old contract ended at "fetched", which on a five year run is seconds before anything on screen changes - a panel clearing its progress on that event looked finished while the tab was still busy. analysing is emitted by the host, not depth, since depth has no idea what a host does with a result. A refused run and an abandoned stream are terminal too, and now say so.

  • A strategy run's memory no longer grows with its range. Drawdown, ulcer index, Sharpe, Sortino, CAGR are now accumulated per bar as the run proceeds, so the stored equity curve is capped at 8,192 points and thinned as the run outgrows it. Measured over a two million bar run: 221 MB before, 1.1 MB after, flat rather than linear in range. The numbers themselves are unchanged - Sharpe/Sortino are still taken from the true per-bar sequence, not the thinned curve, and use Welford rather than sums of squares since the naive form loses precision over a couple million bars. StrategyResult.equity still covers the whole run but is no longer one point per bar past the cap - read stats.totalBars for the count.

  • Excursion is tracked per sub-bar when intrabar data is in use: a position opened partway through a bar no longer inherits the range it wasn't open for (a stop filling at 105 on a bar that dipped to 90 beforehand used to report a 15 point adverse excursion instead of the entry second's own range). MAE/MFE timestamps land on the second rather than the whole bar.

0.12.25 - 2026-08-20

(this should really have bumped the minor version... didnt think about that, whoops)

Added

  • Strategy plugins. PluginType.strategy is a fifth plugin type, sibling to indicator / drawing / chart type / extension. A strategy is an indicator that returns trades instead of a series: it registers, draws and takes parameters exactly like one, and lives in the same list.

    const s = plugin({
        name: 'MA Cross',
        type: PluginType.strategy,
        lookback: 120,                                        // trailing bars each update() sees
        strategy: { initialCapital: 50000, commission: 2.5 }, // defaults, editable in the settings dialog
        params: { fast: { label: 'Fast', type: 'stepperInt', default: 10 } },
    });
    
    s.init = ({ params }) => ({ /* ... */ });
    s.update = ({ bar, index, history, state, params, broker }) => { /* ... */ };
    s.draw = (state) => [ /* ... */ ]; // optional - entry/exit markers by default
    js

    Fill model:

    • An order placed on bar i fills on bar i+1. Acting on a close you have already read is lookahead, and there is no option to switch it off.
    • A bar containing both the stop and the target takes the stop. An aggregate bar cannot say which came first, and guessing in the trader's favour is how a backtest ends up better than the account.
    • pyramiding defaults to 1, so a condition that stays true for twenty bars opens one position rather than twenty.
    • R-multiples are undefined, not 0, on a trade that carried no stop, and so is efficiency on a trade that never moved in favour.
    • totalSlippage is reported rather than deducted - it is already inside the fill prices.

    Contract details resolve DEFAULT_STRATEGY_CONFIG → SymbolInfo.contract → the script's strategy block → params. The instrument sits below the author on purpose: a script that states its own tick value means it.

  • StrategyEngine and DEFAULT_STRATEGY_CONFIG, so a host can score a run outside the chart - a test harness, a batch job, or a server runner. The engine imports nothing at all, and build/probe-script-runtime.mjs fails the build if that ever stops being true.

  • StrategyStats carries the run summary: the usual P/L and drawdown figures plus Sortino, Calmar, recovery factor, ulcer index, SQN, Kelly and CAGR; streaks and hold times; R-multiples and average exit efficiency over the trades that had a stop; average MAE and MFE; and a long/short split. Every risk-adjusted figure falls back to 0 rather than NaN or Infinity.

  • The sweep vocabulary: expandGrid, axisValues, checkSweepBudget, splitIndex, MAX_SWEEP_COMBOS (20,000), MAX_SWEEP_BAR_ITERATIONS (200,000,000) and the SweepAxis, SweepSpec, SweepResult and SweepBudget types - so a sweep UI can refuse an impossible grid before posting it, with the same arithmetic the worker uses. Budget is combinations × bars; neither alone predicts a hang.

  • Walk-forward: planWalkForward, walkForwardEfficiency, parameterStability and pickBest, with WalkForwardSpec, WalkForwardWindow, WalkForwardWindowResult and ParameterStability. Efficiency is per bar so a long anchored window can't dominate the average, out-of-sample segments get no in-sample warmup, and a non-finite objective is skipped rather than chosen - Infinity profit factor is noise dressed as perfection.

  • ExitReason in the script DSL - signal, stop, target, reverse, end-of-data - so a script can compare against a name instead of a string literal.

  • @christtrade/depth/script-runtime re-exports the engine, the sweep helpers and the walk-forward helpers, and adds defaultStrategyDraw, the markers a strategy gets when it declares no draw. The entry point stays DOM-free: the point is that the browser worker and any other host execute this exact module, rather than two implementations that agree today.

  • chart:goto-range ({ fromNs, toNs?, padding? }) and gotoRange() on the useChartData result, which frames a span of time without touching the playhead. Not recenterViewOnHorizon - that one follows the playhead and bails if the target's already on screen, so replay doesn't get yanked around; this one's a command, someone clicked a trade, so it always moves. A span shorter than twenty bars recentres at the current zoom instead of fitting to a single wick.

  • plugin:apply-params ({ id, params }), which writes values into any scripted indicator's settings, not only a strategy's. Keys the plugin does not declare are dropped rather than written - a sweep grid can carry keys belonging to a strategy that is no longer the selected one, and silently storing those corrupts the settings.

  • The plugin:strategy-* events: -updated (stats, trades, equity, any open position, the parameters that produced them, and the parameter declarations so a sweep UI can offer a range without the author declaring one), and the -sweep and -walkforward families, each with a command, -cancel, -progress, -done, -cancelled and -rejected. plugin:strategy-rejected reports a run refused for exceeding the in-browser cap of 2,000,000 bars.

  • A Strategies category in the plugin manager dialog.

Changed

  • The PluginType union gains 'strategy'. Additive for anything that merely reads a plugin type, but an exhaustive switch over it now wants a fifth case.
  • A strategy's settings dialog is generated: initial capital, commission, slippage, pyramiding and reverse-on-opposite-signal appear without the script declaring anything, and a params entry of the same name still wins. Tick size, contract size and quantity step are deliberately left out - they describe the instrument, and putting them in a dialog invites someone to "fix" a multiplier until the numbers look better.

Fixed

  • Not user-visible: the server-safety probe matched DOM markers as substrings, and a bare window. was ambiguous. A walk-forward result carries a window field describing a span of bars, so r.window.isTo failed a DOM check with no DOM within reach. The markers now match only what the real global is followed by.

0.12.24 - 2026-08-19

Changed

  • indicator-stdlib.ts imported LiveTransformer instead of just its type, causing the chart engine to follow with.

Added

  • script-runtime.ts, first step of support for strategy plugin types. If the strategy is to be ran on the server, there is no DOM. This is the entry point for running scripts without a DOM.

0.12.23 - 2026-08-18

Changed

  • Breaking: the SymbolIcon type is now SymbolIconSpec. The name SymbolIcon belongs to the React component that renders one, which is now exported too. A type and a value cannot share a name across a barrel re-export, and in a React library the component has the better claim to the plain name.

    import { SymbolIcon, type SymbolIconSpec } from '@christtrade/depth';
    ts

    Only affects code written against 0.12.22, which exported the type for a few hours.

Added

  • toTransferableSymbolInfo, for stripping icon off a SymbolInfo before it crosses a postMessage boundary. An icon may carry a render callback, and functions do not survive structured clone.
  • SymbolIcon, the component that renders a SymbolIconSpec.

0.12.22 - 2026-08-18

Added

  • The trading domain is exported: Order, Fill, Position, PositionClose, PositionSide, CloseReason, TimeInForce, the bracket and commission types, and getTickValue, calcUnrealizedPnl, calcUnrealizedPnlPct, formatPnl, formatPnlPct. IExecutionAdapter already required these in its signatures, so implementing the documented extension point was impossible without them.
  • The rest of the extension-point vocabulary, ~68 names that appeared in exported signatures but could not be named: BarResponse, FetchRequest, DataAdapterError, TimeRange, SupplementalBarSet, BarPreviewResponse, PreProcessedPayload and makeTimeRange / nsToIso / isoToNs for adapter authors; the IChartPlugin vocabulary (ToolbarItem, PaneOptions, SettingSchema, PluginStorage, ThemeDef and the rest) for plugin authors; the ledger types on AccountManager; and the payload types needed to write a ChartEvents handler.

Fixed

  • The order panel no longer requests /icon-star.ico from the host app. The icon is inlined as a data URI, the same way the attribution banner and Inter already were. It 404'd in every application except ChristTrade's.

0.12.21 - 2026-08-18

First public release. Apache-2.0.

Added

  • Everything: 12 chart types, ~50 drawing tools, 21 built-in indicators, multi-pane and multi-chart layouts, playback, the order ticket and local L3 matching engine, session handling, serialization, the plugin runtime (scripted and WASM) and bring-your-own-key data sources.

Fixed

Not user-visible, but this is what the split out of the monorepo turned up:

  • Three Radix packages used by live components were never declared as dependencies. They resolved only through the monorepo's hoisted node_modules; a standalone install could not build.
  • There was no devDependencies block at all - esbuild, jsdom, tailwindcss, tailwindcss-animate and typescript were all inherited from the parent workspace.
  • tsconfig.json extended the host application's Next.js config, which does not exist in this repo.
  • Inter is embedded in depth.css, so its SIL Open Font License now ships alongside it.
  • 30 unused UI components were removed, taking depth.css from 147 KB to 124 KB.

Was this page helpful?