Upgrading to 2.6.0
2.6.0 is a minor release. Every name 2.5.10 and 2.5.1 exported is still exported, with a type that accepts what it accepted, and the chart states, drawings, alert lists, widget layouts and workspace documents those releases saved load unchanged; both are checked on every build. Most hosts need no code change. The hosts most likely to have something to do are one whose type checker reads the event payloads and casts them, one whose widget loads bars from a feed and offers point and figure or Kagi, one whose tests drive the widget’s drawing actions, symbol field or chart data dialog, and one that stores fractional study lengths or calls the statistics helpers with unusual options.
Each point says what changes and what to do. The first part is for a host on 2.5.10. The second part is for a host on 2.5.1, the version OpenAlgo pins today, which meets every point of the first part and every release in between.
From 2.5.10
1. What compiles differently
What changes:
chart.on,onceandoffnow type the listener’s payload fromChartEventMap. A cast of a payload to a type it does not overlap fails with TS2352, for examplep as Record<string, unknown>on theclickpayload, an interface with no index signature.- A name outside
ChartEventMap, or a list of names typedstring[], still compiles: it resolves to the string overload, which is deprecated, so an editor strikes it through and the payload staysunknown. - The draw tier adds its
draw:*anddrawing:*names toChartEventMapby declaration merging, so their payloads are typed once any module of the program importsopenalgo-charts/draw. Chart.emitis deprecated. A call still compiles and still works.IndicatorApigainsbarSource()andsetBarSource(). It is a handle the library makes, but an object written to that interface by hand, a test double say, needs both.- Under
exactOptionalPropertyTypes, some types the library hands back now say| undefinedon optional members it already set toundefinedat run time:AlertAvailability.reason(and soAlertDrawingInfo.reason),Order.triggerPriceandrole,PlaceResult.stateandintent,MarketProfileSessionResult.label,IndicatorDescriptor.category,ChartStateviewport,barSpacing,panesandalerts,WidgetState.panels,WidgetRestoreReport.reason,DateNavigationResultfromandto, andWorkspacePane.historyPeriod. - The types a host writes gain the same
| undefinedwherever the library passesundefineditself:WidgetOptionsfeed,symbol,exchange,interval,variantandchartType;WidgetContextobjects,alerts,history,drawingTemplates,translateandsymbolSearch;WidgetTranslationOptions.translate;OverlayOptionsanchor,initialFocusandedge;TipSpeclabel,chordandsub;MenuRowicon,subandkey;MenuItemchordandnote;FormControlgroup,tooltip,min,max,step,options,pairandcustom;ColorPickerOptionsliveandopenOverlay;KeyBindingOptionswhen,hiddenandlayered, andKeyBinding.when;ChartHistoryCommand.label;AsyncStorageLike.journal; thevariantanddatapayloads ofWidgetBusEvents;RangeWindowOptions.bars;BottombarContext.localeandBottombarOptionsrangesandnow;TopbarOptionsindicators,search,layoutsandcaptureRows;MobileOptionsmode,tools,searchandbottombar;ContextMenuHooks.tradingCapabilities;EventDetailsPopupOptions.styleNonce;StatuslineOptionslocaleandnow;AccountSummaryOptions.locale;DataWindowOptions.locale;QuickEntryOptions.search;QuoteBoardOptionsfeed,staleAfterMsandpollMs;NewsReaderOptionspageSize,staleAfterMsandmaxItems; thehistoryPeriodaChartGridOptions.feedfunction receives;PriceAlertSource.upperPrice,IndicatorAlertSource.upperValueandAlertInputmessageandexpiresAt;BarsRequest.signalandSymbolSearchRequest.signal;TradingCapabilityRequestexchange,orderId,typeandmode;PlaceRequestexchange,price,triggerPrice,productandclientToken; every optional field ofTradingFeatureRequest;AccountFeed.features,OrderFeed.featuresandOrderFeed.capabilities; thesignalofWorkspaceOperationOptions,WatchlistOperationOptionsandDrawingTemplateOperationOptions; the seven fields ofPointFigureOptions;RequestedAlignmentOptions.gaps;AddSeriesOptionsstyle,priceScaleIdandpriceFormat;PaneRenderContextprimaryDataId,timeFormatter,sessionClockandbarCountdown;SvgContextOptions.background;SessionClockOptions.showOffset;IndicatorFillOptions.gradientandFillPointcolorandgradient;ChartObjectDefinitiongroupIdanddataStatus;OpenAlgoWsConfigsocketFactory,reconnect,authandheartbeat;TickBarOptions.timezone; andReplayOptions.onFrame. - The optional handlers of
TopbarOptions,MobileOptions,PanelDockOptionsandContextMenuHookskeep their 2.5.10 method declarations, so a handler with a narrower parameter type still compiles, andopenMenustill takes a wholeWidgetContext. LayoutSetter, thesetterof alayout:changepayload, gains'setNavigationOptions'. An exhaustiveswitchover it without a default branch fails to compile until it handles the new member.ReplayChartHostgains an optionalon('destroy', callback); a host object written to it needs nothing, and aChartalready has it.- The trade tier’s
OrderSideandOrderTypeare now the base’s types under the same names. - New type exports:
AddIndicatorOptionsandChartApplyOptions, the option types ofaddIndicatorandapplyOptions. - A JavaScript host compiles nothing, so none of this reaches it.
What to do:
-
Read the field you need, or cast through
unknownwhere the old cast was deliberate:// before: compiled in 2.5.10, fails with TS2352 in 2.6.0 chart.on('click', (p) => log((p as Record<string, unknown>).time)); // after: the payload is a ChartClickEvent chart.on('click', (p) => log(p.time)); -
Write a list of names
as const, so each call takes the typed overload:const saveOn = ['alert:created', 'alert:updated', 'alert:removed'] as const; for (const name of saveOn) chart.on(name, save); -
Declare an event of your own once, instead of passing an unknown name:
declare module 'openalgo-charts' { interface ChartEventMap { 'myapp:signal': { price: number } } } chart.on('myapp:signal', ({ price }) => mark(price)); -
Add
barSource()andsetBarSource()to a hand-writtenIndicatorApi, andpolicy()if it was missing (point 8). -
Under
exactOptionalPropertyTypes, a type of your own that takes one of the handed-back types above whole gains the same| undefined. A host compiling that way withoutskipLibCheckno longer meets the one error the 2.5.10 declarations raised (OpenAlgoTradeFeedagainstOrderFeed).
2. Chart events at run time
What changes:
- A listener that throws on the chart’s bus is reported through the platform’s
reportError: in a browser, the console and the window’serrorevent. 2.5.10 dropped the error. The other listeners still run and the engine carries on. Where there is noreportError, as in a test runner without a DOM, nothing changes. - A listener that throws on
chart.trading.onorchart.shortcuts.onno longer stops the other listeners, the chart-bus copy of atrading:*event, or the chart’s pointer handling. objects:changealways carries{}. The pan and zoom switches ofsetNavigationOptionssentundefined; every other site already sent{}.- The widget’s own buses keep their policy: they run every listener, then rethrow the first error.
What to do:
- A browser test harness that fails on console errors may now see a listener bug that was silent before. Fix the listener.
- A listener that told the navigation switches apart by an
undefinedpayload reads the navigation options instead.
3. Transforms in the chart and the bars a study computes on
What changes:
- With the transform tier imported, a widget that loads its own bars from a
feedand is set to point and figure or Kagi now has the chart form the columns or the Kagi line from those bars. 2.5.10 drew the raw bars through those renderers. A widget whose host feedswidget.seriesitself keeps both as renderers, as before. A saved 2.5.10 layout on either type opens transformed. - With the transform tier imported, the widget’s chart type menu lists the six transforms under
a Transforms heading, and
chartTypeChoices()returns the renderers, then the transforms (heikin-ashi,renko,range-bars,line-break,point-figure,kagi), where 2.5.10 listed point and figure and Kagi among the renderers.widget.chartType()and thelayoutevent’schartTypecarry those ids. - The chart settings Price tab, for a transformed primary series, leads with the transform’s
options (
transform.<option>keys), and offers X and O colours for point and figure and thick and thin colours for Kagi, where it offered a line colour and thickness neither renderer reads. - A built-in study with a timeframe set, on a chart that transforms its bars, is refused (point 4); on the underlying bars it folds.
runTransformoverKagiTransform, andflush()for a host that pushes bars itself, date the vertex still forming at the newest bar, where it was time 0.- A chart of transform elements on minute bars, several a bar a second apart, labels its time
axis by the minute instead of with seconds, whether the chart forms the elements or the host
feeds them with the one-second bumps
runTransformgives. Plain charts label as before.
What to do:
- If your feed already returns transformed point and figure or Kagi elements, feed them through
widget.seriesrather than the widget’sfeed, or they are transformed twice. - A host that switches on chart type ids handles the four new ones, or reads
chartTypeChoices()andchartTypeLabel(). - To move a host that transforms bars itself to the chart’s own transform, keep feeding the raw
bars and call
chart.setSeriesTransform(series, { type: 'renko' }). Page older history in withprependData: asetDatasizes an automatic box again from the bars it is given.
Alerts on a step that adds several elements, what changes:
- A study alert now judges each bar a calculation appends after an unchanged history, in order,
as separate appends would: a source bar that completes several Renko bricks (the other
transforms add at most one element per source bar), and several bars a host writes before
the chart recomputes. An alert with no frequency reseeded silently on such a step and never
fired;
everyUpdate,oncePerBarandoncealerts judged only the newest bar. So aneveryUpdatealert over three coalesced writes that delivered once now delivers once per new bar; ticks within one bar still collapse. - An alert judged at a bar before the newest receives the bars and values through that bar.
- A study on the underlying bars judges each underlying bar once, at the first element it
completed, so a bar that completes several Renko bricks delivers its alerts once;
oncePerBarcounts underlying bars andonBarClosewaits for the underlying bar to close. - The hooks of a study on the underlying bars (plot colours, markers, background, bar colours,
levels, an alert’s
whenandmessage) receive the elements and the values sampled onto them, indexed by element. - A trader alert judges each element an update appends in the same way, each dated at its own
element: an
onBarClosecrossing on an earlier element now fires, anonTouchcrossing carries thetimeandindexof the element that crossed, and anonBarClosealert on an in-chart Kagi chart confirms a turning point once the line reverses past it. So aneveryTimealert can deliver severalalert:triggeredevents in one update, one per matching element, each dated at its own element; before, it delivered at most one, dated at the newest.
What to do:
- A host that backfills bars through
series.updatein one frame now has each judged. To keep a backfill silent, write it withsetDataorupdate(bar, { source: 'history' }). - A listener on
alert:triggeredthat expected at most one event per update, or the newest bar’s time on every event, reads each event’s owntimeandindex. - A custom descriptor that keeps per-bar state from
calcand reads it by index in a hook reads the element index on the underlying bars; on a transform that is not one element per bar, that is not the source bar’s index. - A host running OpenScript studies on the underlying bars of such a transform uses OpenScript
0.8.1 (
openalgo-scripton npm,openscripton PyPI) with 2.6.0: 0.8.0 read their alert messages at the wrong bar.
4. The timeframe input on 29 built-ins
What changes:
sma,ema,wma,vwma,hma,dema,tema,alma,smma,t3,lsma,kama,mcginley-dynamic,zlema,vidya,bollinger,keltner-channel,donchian,envelope,supertrend,parabolic-sar,atr,rsi,macd,stochastic,stochastic-rsi,williams-percent-r,cciandadxeach gain one input after their ungrouped inputs:{ key: 'timeframe', type: 'interval', label: 'Timeframe', default: '' }. Empty, the default, leaves their output and their live tail exactly as before.indicatorDefaults()of those studies includestimeframe: '', and their saved settings carry it (see “What 2.6.0 writes”).- A settings form that renders a descriptor’s inputs shows a Timeframe row for them. In the
widget it is a select of Chart and the host’s
intervals; a form of your own renders theintervalinput type as it already does. - A timeframe set shows each bucket’s value once the bucket has closed, and the legend names it
(
EMA 9 close 15m). An unknown code, a tick or volume interval, a chart whose own bars close on trade flow, another study’s output as the source, and a transformed chart’s own bars are refused withIndicatorInputError:addIndicatorthrows, andsetSettingsputs the study in itserrordata status with the message until a good setting clears it. restoreState, and so a widget starting from a saved layout, brings back a study its inputs refuse in its error status, beside the studies around it. In 2.5.10 such a study stopped the restore part way, and the widget failed to start.
What to do:
- A test that compares a study’s settings,
indicatorDefaults()orgetState()withtoEqualaddstimeframe: ''for those studies, or compares the fields it cares about. - A form of your own that lists the chart’s intervals can offer them to the Timeframe input.
- Register your interval codes before you restore a layout that names them; a study restored with a code the chart does not know recovers on the next recompute after the code is registered.
- Read
dataStatus()aftersetSettingsif you need the refusal’s reason; the widget and the reference host show it.
5. Study settings read one way
What changes:
- Fractional lengths round. Every built-in reads a fractional window length as the nearest whole number (14.5 as 15) and a length below 1 as 1. These studies read it raw, and most of them drew an empty pane for it: SMA, EMA, WMA, Bollinger Bands, Supertrend, RSI, MACD, Stochastic, ADX, CCI, MFI, ATR, Williams VIX Fix, Bollinger %B, Bollinger BandWidth, BBTrend, Choppiness Index, Historical Volatility, Average Daily Range, Chaikin Volatility, Standard Deviation, Chaikin Money Flow, Chaikin Oscillator, Ease of Movement and Elder Force Index. These floored it: Aroon, Aroon Oscillator, Chande Momentum, Coppock Curve, DPO, Fisher Transform, Connors RSI, Standard Error, Momentum, ROC, PPO, TRIX, TSI, the SMI Ergodic Indicator and Oscillator, SMI, NVI, PVI, PVO, Mass Index, Ulcer Index, Vortex, Volatility Stop, Trend Strength Index, Williams Fractals, RSI Divergence and WaveTrend. A saved chart with a fractional length now draws a line where it drew nothing, or 15 where it drew 14. Whole lengths are unchanged in every study, and so are levels and scales that take a fraction (an RSI level, a divisor, periods per year). The widget’s number field hands a fraction through, so a user can reach this.
- The Choppiness Index rounds a fractional offset to whole bars.
- A colour, a choice or the VWAP anchor saved as an empty string now reads as its declared default in AlphaTrend, Awesome Oscillator, BBTrend, Chop Zone, MACD, PPO, PVO, VWAP and Williams VIX Fix.
- Calling the
calcof MA Cross, Williams Alligator, Median, TWAP or VWAP directly, without those settings, uses the declared defaults (a long length of 26; 21, 13 and 8; the hl2, ohlc4 and hlc3 sources). A chart merges the defaults, so it draws them as before. rollingMedianand the rest of the statistics helpers now throwTypeErrorfor options that are not an object (an array, a number, a string,null) and for{ missing: null }, where they read them as the defaults. The statistics and the calc helpers now throw the same messages, which differ from 2.5.10’s in both families:Missing-value window period must be a positive safe integer,Missing-value options must be an objectandMissing-value policy must be propagate or skip.percentileNearestRank,valueWhenandalmagive NaN for arguments out of their range, where they wroteundefinedinto the result or threw aRangeError.priceBucketsreturns no buckets for a step that is not a positive finite number, socomputeVolumeProfileandcomputeTporeturn an empty profile for a negative tick size, where they did not return.
What to do:
- If a stored fractional length matters, round it yourself before 2.6.0 reads it, or accept the rounded study.
- Test the error class, not the message, and pass the statistics helpers an options object or nothing.
6. Symbol search in the widget
What changes:
DataFeedgains an optionalsearchSymbols.OpenAlgoDataFeedandOpenAlgoLiveDataFeedimplement it against OpenAlgo’s/api/v1/search. A widget given such a feed and nosymbolSearchnow searches through it in the top bar, the phone layout, typed entry, the watchlist and study symbol inputs, and Enter takes the first result, the exact symbol on the chart’s exchange first, where it committed the typed text.SymbolSearchcallbacks receive an optional second argument,{ signal }, aborted when a newer query or a closed picker makes the answer stale.- A lookup that fails says “Search unavailable” in the results, which used to close silently.
- Enter in the top bar, the phone header and the watchlist’s add box waits while a search runs, then takes its first result, or the typed text once the search finds nothing or fails.
- Pressing a result keeps the focus in the field. In 2.5.10 a mouse pick did nothing unless the typed text matched the chart’s symbol.
What to do:
- A feed object of your own that has a
searchSymbolsmember with another meaning renames it, or the widget calls it. - A callback whose second parameter meant something else reads it differently; a callback that ignores it needs nothing.
- A test that types and presses Enter at once, while a lookup is configured, waits for the result it expects.
- The search sends the API key in the request body, as history does. A host that keeps the key off the page routes both through its own server.
7. Drawing actions, tools and hit tests
What changes:
- Lock, hide, the order moves, duplicate and delete follow one rule on the floating toolbar, the right-click menu, the properties dialog, the rail, the phone bar and the keys. Each press is one undo step (the rail and the phone bar took one per drawing). Lock and hide read the whole selection, so a partly locked selection shows unlocked and a press locks all of it. A selection whose every drawing is locked is neither deleted nor cut: the phone bar’s Delete is off and Delete, Backspace and Mod+X do nothing for it.
- The rail’s right-click menus open through the shared menu and walk with the arrow keys.
- The measure, price range, forecast, a line’s stats readout and the position tools’ zones take
the theme’s up and down colours; a position’s
profitColorandlossColorstill win. The forecast’s verdict chip uses the pattern tools’ pass and fail colours. - The advanced, pattern and analysis tools stroke whole device pixels (a 1.5 px width is 2 px at a ratio of 1), dot at 1 px, and set their labels in the default face and weight every other tool uses.
- Notes, balloons, comments, signposts and price notes hit-test the plate as painted, however long their text; the price label’s box is centred on its pill, and a callout’s bubble is as wide as its text. Where no canvas can be made (a test runner without one), the plates keep the old 120 px guess.
DrawingController.setOptions({ clipboardFallbackToMemory })now takes effect after construction.openalgo-charts/drawloads where Web Crypto is missing, and throws “openalgo-charts: drawing links require Web Crypto” when a link group first shares a drawing, where the import itself threw.- A pinned rectangle or ellipse with one anchor is kept and left unpainted, where it made the drawing layer throw on every frame.
What to do:
- A test that deletes a locked selection with a key or the phone bar, or that counts undo steps after a rail action, expects the new rule.
- Refresh screenshot baselines of the measure, position, forecast and analysis tools, and of every chart on the light theme or a host theme that shows them.
- A caller that paints a built-in tool directly with a partial theme passes the theme’s
upColoranddownColor.
8. The widget’s dialogs, menus and words
What changes:
- The chart data dialog asks for its From and To bounds as a date and a time on the chart’s
clock, with the zone named under the fields, where it asked for UTC seconds. A To written to
the minute takes in the whole minute. The
ChartDataCsvOptionsit builds are unchanged. The dialog’s three UTC-seconds message keys are deprecated. - The alert editor closes from the icon button every form dialog shows. The alerts list and the objects panel keep the word Close.
- The go-to panel refuses a date the calendar does not have (30 February), which used to roll into the next month.
- A study the chart refuses for its inputs shows the reason in the status overlay, naming the study once, with no Retry. Any other failure keeps “Could not load” and its Retry.
- The event popup the widget mounts speaks through the widget’s
translate, and a host’seventDetails.labelsstill win one by one. The watchlist translates its row names and itsn/aand...price cells. - The widget’s key labels read the platform as the engine does, so a browser that blanks
navigator.platformshows Cmd in the widget as in the chart. - The chart grid says “The chart layout could not be saved” on the active chart when a synchronous store refuses the desk. The chart’s Download PNG says “This runtime cannot save files” when the picture could not be handed over, where it said it saved one, and Copy image reports a canvas that refuses to be read. In the grid’s link and capture menus, ArrowUp from the menu itself goes to the last row.
- A JavaScript host that passes a hand-made objects inventory must give the whole
ChartObjectssurface, and a study handle must havepolicy(), as their types already said: the widget no longer probes for them.
What to do:
- A test that fills the chart data dialog types a date and a time on the chart’s clock.
- A test that looks for a Close text button in the alert editor looks for the icon button by its accessible name.
- A host that types a complete catalog as
Record<WidgetBuiltinMessage, string>adds{name}: {error},Event details,Events,Loading details...,No additional details.andUnable to load additional details.. The new schema keys areschema.ui.symbolSearchFailed,schema.ui.watchlist.entry,schema.ui.watchlist.noQuote,schema.ui.watchlist.quoteLoadingandschema.chartType.group.transforms, and the transforms’ names come throughschema.chartType.<id>; a translator that returnsundefinedfor them keeps the English text.
9. Chart, trade and profile changes a test may see
What changes:
addSeries,addPriceLine,addPrimitiveandaddEventMarkersgiven a pane index that is not a whole number of 0 or more throw aRangeError('Invalid pane index')and change nothing. 2.5.10 threw aTypeErrorfrom inside and could leave an empty pane behind.WorkingOrderLineandPositionMarkerdraw their price tags on the chart’s price axis wherever it is, and leave them out when the axis is hidden. On a right axis the tags stay where they were, except near the plot’s top and bottom edges, where they are kept inside it, as a price line’s are.- A market profile with
colorMode: 'period'and an emptyperiodColorspaints its blocks in the profile’scolor. FakeBrokernames an unknown order “FakeBroker: unknown order”.FakeBroker.rejectNextPlaceis documented as an answer lost on its way back; usefailNext('place', 'reject')for a broker’s refusal.- Private members changed in the declarations of
WorkspaceRepository,WatchlistRepository,DrawingTemplateRepository,DrawingController,DrawingLayerandOrderEngine.
What to do:
- Catch a
RangeErrorfor a bad pane index, or better, pass a checked one. - Refresh screenshot baselines of charts that show order or position tags near the plot’s edges.
- Code that read a private member (never supported) moves to the public API.
10. Classic scripts and require()
What changes:
- Every tier ships as a classic script beside the base’s,
openalgo-charts.<tier>.standalone.js, each on its key of theOpenAlgoChartsglobal. Load the base first and the draw tier before the widget; a file loaded too early throws an error naming the files it needs. The widget’s script carries its first-use panels. The base file, its global and theunpkgandjsdelivrfields are unchanged. - Each export entry gains a
defaultcondition naming the same ESM file. On Node.js 20.19 and 22.12 or later,require('openalgo-charts')and every subpath return the moduleimportreturns; an older version throwsERR_REQUIRE_ESMwhere it said the path was not exported. There is no CommonJS build. - The package carries the eight new script files, without source maps; every module file keeps its map, and so does the base’s classic script.
What to do:
- A page that loads no modules, and could use only the base, can now load any tier; keep one form per page, all classic scripts or all modules, since a module import next to the classic global would be a second engine with its own registries.
- A tool that runs in CommonJS mode and fell back on “not exported” now reaches the ESM file and
fails later with its own message on an older runtime: load the package with
import()there.
11. Worth knowing, nothing to do
- Transforms in the chart, the study bar source, the seven new built-ins, a timeframe set on a study, feed symbol search, rich event details and actions, and the typed event map are all opt-in outside the widget behaviour above.
- The event markers and the popup copy the plain data nested in an event’s
details, not only itsfields; aDateor other object you attach is still shared. - A one-chart layout captured from a widget with a data variant writes
variantbeforechartTypein its pane: JSON key order only. - The widget’s text layout and style fallbacks are unchanged; a test now holds them to what the draw tier paints.
WidgetOptions.nowis the widget’s wall clock and is not passed to its chart, whoseChartOptions.nowstays its own; the docs now say so.
12. The base engine and its edges
What changes:
subscribeClick,subscribeDragandsubscribeCrosshairMovetake several subscribers, and each call returns a function that removes its own. A second call used to replace the first; now both run. The trading layer’s order cancel and modify no longer drop out when a host subscribes, and a subscriber that throws is reported throughreportErrorand stops neither the others nor the pointer handling.setNavigationOptionsfireslayout:changewith the setter'setNavigationOptions', and the crosshair magnet’s shortcut fires it with'applyOptions'.setNavigationOptionsstill firesobjects:changefor the pan and zoom switches.Chart.setDataContexttakes a change of data variant as a change of source, sopublishDataContextemitsdata:contextonce for a variant-only change. The 2.5.6 note that such a change emits it twice, first with the interval cleared, no longer holds for a chart; it still holds for a target of the host’s own.setPriceAxisOptions,setPriceAxisAutoFitandsetPriceAxisLockRatioignore a scale id that names no scale (the last returns false), andpriceAxisStatereturns null for one; 2.5.10 applied them to the right axis.maximizePanerefuses a fractional index, andsetPaneWeightignores a weight that is not a finite number.- The crosshair price tag is written in the scale’s text size (
canvas.scales.fontSize,theme.axisFontSize); a chart that sets neither draws the same pixels. - A plot’s Opacity now fades
colorByandcolorPartsplots (body, wick and border), multiplying each colour’s own alpha, where it did nothing. - The chart settings schema offers Line style on area charts, and the HLC area Band swatch shows the colour the band is drawn in.
updatePositionPnl(id, pnlText?, pnlPercent?)is a new form; the number-first form still works, deprecated. Anulltext no longer shows as “null”.- A linked chart whose symbol loader announces a renamed symbol (a suffix, a case change) no longer becomes its group’s instrument.
- Appearance linking copies “Fit primary prices only” (
scales.priceOnly), soapplyChartSettingsemitsstyle:changefor it. ReplayShade.setOptionsrepaints at once. AReplayControllerwhose chart is destroyed stops its timer and leaves replay without writing to the chart.comparisonController(chart, options)appliesmodeandbaselineto the chart’s existing controller, where it ignored them.- A timer a caller sizes is held under 2^31 - 1 ms (the replay and fake-feed intervals also at least 1 ms); past that it fired at once. This covers the replay and fake-feed intervals, history request timeouts, the alert expiry timer and the socket’s auth, heartbeat and reconnect timers.
- A throwing
OpenAlgoWsFeedcallback no longer stops the other callbacks or the feed’s own state change; its error goes toreportError.ReplayGroupkeeps its policy: a throwingonChangeoronFrameends the group, as its docs say. - The time navigator reads a four-digit
#rgbatheme colour by its channels; a malformed two, five or seven digit hex falls back as every other primitive’s colours do.
What to do:
- A host that subscribed again to replace its callback calls the function the first call returned; a component that subscribes on mount unsubscribes on unmount.
- A host that saves on
layout:changenow saves navigation and magnet changes too; one that counteddata:contextevents for a variant change counts one. - Pass a scale id the chart has; read
priceAxisState’s null. - Refresh screenshot baselines of studies with an Opacity set on a colour-by plot, and of charts whose scale text size is set.
- A widget with appearance linking and a host that saves on
style:changesees one more setting.
What 2.6.0 writes into saved documents
- Each study that offers a timeframe saves
timeframein its settings,''unless the user chose one. Saving a document from 2.5.10 or 2.5.1 again adds this field and nothing else of this release’s. - A series the chart transforms records its spec as
SeriesState.transform; a series without one records nothing new. - A study set to the underlying bars records
IndicatorState.barSource: 'underlying'; the default is not written. - Workspace documents and indicator templates keep both.
- Document versions are unchanged: chart state 1, drawings 2 (3 only when a drawing is limited to some intervals, since 2.5.9), alerts 1, widget state 1, workspace 1.
Deprecated in 2.6.0
Each keeps working until 3.0.0 and is listed on the compatibility page.
| Deprecated | Use instead |
|---|---|
chart.on, once and off given a name outside ChartEventMap | A ChartEventMap name, which types the listener; declare an event of your own by merging it into ChartEventMap |
chart.emit(name, payload) | chart.setDataContext for an instrument, LinkGroup.setSymbol, setInterval and setChartType for a link group, and an emitter of your own for events of your own |
The priceAxisMoved key of ChartEventMap (the event is deprecated since 2.5.4) | priceAxisPlacementChanged |
| Widget message keys “From (UTC seconds)”, “To (UTC seconds)” and “Enter finite UTC seconds or leave the bound blank" | "From”, “To” and “Enter a date and a time on the chart clock” |
VolumeProfileOptions, which no function takes | computeVolumeProfile(bars, tickSize, valueAreaPercent) as before, or computeVolumeProfileSessions with VolumeProfileFamilyOptions |
TimeScaleOp, InvalidateMask.addTimeScaleOp and InvalidateMask.timeScaleOps | Nothing to queue: since 2.5.8 the frame reads no queued operation; change the time scale with chart.timeScale, chart.fitContent or chart.setVisibleLogicalRange |
InvalidateMask.merge | Nothing: the chart raises one mask per frame, and a host raises levels on the mask chart.invalidate hands it |
updatePositionPnl(id, unrealizedPnl, pnlText?, pnlPercent?), the number first | updatePositionPnl(id, pnlText?, pnlPercent?), the same call without the number the pill never showed |
SeriesStyle.hollow, which never had an effect | The 'hollow-candle' series type |
TradeFeed | OrderFeed from openalgo-charts/trade; hand the book to the chart with chart.trading.syncState |
PlaceOrder | PlaceRequest from openalgo-charts/trade |
The tiers’ structural hosts (AlertChartHost, ReplayChartHost, DrawingChartHost,
PickHost, TradingHost, IndicatorHost) keep their emit member through 2.x, and a Chart
still satisfies each of them. What they take in its place is decided for 3.0.0.
Rolling back
2.6.0 is additive, so rolling back is a deployment step rather than a data migration, with the facts below. The exception is a chart shown as one of the transformed types, which 2.5.10 cannot show.
Before upgrading. Pin the exact version, keep the previous build deployable, and keep a copy
of what you store: the widget’s persisted keys (oac-widget:<namespace>:*), each workspace
(WorkspaceRepository.exportDocument), and whatever you keep from chart.getState(),
DrawingController.toJSON() and AlertController.toJSON().
Before rolling back. Export each workspace with WorkspaceRepository.exportDocument and
keep a copy of the widget’s persisted keys, so a desk 2.5.10 refuses or saves over can be
imported again later. Or switch every chart shown as a transformed type to a plain type in
2.6.0 first, and let it save.
Back to 2.5.10. What 2.6.0 saves loads in 2.5.10 with its studies, drawings and alerts, except a chart grid desk or saved layout holding a transformed chart (the last point below). Three 2.6.0 settings do not carry over. 2.5.10 writes a widget’s layout back as soon as it opens it, so they leave the store at that moment:
- A study set to a higher timeframe keeps the setting but computes on the chart’s own bars. Upgrading again brings the timeframe back.
- A study set to compute on the underlying bars computes on the chart’s bars, and 2.5.10 drops that setting when it saves.
- A chart shown as a transformed type comes back without the transform, and 2.5.10 drops the transform and its options (box size, reversal, range, lines) when it saves. A widget, or a restored chart state, shows Heikin Ashi, Renko, range bars and line break as candlesticks of the raw bars. Point and figure and Kagi come back as 2.5.10 draws them, the raw bars through that renderer, where the transform tier is imported, and as candlesticks where it is not. The saved visible range counts the transformed chart’s elements, so on the raw bars the chart first shows older history.
- A chart grid desk, or a layout saved from the widget’s Layouts menu, with a chart on Heikin
Ashi, Renko, range bars or line break, or on point and figure or Kagi without the transform
tier, does not open:
applyWorkspaceandrestored()reportunknown chart type, and the Layouts menu refuses it. The stored desk is kept until the grid 2.5.10 shows instead is changed, and that change saves over it, studies and all. An exported workspace imports again after upgrading.
After upgrading again, pick the chart type again where it came back as candlesticks (a point and figure or Kagi widget that 2.5.10 kept with the transform tier comes back transformed on its own). Then set the transform’s options and each study’s bar source again: the transform starts from its default options, and a study with a timeframe on a transformed chart shows an error until its bar source is Underlying bars again. A desk 2.5.10 refused and left alone comes back in full; one it saved over comes back as 2.5.10 left it.
Code that calls what 2.6.0 added (setSeriesTransform, setBarSource, withTimeframe,
searchSymbols, the classic tier scripts, require()) comes out before the rollback, and so
does a transform id passed as WidgetOptions.chartType: 2.5.10 throws for a chart type it has
not registered, which is every transform id except point-figure and kagi, and those two as
well when the transform tier is not imported.
Back to 2.5.1. Everything 2.6.0 saves loads in 2.5.1, with its studies, drawings and alerts.
2.5.1 does not know the settings added from 2.5.2 to 2.6.0 (pan and zoom switches, scale
precision, fixed ranges, axis placement, auto-fit and legend preferences, the panel dock), so
they return to their defaults and the next save drops them. The timeframe setting survives,
and a widget layout 2.5.10 moved into IndexedDB is not read by 2.5.1, which finds the copy it
left in localStorage as it was when it was copied. A chart shown as a transformed type comes
back in a 2.5.1 widget as it does in a 2.5.10 one, which applies the same chart type fallback;
2.5.1 has no chart grid or Layouts menu to refuse a desk.
Not covered. Documents a host builds itself rather than through these APIs, and any store other than those above. Test a rollback in a copy of the real host before relying on it.
From 2.5.1
A host on 2.5.1 meets every point above, and each release from 2.5.2 to 2.5.10, whose notes are under Earlier upgrades below. The points a host is most likely to meet, oldest first:
- 2.5.2. Anchored VWAP and Fixed Range Volume Profile join the drawing registry; a toolbar
with a fixed tool list adds
anchored-vwapandfixed-range-volume-profileto show them. The widget opens plain-text event details by default; passeventDetails: falseif the host has its own popup. - 2.5.3. A Data and Objects dock, closed at start;
panels: falsekeeps the Objects popup. A letter or digit typed on the focused chart opens symbol or interval entry;typingNavigation: falsewhen the host owns plain typing. Code withRecord<ChartObjectKind, ...>or an exhaustive switch over it addsgroup, which fails to compile until it does. A host that manages its own styles includesWIDGET_COMPONENT_CSSbesideWIDGET_CSS. - 2.5.4.
chart.navigationOptions()also reportspanEnabledandzoomEnabled. The top pane’s legend starts with an Indicators row. An external-data study asks for its values again after a history resync. HMA at odd lengths and the early ADX readings follow corrected definitions. - 2.5.5. Moving the price pane is opt-in (
movablePrimaryPane). Running studies resume after a missing input.OpenAlgoTradeFeed.placerefusesaccount,duration,expiresAtandleveragebefore any request. - 2.5.6. Times past the last bar follow the median bar spacing. Pane boundaries round to
whole device pixels.
indicator.setSettingsandindicator.removereturn false when a study policy refuses. The OpenAlgo adapters refuse a non-default data variant. The widget’s Undo and Redo walkwidget.history. (Its note that a variant-only change emitsdata:contexttwice no longer holds for a chart: 2.6.0 emits it once, point 12.) - 2.5.7. Nothing a host calls, receives or sees.
- 2.5.8. Level of detail is on by default, but engages only below about one CSS px per bar,
which the default
minBarSpacing: 1never reaches. A study writes its plots throughupdate()on a tick. Draw items handed to a renderer are reused between paints. - 2.5.9. The widget keeps drawings per instrument (
drawingScope: 'instrument'), and a layout saved before that attaches its drawings to the symbol it was saved on. Drawings documents are version 3 when a drawing carries an interval range. Modifier gestures on drawings are on by default, and a floating drawing toolbar shows with the rail. - 2.5.10. With
persist, the widget keeps its state in IndexedDB, copies what 2.5.1 left inlocalStorageon the first visit, and settleswidget.readyonce the saved layout has landed: await it before reading or changing the restored state, or passstorage: localStorageto keep the synchronous behaviour. A 28 px bottom bar carries Go to, preset ranges, the market status and the scale toggles (bottombar: falseremoves it), and the phone layout follows the container’s size, so tablets keep the desktop chrome. Parts of the widget load on first use from hashed files beside the tier: serve a tier file and its parts from one release.
Every release from 2.5.4 to 2.6.0 adds widget message keys. A host that types a complete catalog
as Record<WidgetBuiltinMessage, string> adds them; a translator that returns undefined keeps
the English text. Several of these releases move pixels on purpose, so refresh screenshot
baselines once, on 2.6.0.
Before moving a production host from 2.5.1, install the packed 2.6.0 in an isolated checkout of it and run its own tests, typecheck, production build and browser harness against it, starting from the version it pins today.
A dry run of a production trading host from 2.5.1 to 2.6.0 met the points below, beside the
deprecated chart.on and chart.emit calls point 1 describes; its order requests, quantities,
exchange timestamps, session buckets, volume and replay guards came out the same on both
versions. Each point is a documented 2.5.x change.
- An exhaustive map over
ChartObjectKind(2.5.3).Record<ChartObjectKind, string>, or an exhaustiveswitch, fails to compile with TS2741 until it hasgroup, the kind of a named drawing group, and a build that type-checks first stops there. Add the entry. A group row reaches an objects panel only when the drawing controller has groups. ReplayState.simulated(2.5.9). A test fixture that builds a wholeReplayStateaddssimulated: false. Only a type check sees it; the test itself runs as before.- Replay’s forming bar (2.5.9). The bar that forms step by step keeps the displayed bar’s open, holds its close, high and low inside the displayed bar’s range, and caps its volume at the displayed bar’s. Where the finer history and the displayed interval’s history disagree, as a broker’s can, the forming close is a held value rather than the last finer close; where they agree, nothing is held. An acceptance check that asserts the forming bar equals the aggregate of the finer bars asserts that rule instead: the open is the displayed bar’s open, and the close, high and low are the finer bars’ held inside the displayed bar’s range.
- Two drawing tools (2.5.2) and redrawn glyphs (2.5.6 and 2.5.9). The draw tier registers
anchored-vwapandfixed-range-volume-profile, so a tool menu grouped by hand adds them (the widget’s rail puts them in a Volume studies group), and a test that pins the menu to the registry fails until it does. Nineteen drawing-tool glyphs were redrawn in 2.5.6 and eighteen in 2.5.9: generate any catalogue or snapshot of glyph paths again from the installed package. - The indicator catalogue (2.5.10 and 2.6.0). Since 2.5.10
rocis named “Rate of Change” (it was “Rate Of Change”) andwilliams-vix-fix“Williams VIX Fix” (it was “William VIX FIX”), with their ids unchanged, and 2.6.0 adds seven built-ins. Generate a catalogue that a test pins to the registry again, and match studies by id, never by display name. - Row names in an objects panel. The new tools’ rows read “Anchored vwap” and “Fixed range
volume profile”, built from the tool id, unless the host passes
ChartObjectsOptions.drawingName(since 2.5.10) to name rows by the draw registry’s display names.
See the release notes for everything 2.6.0 adds, and the benchmark measured against 2.5.10.
Earlier upgrades
Version 2.5.10 needed no code change for most hosts. Saved layouts, drawings and workspace
documents from 2.5.9 loaded unchanged, and no export was removed. A host that persisted the
widget, served dist/ itself, or tested the widget’s words and roles checked these points:
- Widget persistence is asynchronous by default. With
persistand nostorage, the widget and the chart grid keep their state in IndexedDB. The saved symbol, interval, layout, drawings and chords land once the store answers, andwidget.ready(grid.readyfor a grid) settles then; until it does, the widget shows its defaults out of sight and asks the feed for nothing. A host that changes the symbol or reads the saved state right aftercreateWidgetawaitswidget.readyfirst. The first visit copies theoac-widget:<namespace>:keys 2.5.9 left in localStorage and leaves them there. To keep the 2.5.9 behaviour call for call, passstorage: localStorageor any synchronous store. See Persistence. - What
readysettles on.widget.readyandgrid.readynever reject. A store that fails, or does not answer within 4 seconds, is reported on the status line and in a toast; the widget then opens on its defaults and keeps that session’s changes in memory only. When the saved state lands, the saved symbol and interval arrive assymbolandintervalevents, and the layout as alayoutevent with the reasonrestore. Add default studies or drawings afterready, because what a host adds before it may be replaced by the saved layout; a symbol, an interval or arestoreStategiven beforereadyis newer than the stored one and wins. On a grid, a workspace applied withapplyWorkspacebeforereadywins, whilesetPreset, or a symbol set on one of its charts, beforereadyis replaced by the stored desk, andgrid.restored()is null until then. To name the database, passstorage: createIndexedDbWidgetStorage(indexedDB, 'my-app-charts'). A test that seeds or readsoac-widget:keys in localStorage reads IndexedDB instead or passesstorage: localStorage, and a test that takes a screenshot or queries the chart right aftercreateWidgetawaitsreadyfirst. Every change after the copy lands in IndexedDB only, so a page that goes back to 2.5.9 finds the localStorage keys as they were when they were copied. - Serve the widget’s parts with the tier. Seven parts a plain widget never opens (the
shortcuts editor, the Layouts menu, the templates list, the chart data dialog, the grid bar
and its menus, and the IndexedDB store) load on first use from files beside the widget tier,
named by a content hash (
openalgo-charts.widget.<part>-<hash>.mjs). A host that servesdist/itself deploys the whole directory from one release, revalidates the tier files, whose names stay the same, and may cache the hashed parts for a long time. A strictscript-srcallows their directory, never a part by name. A CDN URL pinned to the version needs nothing. A part’s rules join the widget’s one stylesheet and keep itsstyleNonce, sostyle-srcneeds no change. A part that cannot load says so in a toast, or on the status line for the store, the chart data dialog and a grid’s menus, and asking again gives the same answer until the page reloads; the rest of the widget goes on working.openShortcutsPanelstill returns its closer at once, but its first call opens the panel only once the part has arrived, so a test that looks for the panel right after the call waits for it to appear.openLayoutsMenu, new in this release, resolves with the menu once it is open and rejects when it cannot load or the widget was destroyed first. The widget file also exports, under minified names, the helpers its parts import: they are not API, no declaration names them, and a host never imports them. - The bottom bar is on by default. It carries the preset ranges, Go to (moved from the top
bar), the market status, a clock with a timezone menu and the scale toggles, and the widget
attaches session shading, which shades nothing unless the calendar has pre-open, post-close
or extended hours.
bottombar: falsegives the 2.5.9 chrome back, with Go to in the top bar and the market status on the status line, andsessionShading: falseturns the shading off. A chart grid shows one bar for the active chart only withbottombar: true; without it each chart keeps Go to in its top bar and its footer shows the market status. The bar is 28 px tall, so the chart is 28 px shorter in the same container. A widget built withtopbar: falsegets the bar too,ranges: []leaves the range buttons out, and a timezone picked in the bar, or anywhere else, is saved with the layout and emitslayoutwith the reasontimezone, which a host that saves onlayoutevents now sees. Refresh screenshot baselines of the widget. - Auto mobile mode follows the container’s size. Tablets and touch laptops now keep the
toolbar and the drawing rail, and phones keep the compact controls. The rule: a container
at most 640 CSS px wide, or, with a coarse pointer, at most 960 px wide and under 600 px
tall. On a tablet a touch on a rail group picks its tool, and a long press, or a second tap
on the active tool, opens the list. Pass
mobile: 'always'or'never'to force either; to keep the compact controls on every touch device, passmobile: matchMedia('(pointer: coarse)').matches ? 'always' : 'auto'. A test at a tablet viewport that expected the phone layout now finds the desktop chrome, and screenshot baselines taken on touch devices need refreshing. - Users can move shortcuts. The ? panel edits every chord the widget owns, and with
persistthe chords are saved.shortcutsEditor: falsekeeps the panel a list and applies no saved chords, andopenShortcutsPanel(ctx, { edit: false })opens the list from a host control. A chart command resets to the chord it had when the widget mounted, so chords a host passes inshortcuts.overridescount as its defaults, and in a chart grid the chords belong to the desk. Leave the engine’s ownshortcuts.persistoff on a widget: the widget saves the chords itself, and with both on a chord chosen in an earlier visit is read back as the default and Reset has nothing to return to. - Words a host test may match on. Trading capability reasons are in words (“Placing orders
is not supported”, “Stop-loss orders are not supported”, “Live trading is not supported”)
where they named ids; test
supportedrather than the text.DEFAULT_KEYMAPsays “Reset view” and “Fit all bars”, the indicatorswilliams-vix-fixandrocare named “Williams VIX Fix” and “Rate of Change” (the ids are unchanged), chart settings say “Linear” and “Auto-fit to the data”, and the unknown indicator and missing transform tier errors use a comma where they had an em dash. The widget says active, not armed. The theme button shows a sun or a moon and no text, so a host or test that read its text reads its accessible name orwidget.theme()instead. A host that types a complete catalog asRecord<WidgetBuiltinMessage, string>adds the new keys, the chart grid’s words among them (ChartGridMessageis now part ofWidgetBuiltinMessage). The bottom bar, the ranges, the market status, the Layouts menu and the templates list speak through newschema.ui.*keys (schema.ui.bottombar.*,schema.ui.range.*,schema.ui.market.*,schema.ui.layouts.*,schema.ui.templates.*and their neighbours); a translator that returnsundefinedfor them keeps the English text. - Widget roles and names. An action row in a widget menu has the role
menuitem(for example “Download chart data (CSV)”), and only a choice keepsmenuitemradio. A toggle keeps one name (“Lock”, “Hide”, “Pin to rail”) and reports its state througharia-pressedoraria-checked, so a test that looked for “Unlock” or “Show drawing” looks for the constant name and its state. Two objects of one name are “Relative Strength Index (2)” in Objects, the alert editor and its list, study settings and the CSV dialog, where the alert editor wrote “2: Relative Strength Index”.renderFormputs the rows under a heading in adiv.oac-form__groupwithrole="group"anddisplay: contents, so a stylesheet with.oac-form > .oac-form__rowchild selectors allows for it. A field’s help text is its control’saria-description, not part of its name. Level editor rows are named by their level (Level 0.618 enabled,Remove level 0.618), the search and pick buttons of an indicator input by the input’s label, a pinned rail tool asTrend Line (pinned), and an interval pill by the text it shows. The Objects add-to-selection button and the grid’s Maximize no longer carryaria-pressed, and a menu row’s chord is itsaria-keyshortcuts, so its name no longer ends in the chord. - Deprecated message keys. A translation catalog keeps compiling. The keys the widget no longer shows are listed on the compatibility page with the keys to translate instead, and are dropped in 3.0.0.
matchDrawingShortcut. Pass the keydown event itself, socodeis there: Option chords on macOS then match. A typed letter still decides the tool, so other layouts behave as in 2.5.9.- Chrome glyphs. Every widget picture comes from the icon registry, the theme button shows
a sun or a moon, and the maximize, restore, check and calendar glyphs are redrawn. Refresh
screenshot baselines of the widget chrome.
chromeIcon,chromeIconAccent,drawingToolIcon,drawingToolAccentandchartTypeIconread only a registry’s own entries: an inherited name such astoStringnow givesundefined, and the SVG builders throw for it as for any unknown id. - The chart grid.
CHART_GRID_PRESETSlists every uniform layout up to four by four, andChartGridPresetis wider to match: an exhaustive switch over it handles the new ids, and a host that labels the presets itself readsCHART_GRID_LAYOUT_NAMES.presetandsetPresettake anyChartGridLayoutId, uneven layouts included. A cell narrower than 560 or shorter than 340 CSS px is dense: it hides its drawing rail and keeps its top bar to one row, which applies to 2.5.9 desks too (a two by two grid on a laptop screen under about 700 px tall); drawing shortcuts still work, and maximizing a chart shows everything again.layoutevents carry two more reasons,maximizeandswap.linkOptions()reads the active chart’s group, andsetLinksswitches that group, or every group while the active chart is in none. Until the user makes a second group, names one or takes a chart out of it,getWorkspace()writes what 2.5.9 wrote; with groups, a 2.5.9 reader drops them and applies the flat flags. The grid bar (toolbar) and the bar under the charts (bottombar) are off unless the host turns them on. Refresh screenshot baselines of small cells. - The status line and text markers. In
mountStatusline,setBar(null)now lets the row follow the latest bar where it used to clear the readings, andsetSymbolwith a title other than the one set clears the readings until the chart’s data is next replaced. Text markers take lanes, so pixels move where neighbouring labels collided: refresh screenshot baselines of charts that show text markers. - Interfaces a host implements itself. A host object written to one of these types adds
the new members:
Widget(ready,layouts,openLayouts,setRange,range),ChartGrid(ready,maximize,restore,maximized,swap,linkGroups,setLinkGroup,addLinkGroup,setGroupLinks,renameLinkGroup,shareDrawings,takeScreenshot,downloadScreenshot),ChartGridCell(linkGroup) andKeyBinding(defaultCombo,command,rebindable). The new members ofSessionCalendarSource,ChartShortcutSource,KeyEventLike,LinkOptions,LinkMemberOptions,MenuRow,TopbarOptions,MobileOptions,StatuslineOptionsandIndicatorPickerOptionsare optional.WidgetOptions.storageandChartGridOptions.storagealso take anAsyncStorageLike,WorkspacePayload.syncis aWorkspaceSync(a four-flag sync a host builds still type checks),KeymapGroup.rowsis aKeymapRow, andCHART_GRID_CSSis typedstring; the grid bar’s own rules left it and arrive with the bar’s part. - Worth knowing, nothing to do.
WorkspaceRepositorymethods take an optional lastoptionsargument; withoutexpectedRevisiona change applies to the catalog as stored, andsubscribeis new.ShortcutManager.onChangeis new, and the time navigator’s key hints follow a rebind unless the host passed hints of its own.ChartHistory.clear()empties its stacks in place. Session phases, market status, session shading, the link channels, the layouts controller and the grid’s groups are opt-in outside the widget’s defaults above.
See the release notes for everything 2.5.10 added.
Version 2.5.9 needed no code change for most hosts. Saved layouts, drawings and workspace documents from 2.5.8 loaded unchanged, and no export was removed. What a host could notice:
- Drawings belong to the instrument they were drawn on. The widget and the chart grid
now keep one drawing document per instrument (
drawingScope: 'instrument', the default): loading another symbol shows that symbol’s drawings, and deleting them there leaves the first symbol’s alone. Withpersist, each instrument’s drawings are stored beside the layout underoac-widget:<namespace>:drawings:<exchange>:<symbol>. A layout saved before this attaches its drawings to the symbol it was saved on. To keep one set of drawings whatever symbol is loaded, passdrawingScope: 'chart'. See Drawings per instrument. - Drawings documents may be version 3. A document is written as the lowest version
that holds it: version 3 only when a drawing carries an interval range (visibility per
interval), otherwise version 2, byte for byte what 2.5.8 wrote. A host that checks
version === 2must accept 3. An older build refuses a version 3 clipboard payload and drops the ranges from a version 3 layout. - Modifier gestures are on by default. Ctrl while placing or dragging snaps strongly,
Shift+click on empty space lays down a temporary measure, Ctrl+drag on empty space
selects every drawing the box touches, and Alt+drag on a drawing drags a copy. A host
whose own chart gestures use one of these keys turns it off with
gestures, for examplegestures: { boxSelect: false }. See Modifier gestures. - The widget shows a toolbar over the selected drawings on a desktop layout. It is on
whenever the drawing rail is;
drawingToolbar: falseturns it off. - The price axis. The bar countdown appears only in the last-price tag of the pane that shows the chart’s price source, so a study pane’s value tag stays one row. The last-price and study value tags are painted over price-line and level tags where they meet, so an order tag within a tag height of the last price is now under it. A tick label within half a tag height of a pane’s top or bottom edge is left out instead of being cut in half; its gridline stays. Refresh screenshot baselines of study panes.
- Lines at the edges of the view. A line, step or area series draws the segment that
crosses each edge of the view, so a sparse level held across the edge no longer loses
that part. Dashed lines keep 2.5.8’s dash pattern along the bars in view, and a gap at
the edge is never bridged. A custom renderer that joins neighbouring bars opts in with
RendererEntry.connectsBars. Pixels change at the edges; refresh screenshot baselines that crop there. - Replay’s forming bar. With
subBars, the bar that forms step by step now carries the displayed bar’s open from its first step, and its high, low and volume never pass the displayed bar’s, so nothing jumps back when the bar closes.ReplayStategainssimulated; a test that compares a whole state object withtoEqualneedssimulated: falseadded. The new, optionalsimulate: { steps }forms a bar that no finer bar covers over simulated steps. See Market replay. - A
DrawingLayerdriven directly. The layer now keeps a hit box per drawing. A host that drives aDrawingLayeritself and edits a drawing in place passes the list again withsetDrawings, asDrawingControlleralready does. - Widget colours. Faint chrome text now meets WCAG AA (4.5:1) in both themes, and the
watchlist’s up and down colours follow the theme through the new
--oac-upand--oac-downtokens. Eighteen drawing tool glyphs are redrawn. Refresh screenshot baselines of the widget chrome.
See the release notes for everything 2.5.9 added.
Version 2.5.8 needed no migration. Saved layouts, drawings and workspace documents from 2.5.7 load unchanged, no export was added or removed, and a chart that keeps the default zoom floor paints the same pixels. It changes one default and how a study writes its plots, and it makes several internal paths cheaper that a test of your own may count.
Check these points in your host:
- Level of detail (
conflate) is on by default. It engages only below about one CSS px per bar, which the defaulttimeScale.minBarSpacing: 1never reaches. If your host lowersminBarSpacing, a chart zoomed out past that spacing now draws one OHLC-preserving stick per device-pixel column, and line and histogram series keep each column’s extremes. OHLC bar series look thinner there, because one stick’s open and close ticks spill into fewer neighbouring columns than every bar’s did; the envelope is the same. Refresh screenshot baselines taken at those zoom levels, or passconflate: falseto draw every bar. See Large datasets. conflationFactorhas a new meaning. It is now the column width in sticks; it used to multiply a half-pixel threshold. A value you set therefore engages the merge at a wider spacing than before. A chart type you registered withregisterChartType, even under a built-in name, still receives every bar.- A custom
IndicatorHost(only if you implement it yourself;createChartsupplies its own). On a live tick a study now writes its plots throughupdateon the series youraddIndicatorSeriesreturned, for the points that changed and the last point, instead of onesetDataof the whole history. That series’updatemust behave asSeriesApi.updatedocuments: an item at an existing time replaces that point, an older one included, and a newer one appends. A series that ignoresupdateshows the study frozen at its last whole write. - Data written into a study’s plot.
indicator.series(key)is for styling. Data you write into it used to be overwritten on the next recompute; it now survives wherever the study did not move a point. Put values of your own on a series of your own. - Primitive hit boxes (
hitBounds). Optional: a primitive without one is asked on every pointer move as before. If you add one, it must hold every point yourhitTestanswers, work from the same geometryhitTestuses, and change only with the scales, the pane’s layout, hover and drag, or your own state announced throughhost.requestUpdate(); anything else it depends on (bar prices, say) must callrequestUpdatewhen it changes. A primitive that declares a box is attached with a host object that wraps the chart’s, so do not compare that host with another by identity. See Hit boxes. hitTestcan be skipped. Besides the boxes, a pointer move stops at an exact hit (distance: 0) among the primitives painted in front. KeephitTestfree of side effects, and never return a negativedistance.- Draw items are reused. The
itemsarray and its objects handed to aRendererEntry.drawor anIRenderBackend.drawSeriesare rewritten the next time the pane draws that series. A renderer or backend that keeps them past the call must copy them. - The built-ins’
calcTail. Sixteen built-ins now carry one, as a property that is not enumerable, so{ ...getIndicator('ema'), calc: myCalc }recomputes in full throughmyCalcas before. Code that lists a built-in’s keys sees no change; code that testsdescriptor.calcTailon one of the sixteen now finds a function. Copy it by name (calcTail: getIndicator('ema').calcTail) only when yourcalcreturns the built-in’s result unchanged. See the built-ins’ tails. - Glides step inside the chart’s frame. An injected
rafnow gets one request per kinetic or zoom-glide frame instead of two, a glide’spanandzoomevents fire in the frame that paints them, and the autoscale easing during a glide starts a frame earlier. Charts in aLinkGrouppaint a glide one frame apart: the leader in the frame it steps, a follower in the next, where both used to lag a frame together. A history loader that throws while a glide runs now also skips that frame’s paint until the next change; catch inside the loader. - Fewer repaints. A tick that replaces the forming bar, and a study recompute,
no longer repaint the panes they do not change, so a test counting
Pane.paintBasecalls sees fewer. The pixels are those of a full repaint. While the bar countdown is on, every pane with a price series still repaints on each tick, and the bottom pane while the corner clock is on.
New and optional: IPrimitive.hitBounds. See
Primitives and plugins,
Indicators and the
release notes.
Version 2.5.7 needed no migration and no code change. It reorganised the chart’s internal code; every public method, option, event and type stayed the same, saved layouts, drawings and workspace documents from 2.5.6 loaded unchanged, and charts painted the same pixels. The base engine grew by 1.52 kB Brotli. Code that reached into the chart’s private members (never supported) found several of them moved to internal collaborators.
Version 2.5.6 needed no migration. Saved layouts, drawings and workspace documents from 2.5.5 loaded unchanged, and every new contract was optional.
Check these points in your host:
- Times past the last bar now continue at the median of the last 64 bar intervals, or follow a session calendar when you set one, instead of the gap between the last two bars. Stored drawings keep their times; one anchored in the future is drawn where that time now falls. Evenly spaced data maps exactly as before.
- Pane boundaries round to whole device pixels. At a ratio of 1 a pane’s height can differ from its exact share by up to one pixel, and at a fractional ratio the separator is a one device pixel box over the lower pane instead of a CSS border. Screenshot baselines of multi-pane charts at 1.25 or 1.5 need refreshing; at whole-number ratios a chart whose pane heights are whole pixels paints exactly as before.
- Chrome icons draw a 2px line and 19 drawing tool glyphs changed. Update any snapshot of the icon markup.
indicator.setSettingsandindicator.removereturn a boolean, false when a study policy refuses the call. User-facing controls you build should call them without{ force: true }, so a policy the host set is respected.- The OpenAlgo adapters and
FakeDataFeedrefuse a non-default data variant withDataVariantUnsupportedError. A feed withoutdataVariantsserves only its default series. - A variant-only change through
publishDataContextemitsdata:contexttwice, a passing context with the interval cleared and then the real one. A host listener that fetches ondata:contextshould skip a context without an interval. - The widget’s Undo and Redo now walk
widget.history, not only the drawing history. A host with its own undo stack can readDrawingController.historySteps()and thestepondrawing:change, or hand input anchor steps over withdelegateInputAnchorSteps. - A host that types a complete translation dictionary as
Record<WidgetBuiltinMessage, string>must add the new messages for conditional inputs, point picks, data variants, protected studies and undo failures; a translator that returnsundefinedkeeps the English text. - Deprecated, working until 3.0.0:
mapOrder, a study level’sdashed, the flat modifier flags onclick,chart.movePriceAxisand thedepth_levelkey in depth frames. See the compatibility policy.
New and optional: IndicatorPolicy on addIndicator, the series stack
(seriesStack, moveInSeriesStack, placeInStack), ChartHistory, data
variants (BarsRequest.variant, DataFeed.dataVariants, the widget’s
variant option), SessionCalendar and chart.setSessionCalendar, paired
timeKey inputs with chart.beginPick('point'), visibleWhen, activeWhen
and inline on inputs, and background targets. See
Indicators, Data variants,
Instruments, Scales and panes and
Widget controls.
Version 2.5.5 needed no migration. Saved layouts, drawings and workspace documents from 2.5.4 loaded unchanged, and every new contract was optional.
Check these points in your host:
- Moving the price pane is off unless you opt in with
movablePrimaryPaneoncreateChart,createWidgetorcreateChartGrid. Without it pane 0 is the price pane exactly as before. Before you opt in, replace every explicit0that means the price pane with no pane argument orchart.primaryPaneIndex(), followpaneMoved, and includeprimaryPanein any saved-state allowlist. See Opting in. - A chart state that moved the price pane is written as version 2, and an older engine refuses it rather than misplacing the price pane.
- Running studies such as ATR, Supertrend, VWAP, OBV, A/D, Parabolic SAR, CCI, Stochastic, RVI and TSI now resume after a missing or non-finite input instead of going blank. Complete data reads as before, apart from last-digit changes in TEMA, Stochastic, True Strength Index and the SMI Ergodic pair, and the corrected Trend Strength Index. See the release notes and the Numerical contract section of Indicators.
OpenAlgoTradeFeed.placerefusesaccount,duration,expiresAtandleverage, which OpenAlgo’s order endpoint does not take, before any request.- A host that types a complete translation dictionary as
Record<WidgetBuiltinMessage, string>must add the new account summary, pane move and drawing anchor messages; a translator that returnsundefinedkeeps the English text.
Also new then: named watchlists (WatchlistRepository) with QuoteFeed
rows and a NewsFeed reader in the widget dock, account state and native
position commands for brokers that declare them (AccountManager,
TradingFeatures, previewOrder, closePosition, reversePosition),
price-dependent TickSchedule bands, and drawings pinned to the viewport
(space: 'viewport'). See Widget controls, Trading,
Instruments and Drawing tools.
Version 2.5.4 needed no migration. Saved layouts, drawing documents and workspace
documents from 2.5.3 load unchanged; pane collapsed, drawing policy and a
pane’s historyPeriod are optional fields that older records simply omit.
Check these points in your host:
chart.navigationOptions()now also reportspanEnabledandzoomEnabled. A test or a comparison that expects exactly{ mousePan, defaultVisibleBars }must include them, or compare the fields it cares about.- When studies are applied, the top visible pane’s legend starts with the persistent Indicators N control, so study rows begin one row lower. Code that locates legend rows by fixed pixel offsets must allow for that row.
- An external-data study requests its values again after the chart’s history is resynchronised, because the bars are a new source revision. Resolve that request as you would the first; its status reads as loading until you do.
- The widget’s top bar gains Go to. A host that types a complete translation
dictionary as
Record<WidgetBuiltinMessage, string>must add the new go-to and grid messages; a translator that returnsundefinedkeeps the English text. - HMA at odd lengths and the early ADX readings follow corrected definitions, and several averages treat missing or overflowing inputs as unavailable. Strategies tuned on the old values should be checked. See the release notes.
New and optional: widget.goTo() and DateNavigator for date navigation,
createChartGrid for a grid of widgets, chart.setPaneCollapsed(), overlay
and plot targets on study drawings and markers, and a policy on drawings.
A drawing UI of your own should route its edits through the drawing controller,
which enforces policies, and pass { force: true } only for the host’s own
changes. See Chart grid, Data loading,
Scales and panes and Drawing tools.
Version 2.5.3 adds the widget’s Data and Objects dock, richer symbol lookup,
direct typing, shared colour controls, and individual running-study removal.
The dock starts closed. Set panels: false to retain the Objects popup, and
typingNavigation: false when your application already owns plain typing.
Existing symbol lookup callbacks and results still work. Asset categories,
images, and futures contracts are optional host-provided metadata.
Saved widget records can include panels, and drawing documents can include
named groups. Older records load without migration. Study movement retains IDs
and attached alerts. Reordering changes the rendered order; custom object
providers can opt into the new move and reorder callbacks. Custom inventories
should handle the additive group object kind when consuming grouped drawings.
If your TypeScript host uses Record<ChartObjectKind, ...> or an exhaustive switch,
add a group entry before upgrading. Existing stored drawings do not need a rewrite.
For custom hosts, createAlertUi().context can mount the shared panel, search,
and form components. Use the context’s overlay opener for nested colour popups,
and call a generated form’s destroy() before unmounting it. Include
WIDGET_COMPONENT_CSS alongside WIDGET_CSS if your host manages styles.
See Widget controls and Objects.
Version 2.5.2 adds Anchored VWAP and Fixed Range Volume Profile to the drawing
registry. Existing drawing records still load. Both tools need candle volume;
missing observations stay missing, and a profile is a candle-based estimate,
not a record of traded volume at each price. See Drawing tools.
Custom toolbars with a fixed tool list must add anchored-vwap and
fixed-range-volume-profile to expose them. The widget and reference host already do.
Drawing and appearance synchronization are opt-in. Use DrawingLinkGroup from
openalgo-charts/draw for price-pane drawings on the same symbol and exchange.
Persist its drawing metadata to reconnect saved copies, and call share() to
include existing local drawings. Appearance links use the chart settings adapter;
they do not copy instrument, timezone, alerts or orders. See Chart linking.
Timeline events retain their existing marker behavior. Enable clustering and
groups through the new event APIs. The widget opens plain-text event details by
default; set eventDetails: false if your host supplies its own popup. Calendar
data and optional detail loading remain the host’s responsibility. See
Timeline events and the 2.5.2 release notes.
Set the new instrument context before supplying its events: symbol or exchange
changes clear the previous calendar, while interval changes preserve it.
Version 2.5.1 adds the opt-in controller setting spentLines: 'hide' to hide
triggered and expired alert lines. The default remains 'show'. The alert stays
in list() and saved state, so a once-only alert remains spent after reload.
Re-arming restores its line. Set this policy when constructing each controller;
it is not stored in alert documents. See Finished alert lines.
Version 2.5.0 adds automatic table columns with cellWidth: 'auto' and clips text
inside every cell. Alert drags now snap to their source scale’s tick in both
preview and release. The widget and yfinance host support removing a hovered
alert with Delete or Backspace, after drawing and text-editing shortcuts. Custom
hosts can use alerts.hovered() to add the same shortcut.
Version 2.5.0 keeps fixed price-alert levels visible across timeframes for the same symbol and exchange. The label names the original timeframe and an armed alert shows Paused when another timeframe is open. Evaluation still uses the original timeframe, including intrabar alerts. Return to that timeframe to resume; the controller does not evaluate unseen bars in the background. Triggered records survive reload, and changing intervals cannot consume another interval’s evaluated-bar checkpoint. No API or saved-alert migration is needed. See Trader alerts and the 2.5.0 release notes.
Version 2.4.8 shows a grabbing hand while you hold the plot. Mouse and pen panning stops on release, including a release outside the chart. Touch flicks keep their momentum. Two-axis panning remains the default; saved horizontal-only preferences still apply. No API or saved-state migration is required. See the 2.4.8 release notes.
Price and study-threshold alerts now support dragging through the existing alert
controller. No additional drag callback is required. Preview only moves the line;
alert:updated and saved state change once on release. Cancel with Escape or a
touch cancellation. Pause, replay, source changes and restoring or updating an
alert discard an unfinished gesture. Drawing-anchored levels still move with
their drawing. An armed badge reads “Alert”; persisted state is still armed.
If your host consumes raw primitive gestures, drag:start uses the same payload
shape as drag:end. drag:cancel carries { id, paneIndex, reason }, with reason
pointercancel, pinch or escape. For compatibility, pointer cancellation
still delivers the existing end notification after cancellation; discard your
draft on drag:cancel before considering a later release. Custom primitives
opt into Escape rollback with PrimitiveHit.cancelOnEscape: true and must
handle cancellation without requiring an end notification.
See Trader alerts, the alert example and 2.4.7 release notes.
Existing 2.4.6 integrations
Version 2.4.6 preserves default plot anchoring. To place an overlay’s signals
outside candle highs and lows, set markerAnchor: 'price' on its descriptor.
This uses the primary series and its current price scale. Separate-pane studies
keep their own plot anchors. Instrument bars fill plot gaps only when the plot
and primary series share the price scale.
Set hasSource: true only when your host handles indicatorSource. The event
identifies the descriptor, instance and pane; your host resolves and displays
the source. Use legendIconSize or chart.setLegendIconSize() to set a common
button size across existing and future legend rows. See the
indicator guide and release notes.
The 2.4.6 alert editor uses its opening chart timezone for expiry and prefills
new drafts two calendar months ahead. Clearing the field keeps an alert
indefinite. Existing saved alerts and programmatic defaults are unchanged.
Hosts with translation catalogs should add the new zone-neutral expiry
messages; previous typed keys remain accepted. Dialog fields also respect
--oac-ctl-h and --oac-radius and share a consistent control column.
Adopting the 2.4.5 host contracts
Existing chart options keep their defaults. Update the package and lockfile, then run your host’s source-switch, persistence, replay and trading guard checks. The optional APIs require explicit host wiring; a dependency update alone does not add workspace controls to an existing terminal.
- Import named layout and template contracts from
openalgo-charts/workspace. Keep account namespaces separate and show rejected saves or revision conflicts. Portable documents exclude credentials, live orders, positions and armed state. - Treat open interest (
Bar.oi) as a level: folds take the latest defined reading, never a sum. Preserve missing observations and real zero separately. Declare instrument OI support independently of whether the current bar has an observation. - Restore drawing and study identities before their alerts. Triggered once alerts survive reloads, and restoration sends no historical notifications. Alert delivery remains your host’s responsibility.
- Use Instrument for validated calendar, supported interval, formatting and quantity rules. Keep request cancellation and quantity units at your adapter boundary.
- Supply optional widget translation and trading capabilities when needed. Capability checks complement server authorization and broker authority. Keep order entry locked through replay selection and transitions, as well as active or paused replay.
The complete integration guide includes data, persistence and validation details. Read the compatibility policy for public API and support boundaries, and the release notes for the full change list.