Skip to content

Release notes

All notable changes to this project are documented in this file. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

  • The channel studies open with their usual inputs and fill their bands. Envelopes opens at 10% and fills the band between its upper and lower lines. Keltner Channels take a source (close by default), an exponential or simple middle line (exponential by default) and a band style, KeltnerBand: Wilder’s average true range (the default), the bar’s own true range, or Wilder’s average of the bar’s high minus low over the middle line’s length; the default inputs give the former values bit for bit. LinearRegressionChannel opens at 100 bars, takes separate upper and lower deviations (2 each; with_multipliers sets them and new sets both) and fills the band above and the band below its middle line. MA Channel draws the simple average of the highs as its upper line and of the lows as its lower line, each with its own length (20) and bar offset (0), and fills the band between them. All fills use the faint shade Bollinger Bands and Keltner Channels already use, and a colour list with at least as many entries as the study has lines replaces that many leading colours, so a list without the fill colours keeps the fills. Saved templates and layouts keep loading: StudyTemplate::create_with upgrades a regression channel saved with one multiplier to both deviations and loads an MA Channel saved before this change as Envelopes with its length, percentage, a simple average and its styles, which draws exactly the lines it had. (#1492)

  • Long and short position drawings are edited by level. Their Inputs tab lists Entry price, Target price and Stop price, and Target and Stop distances in ticks that follow the prices, using the tick size of the chart’s instrument; without one the tick rows are disabled and the tab says the tick size is unavailable. Changing the entry moves the target and the stop with it and keeps their distances, and a position with two anchors gains an explicit stop, mirrored from the target about the entry, only when a level is edited. Target colour and Stop colour set the zone and level colours; they are saved with the drawing, its templates and defaults and carried through previews, cancellation and undo, and without them the former colours apply, so saved drawings keep their look. The entry, target and stop prices are tagged on the price scale of the pane that owns the drawing, the target and stop in their colours, with the scale’s own formatting, contrast and overlap handling, whether or not the drawing is selected and only while the drawing is visible. (#1408)

  • SymbolSearchDialog::open_with_selected_query opens symbol search with the supplied text selected on its first focused frame, so typing replaces it, where open_with_query keeps the text of a typed shortcut with the cursor after it. The demo and terminal pass the current symbol when the user opens search explicitly, and a clear control in the query row empties the query. (#1561)

  • A drawing can be shown on ranges of intervals of every unit. A drawing limited to some intervals could be shown only on nine fixed intervals, from 1min to 1M, so it disappeared on 2h, 3min, seconds, ticks, ranges and every other interval, and a level drawn on a 4h chart could not also be kept on the 2h chart. TimeframeVisibility::ranges holds, per TimeframeUnit, a range of values with both ends included, and is_visible_on reads the unit and value from the interval’s label as Timeframe::as_str writes it (90min is 90 minutes, and a 24 hour interval labelled 1D is 1 day); range and set_range read and write a unit’s range, and set_range replaces that unit’s saved labels. Labels saved before ranges are still matched exactly. The Visibility tab has one row per unit (ticks, volume, range, delta, milliseconds, seconds, minutes, hours, days, weeks and months) with a checkbox and from and to values, and writes only the row the user edits, so the saved labels of other units keep their exact visibility. A filter that names no interval and holds no range loads as show on all, and a drawing restricted by ranges alone stays restricted after a reload. Files of drawings without ranges are written byte for byte as before. (#1368)

  • examples/network_feed.rs connects a chart to a network backend, natively and in the browser. It implements Datafeed over HTTP: resolve and history fetch JSON and answer their Reply after the call has returned, from a thread natively and from a fetch task on wasm32, and history sends before, since and count. HTTP statuses map to FeedError categories whose recoverability decides whether the chart retries: a server error is a Network error, 429 is RateLimited with its Retry-After, and 404 is SymbolNotFound. Live trades arrive as server-sent events and go into the subscription’s Sink until it becomes inactive. The example starts its own backend of generated sample data on a local port, which fails every fourth history request on purpose so that scrolling back shows the retry, and --serve runs the backend alone on port 8090 for the browser build of examples/network_feed.html. The library’s dependency tree is unchanged: the native client is plain HTTP over std::net and the browser client uses web-sys as a wasm32 dev-dependency. The builder guide and the README list the example. (#1486)

  • The drawing bar’s magnet button switches the magnet on and off with one click and keeps its strength, and a secondary click opens Off, Weak, Strong and Snap to indicators, where a menu selection was needed to switch it. The Hide menu gains Hide all and the Remove menu gains Remove drawings and indicators, through DrawingToolbarAction::HideAll and DrawingToolbarAction::RemoveDrawingsAndIndicators; the terminal and demo apply each as one undoable operation. The Gann section lists box, fixed square, square and fan, in that order. (#1409)

  • Instrument::profile_resolutions lets a feed suggest, from Datafeed::resolve, the bars volume profile studies read: each ProfileResolution names an interval and the longest profile it serves, measured from the open of the profile’s first chart bar to the close of its last, or any length. While the Source interval input follows the chart and the new Feed suggested interval input is on, as it is by default, the visible range, fixed range, session, periodic, anchored and auto anchored profiles request the shortest suggested interval shorter than the chart’s that serves their length: the visible bars for the visible range profile, the longest period for session and periodic profiles. When the length crosses a limit the request changes and replies for the previous interval are dropped. Without suggestions the studies spread each chart bar’s volume as before. (#1087)

  • The session volume profile adapts its rows to the zoom with the new Adapt rows to zoom input. Every session in view then takes one row height, the price range of their chart bars divided by Row count, raised to 1, 2 or 5 times a power of ten ticks of the instrument’s tick size, or of price without one, in place of the Height input. Zooming in to fewer sessions gives finer rows and zooming out coarser ones, each row a whole number of ticks on a grid from zero; volume, point of control and value area follow the same rules as before, and a flat range keeps the configured rows. (#1087)

  • The Style tab offers Line start and Line end choices (Plain or Arrow) on trend lines, rays, extended lines, info lines, trend angles, horizontal lines, horizontal rays, vertical lines, arrows, arrow markers, paths and polylines. Rectangles and parallel channels offer an optional thin dashed Middle line, off by default, that follows their extensions; the channel’s checkbox moves from its Inputs tab, which is no longer shown for it, to the Style tab. These settings use the existing drawing defaults, persistence and undo paths. The rows come from DrawingToolType::supports_line_ends and supports_middle_line, which a test compares with what each renderer paints, so the dialog cannot offer a row that does nothing or miss one a renderer honours. (#1372, #1453)

  • Shift holds a trend line, ray or channel point to 45-degree steps while it is placed or dragged, makes a new ellipse a circle and keeps a moved drawing on its bars or on its prices. Ctrl/Cmd-drag on a drawing leaves it in place and drags a copy that one undo removes, and Ctrl/Cmd held during a gesture inverts the magnet for that gesture without changing the toolbar setting. With an unlocked drawing selected, Left and Right move it by one bar and Up and Down by one price step (the instrument’s tick size, else one unit of its last price decimal), each press one undoable edit; with none selected the arrows pan as before. (#1365)

  • Selected icons, emoji and stickers show a square frame with four corner handles that resize them around the centre within the shared font size bounds, as one undoable drag. (#1401)

  • Fibonacci time zones, trend-based time, speed resistance fans, circles and speed resistance arcs draw saved, editable levels, each in its own colour, and share the Inputs level grid with retracements, extensions, channels, wedges and pitchforks: visibility, value, colour, a line style and width where the level has one, one colour for every level, and background opacity in percent. Wedges show their level colours and background, and PitchforkLevel::width sets each pitchfork level’s width. FibonacciConfig::show_prices, show_levels, levels_as_percent and labels_on_left choose whether labels show the price and the level, as a ratio or a percentage, and on which side they sit; labels are derived from the level value, and saved custom labels are kept. New drawings of the five tools start with their level tables (FibonacciConfig::for_tool); drawings saved without levels keep their fixed presentation, and wedges saved with levels now draw them in their saved colours. ChartView::y_to_price gives channel labels the price at their displayed end on every scale. Migration: FibonacciConfig literals add show_prices: None, show_levels: None, levels_as_percent: true and labels_on_left: false, or use ..Default::default(); PitchforkLevel literals add width: None to inherit the drawing width; ChartView literals add y_to_price, the inverse of price_to_y. (#1379)

  • FloatingSelectionToolbar::show_and_apply follows the selected drawing with the shared colour palette, fill or text colour where supported, line width and line style, applying each edit immediately with undo. The terminal and demo show the draggable toolbar beside the selection, keep it within the viewport, hide it while dialogs are open and offer settings, lock, delete and the drawing context menu in More. The drawing menus also offer Bring forward, Send backward and Copy; single-step moves cross exactly one neighbour even when layers are tied. (#1366)

  • The account panel loads older history from the broker. Scrolling to the end of Order History, its executions, Balance History or Trading Journal, or showing one empty, asks Broker::history for the entries before the oldest one listed, in a range that ends one second after it, then follows the page cursor until the broker has nothing older or the history lists 1,000 entries. An entry is listed once, whether a page or the live stream brings it first: orders are matched by id and other entries by value, each listed entry matching one entry of a page, so two equal fills stay two. Pages never replace working orders, positions or the account and raise no notification or sound, and an answer that arrives after the account changed or the stream restarted is dropped. A broker without history answers FeedError::NotSupported, which ends paging quietly; any other error is shown once and ends paging of that history until the broker connects again. (#1097)

  • strategies::Backtest, behind the new strategies feature, runs a strategies::Strategy over bars and returns a complete StrategyReport, so the report’s metrics, StrategyReportPanel and the CSV exports work on its output unchanged. A strategy computes what it needs from the whole run once in prepare, then decides on each closed bar in on_bar through a StrategyContext that shows only the bars up to that bar and the open position. It places named entries (market, limit, stop and stop-limit, long or short) and exits with a take profit, a stop loss or neither, and cancels them by name; an order placed with the id of a working order replaces it, keeping its original place among orders reached at the same point. Orders fill no earlier than the next bar, along its path from the open to the extreme nearer the open (the high first for ties within a few ulps), then the other extreme, then the close, at the order’s price or at the open after a gap, with the paper account’s fill rule; fill_on_close fills market orders at the close of the bar they were placed on instead. An exit fills whichever of its take profit and stop loss the path reaches first. It only reduces the position open when it is placed, or, placed while flat, the position the next entry opens, and is cancelled once that position is closed or reversed, as the paper account cancels its exits. An entry against an open position closes it before opening the other side. Each entry is a trade, closed first in first out with each partial exit its own trade, labelled with its entry and exit orders. Decimal closes and scaling out leave no dust trades. Flat positions and breakeven profits use positive zero, including in the trades CSV. The equity curve starts with the initial capital one interval before the first bar and marks the account at each bar’s close, stamped with the bar’s time. Bars with non-finite prices or with an open or close outside their high and low fill no orders and have no equity value. Fees, slippage, margin and pyramiding limits are not modelled. It needs no egui, so a server can run the same code. (#1151)

  • services::OrderFlowDetectors, behind the new headless detectors feature, is a ready-made Signals service that finds order-flow events in the events a host already pushes into the chart’s Sink: the host calls track with each Instrument (its tick size is required), push with each data::MarketEvent tagged with its symbol and feed time, and push_history with loaded trades, and connects the service with Chart::set_signal_source. Events of untracked symbols are ignored, untrack and reset drop a symbol’s state, trades with an id already seen are dropped, so the trade of an order execution counts once. Grouping uses the aggressor id on the first copy: push the execution before its tape copy or carry the id on the print. Depth and order events keep the symbol’s book with the Sink’s sequencing rules, a gap clearing it silently until the next snapshot. Every window runs on feed time, so replay gives the signals live data gave. Trade timestamps must be valid feed times: a far-future print can end zones at that time and block body or wick classification until reset. subscribe pushes the symbol’s most recent 5,000 detections, then each new one, removing evicted detections from live streams too, in one signal category per DetectionKind. DetectorSettings holds per detector (Detector) whether it is enabled, whether its live detections should alert and play a sound, and its rule; set_settings applies to later events and panics on a fixed threshold that is not positive and finite. The first detector finds big trades (BigTradeRule): fills sharing an explicit aggressor order id form one trade, aggregated in constant space and work per fill, large once its size reaches a Threshold, fixed or automatically the 99th percentile of the symbol’s last 10,000 trade sizes, recomputed every 100 trades and inactive until 1,000 have been seen. A large trade is marked at its first fill time and volume-weighted price, coloured by its aggressor side, labelled with its size and updated as its fills arrive, and projects a zone over its fill prices, at least one tick high, until a trade at or after its start lies strictly beyond its far side. The latest subscription chooses one interval per symbol for all its charts: intraday bars use the exchange time zone and regular session, daily and longer bars use UTC, and display time zone and extended hours do not apply. Once the bar of that interval that holds it closes, a trade is in the bar’s body or a wick, and body_zones and wick_zones choose which zones stay. Zones in a bar not seen from its open, under a trade-based interval, or first detected after their first fill’s bar closed stay without body or wick classification. (#1142, #1143)

  • The prelude exports HistoryPage and Subscription, so a host can implement Datafeed::history and subscribe with the prelude as its only import. (#1317)

  • TradingRules::pip_value gives the value of one pip for one unit in the account’s currency, and the order ticket shows it as Pip value for the order, taken from the broker’s rules or else from the instrument’s pip size times the point value, and left out when neither is known. Trading::set_instrument describes the other symbols of the account, so the account tables write their prices, and the order editor takes its decimals, from each row’s symbol instead of the chart’s decimals or two, and Trading::set_formatter takes a TradingFormatter whose price, quantity, spread and pip value text, per symbol, replaces the built-in text in the ticket, depth ladder and account tables. Rules with a non-positive pip value are rejected like other invalid rules. (#1125)

  • ChartBuilder::with_locale, with_time_formatter, with_price_formatter, with_percentage_formatter, with_volume_formatter, with_storage and with_study_factory install the chart’s locale, formatters, drawing storage and the study factory at construction, and ChartBuilder::build_restored builds the chart with them, then restores a ChartSnapshot through the factory, so restored studies and series see the host’s formatters and storage before the chart is first used. A snapshot that cannot be restored returns an error and no chart; the drawings that could not be read come back with the chart, and Chart::restored_series_id maps the saved series to the new ones for the host to bind its data again. (#1102)

  • ChartSnapshot saves the bar series added with Chart::add_series (ChartSnapshot::series: options, visibility, pane, markers, marker options and price lines) and the main series’ markers and price lines (main_annotations), and SavedLayout documents are version 3; versions 1 and 2 still load and leave the chart’s added series in place. Chart::restore replaces the added series with the saved ones, without bars and under new ids that Chart::restored_series_id maps from the saved ones, so the host binds its data again with set_data. Chart::snapshot_with and Chart::restore_with take an IndicatorFactory, as does StudyTemplate::create_with, so studies a host registers are saved and restored with their inputs, styles and links. Restore now checks before changing the chart that each study source names a saved study and a plot of it and that sources form no cycle, and that no series or study id repeats; a failing check leaves the chart as it was. Marker::color is saved with the marker, and PriceLine, SeriesOptions, SeriesStyle (without its autoscale function), MarkerOptions, MarkerZOrder and PriceLineSource are serializable. Migration: ChartSnapshot literals add series and main_annotations; a host that saves its own series metadata and adds the series again after restore now gets them twice from a new snapshot, and sets series to None before restoring to keep its handling. (#1058)

  • Profiles is a host service for profiles and follow relations: watch pushes ProfileEvents carrying Profile details and the host-reported follow state, and follow follows or unfollows a ProfileId, which the host may refuse. ProfileDirectory holds one account’s profiles, reports each request as FollowStatus::Pending or Failed through operation, repeats nothing on its own, and set_service drops the previous account’s profiles and requests and ignores its late answers. Notification::target takes a NotificationTarget::Profile or Room, which the notifications panel offers as an Open profile or Open room button and reports as NotificationsAction::OpenProfile or OpenRoom for the host to perform. ui::profile::ProfileCard embeds the latest profile name, bio, avatar and follower count in any layout, sends Follow and Unfollow through the directory, disables the control while pending and shows host failures with retry and dismissal. It keeps no account details of its own; an unknown or removed profile shows as unavailable. Removing or clearing profiles also invalidates their follow requests, so late answers cannot settle a newer request for the same identifier. Accounts, authorization and delivery stay with the host. (#1123)

  • Broker::history answers one page of finished history older than what connect pushed, through HistoryRequest (a HistoryKind of orders, executions, balance changes or journal lines, an optional UTC range, a cursor and a page size) and HistoryPage. Pages come newest first with a cursor to the one before, hold only finished orders, fills, balance changes and journal lines, never working orders or positions, and may repeat live entries unchanged so a consumer can drop duplicates, orders by id and other entries by value. The default answers FeedError::NotSupported, so existing brokers are unchanged. (#1097)

  • Storage can keep document revisions: load_versioned, save_versioned and watch have defaults that refuse or push nothing, so existing hosts are unchanged. A host that implements them makes the library write a document only over the revision it read; a write over a newer revision changes nothing, answers SaveOutcome::Conflict with the stored version and leaves the newest unsaved document in memory, never writing it until the user’s ConflictChoice takes effect: reload the stored version, save the unsaved one as <name> (local copy) (or <name> (local copy 2) and so on if that name is taken) and reload, or write over the stored version. SettingsStore reads a change another client made once nothing is unsaved and returns it from poll like the first read; while settings are unsaved it reads nothing, so their write is refused instead, and conflict is true until resolve_conflict applies the user’s choice. ui::dialogs::StorageConflictDialog asks for that choice, and the terminal shows it when its settings conflict and performs the answer as Action::StorageConflict. A new Storage for another account drops the old one’s pending answers and watch streams. (#1100)

  • Session::overrides holds SessionOverride entries, the regular and extended windows of one trading date, for early closes, exceptional openings and closures; an override with no windows closes its date. An override replaces the weekly windows and a listed holiday of its date, and the first of two overrides for a date applies. Windows are named by their closing day and may cross midnight, as weekly ones. Bar clocks, history and session boundaries, daily bar closes, the countdown, extended-hours shading and the studies that anchor on trading dates all read the hours through ExchangeSessionProvider, so they follow the overrides across daylight-saving changes. (#1127)

  • Alerts can test a value inside or outside an inclusive channel with AlertCondition::InsideChannel and OutsideChannel, which hold on every evaluation while the value is in that state, unlike entering and exiting. AlertFrequency::OncePerMinute allows one trigger per UTC clock minute. Alert::schedule holds an optional NotificationSchedule, a named time zone, weekdays and time windows, including windows that cross midnight and belong to the weekday they start on, and NotificationSchedule::allows tells whether a trigger time is inside it. The alert dialog edits the new conditions, the frequency and the schedule, rejects empty or malformed schedules, and presets keep them; Alerts documents the semantics for services, and AlertEngine evaluates the new conditions and frequency and calls on_trigger only for triggers the schedule allows. (#1047)

  • HistoryRequest, TradeRequest and DepthRequest carry an explicit range, since (inclusive) with the existing before (exclusive), alongside count. Chart::scroll_to_time bounds the pages it asks for by the target time. An empty HistoryPage, TradePage or DepthPage may name continue_before, where older data continues, so a weekend or other gap no longer ends history and the next request starts there instead of repeating; a continuation that does not lie before the request stops paging with FeedError::InvalidData. Charts page older trades into the held ones when the view reaches the oldest trade, while bubbles, a footprint or a study use them, merged by the existing id rules and retried and cancelled with the other requests, and study sources on other symbols follow continuations. FeedState::trade_history_complete and depth_history_complete report whether more can be loaded. Migration: HistoryPage is now #[non_exhaustive]; replace HistoryPage { bars, end_of_history } with HistoryPage::new(bars, end_of_history). (#1080)

  • Chart::set_conversion carries a host-chosen currency or unit through the feed: Datafeed::resolve_converted describes the symbol in it, and HistoryRequest, TradeRequest, DepthRequest and Subscription gain conversion, which also reaches the studies on other symbols. A changed choice drops the data held, discards replies and subscriptions of the previous choice and reloads, and the legend shows the resolved instrument’s currency and unit only once it arrives. A feed that cannot convert answers NotSupported (the default) and the chart shows no data instead of unconverted data. The library converts nothing. The request structs are #[non_exhaustive], so hosts that only read them need no change. (#1126)

  • services::Sharing lets a host share layouts and watchlists: offers reports per ShareKind whether link and copy are available, link answers a view-only ShareLink that says whether a recipient may save a copy, and copy saves a copy and answers its name. LayoutMenu::set_sharing and WatchlistPanel::set_sharing add Copy link and Save a copy rows only for what the host offers, disable them while an operation is pending, copy the link to the clipboard and show the reported copy policy, the saved name or the host’s rejection. A layout copy appears in the menu once re-listed from Storage; a watchlist copy is added to the panel’s lists. Accounts and cloud storage stay with the host. (#1099)

  • Datafeed::capabilities reports what a feed offers as a whole before any symbol resolves: FeedCapabilities lists its intervals, exchanges, symbol classes and optional FeedServices, each either unreported (None, which restricts nothing) or a list, where an empty list means none. The chart asks once when the feed attaches and Chart::feed_capabilities returns the answer. TimeframeSelector::set_feed_capabilities limits the interval choices to the feed’s, alongside a symbol’s own set_supported_timeframes, and SymbolSearchDialog::set_feed_capabilities takes the source menu’s exchanges and the category tabs from the feed. FeedCapabilities::offers tells a host whether to show the controls of a service. The default answers nothing, so existing feeds are unchanged. (#1098)

  • ChartMenus::series_click_price returns the price of the series menu’s last right-click, which SeriesContextMenuAction::CopyPrice does not carry. (#1214)

  • WatchlistPanel::show_wide draws the active list as a wide table with every WatchlistColumn::WIDE column and Earnings, Dividends and News tabs filled from the host’s WatchlistDetails; its view button returns WatchlistAction::CompactView, and AdvancedView asks for the wide view. The tabs list the rows of the selected symbol, or of every shown symbol while none is selected, and clicking a symbol selects it. Selection, sorting, the active list and the flag filter belong to the panel, so switching views keeps them. SymbolDetailsPanel gains Performance and Seasonality sections: take_market_requests returns a MarketDetailRequest for each section a symbol still lacks and marks it loading, and the host answers with set_period_returns (PeriodReturn) and set_seasonality (Seasonality, SeasonalityMonth); answers for another symbol are ignored. Every host-supplied section is a MarketDetail and says whether it is loading, empty, unavailable or failed. A host that never asks sees none of it. (#1056)

  • Watchlists duplicate, filter by flag and show more quote columns. The list menu duplicates the active list as “Name copy” (Watchlist::duplicate), keeping sections, symbol order and flags, and the Flagged symbols swatches show the symbols flagged one colour across every list, each once, so the red-flag view follows flag changes; a flag change or removal in that view applies to every list that flags the symbol that colour (WatchlistPanel::set_flag_filter, flag_filter); symbols then returns the flagged symbols so the quote subscription follows. WatchlistPanel::set_columns adds WatchlistColumn::Volume, ExtendedLast, ExtendedChange and ExtendedChangePercent, measured from the regular last price, which sort with missing figures last and show a dash when the quote lacks them; they follow the live quote stream. ChartMenus::set_watchlists adds a submenu to the chart menu that returns ContextMenuAction::AddToWatchlist { list, symbol }, applied with WatchlistPanel::add_symbol_to, which refuses a symbol the list already holds. WatchlistColumn is now #[non_exhaustive]. Migration: matches on WatchlistColumn add a wildcard arm. (#1055)

  • The order ticket offers its risk percent sizing for limit, stop and stop-limit entries, sized from the entry price with the same validation as a market entry. Orders from the depth ladder take the ticket’s enabled take profit and stop loss, priced from the ladder order’s own side, entry and quantity, and the confirmation lists them; an invalid exit refuses the order and says why. Capabilities::close, reverse and preview are reported independently: the Close and Flatten controls, the Reverse controls and the new Preview order button appear only when set, and the ladder’s disabled buttons explain why. Broker::preview answers an OrderPreview (cost, commission, margin and warnings) without placing the order; the ticket then confirms that exact request, and a refused preview shows an error. Migration: an account that closes and reverses positions through its market orders sets close and reverse, which PaperBroker now does; without them the Close, Flatten and Reverse controls are hidden. Broker implementations need no other change. (#1054)

  • The layout menu stars saved layouts and filters the list to the starred ones with a Favorites toggle, keeping the current layout selected. LayoutMenu::favorites holds the starred names, follows a rename, loses a deleted layout and is kept between sessions in the new UserSettings::layout_favorites; documents written before read with none. (#1051)

  • AlertsPanel orders its list by name, symbol or status, ignoring case, in either direction, with equal values in arrival order, and offers a Duplicate button that returns AlertPanelAction::DuplicateAlert with a copy that has no identifier and is active, for AlertDialog::edit. A Quick alert form creates price, study-output and volume alerts with the dialog’s condition editor and Alert::is_valid, starts on the symbol given to AlertsPanel::set_symbol, offers the outputs given to AlertsPanel::set_sources, and sends them through the connected Alerts service; a save or removal waiting for the service is shown, a failure keeps the form and its error, and the list changes only when the service pushes. (#1046)

  • The market heatmap shows a universe chosen from MarketHeatmapPanel::universes, sizes its tiles by one MarketHeatmapMetric and colours them by another, both chosen independently in the panel from the host’s metrics with their labels, units and availability, and draws a legend of the size metric and the colour scale. MarketHeatmapPanel::selection (MarketHeatmapSelection, also UserSettings::market_heatmap) holds the choices for settings restore; a chosen universe or metric the host does not offer or has no data for stays chosen and shows as unavailable. Migration: replace MarketHeatmapPanel::entries with universes, put the former value and change_percent of each MarketHeatmapEntry into values under the identifiers of two MarketHeatmapMetrics listed in metrics (the second may set saturation: Some(5.0) for the former fixed scale). (#1124)

  • The screener sends the market, a text description and a page offset in ScreenerQuery::universe, text and offset. ScreenerPanel::set_universes offers the host’s ScreenerUniverses (stocks, funds, bonds, coins, exchange pairs) in a selector; set_text_query adds a field whose description the feed interprets in the optional Datafeed::screen_text, answering the rows with an explanation (ScreenerTextAnswer) shown above them; a full answer offers Show more for the next page. set_storage lets the user save, rename, load and delete named screens in the new StoreKind::Screens, each holding its universe, column set, filters, sort order and description, so a restored screen sends the same request. The chosen criteria stay through loading, failures, paging and CSV export. (#1096)

  • Chats offers optional host operations, enabled through Chats::capabilities: find_users to choose recipients, create_room for direct, private and group rooms (NewChatRoom), and add_member and remove_member for rooms whose members the host pushes with ChatEvent::Members. Users and rooms keep the host’s stable identifiers (ChatUser). The chats panel header offers New chat and Members where the host allows them, shows each action while it is pending and when the host refuses it, keeps the form after a refusal, opens a created room once pushed, and clears the form, recipients and pending actions when ChatsPanel::set_service attaches another service. Accounts, authorization and delivery stay in the host. (#1094)

  • StrategyReport::summary_csv writes the summary metrics and run properties the report panel shows as a table with the columns section, name, value, unit and currency: money in the report’s currency, percentages as 100 for 100%, and an empty cell for an unavailable value. The panel’s new Export summary CSV button returns StrategyReportAction::ExportSummaryCsv { filename, content } beside the trades export. (#1121, #1157)

  • NewsQuery carries symbols, topics and providers, and the news panel offers them: NewsPanel::set_symbols adds symbols to the followed one, and set_topics and set_providers list the topic values and provider identifiers the feed supports. Every change sends the complete selection through Datafeed::news, a superseded reply is ignored, and the choices stay selected through loading, empty and failed states and while the host offers the same values again. Migration: read NewsQuery::symbols, empty for the whole market, instead of NewsQuery::symbol. (#1101)

  • The depth ladder’s View menu shows columns for the order count of each side, the observed size change of each side and the volume traded at the bid and the ask, independently, beside the resting size and the last account fill. The hover text uses the same values: a change is one observed between book snapshots, not confirmed execution or cancellation, and an order count the feed did not send is shown as unavailable. The price column’s profile is total volume, delta or bid and ask volume, summed over the retained trades, the trades since the open of the current exchange session, or the trades since a manual reset, which later live trades extend. (#1077)

  • Order flow studies sum the same executions three more ways, added like any indicator: Multi-Range Delta (OrderFlowKind::SizeDelta) gives the buy minus sell volume of three independent inclusive size ranges, Rolling Volume and Delta (FlowSum) sums the volume and the delta over a number of bars, drawn as histograms or lines, and Size-Filtered CVD (FilteredCvd) accumulates the delta of executions in a size range in its own pane. A bar without executions is a gap; a rolling sum over a gap or before its warm-up is a gap, and a cumulative sum carries over a gap. Trades of unknown side add to the volume but to no delta. Live updates, history merges and evictions follow the trade rate’s, and update recomputes only from the first changed bar. (#1078)

  • OrderFlowKind::AggressorRate gives the bar total and the rolling and instant rates per second of distinct explicit aggressor order ids, counting an order once however many fills it has and neither merging nor counting fills without an id. OrderFlowKind::LevelsExecuted counts the distinct prices that buy and sell executions printed at, per bar or over a rolling window, optionally restarting a side when its executions reverse; unlike LevelsTradedThrough it ignores quote movement, so cancellations add nothing. Both are Order flow studies (Aggressor Rate, Levels Executed) and follow history merges and evictions as the trade rate does. CombinedTrade::consumed lists the resting orders (ConsumedOrder: id, price, size) that an aggressive order’s retained fills took, summing to its size, and CombinedTrade::complete says whether its aggressor and every resting order are named. Time and sales shows that breakdown when hovering a fill with an aggressor order id. (#1072)

  • Trade profiles choose volume nodes through FootprintConfig::node_sensitivity (NodeSensitivity): smoothing averages each price row with that many rows on each side, and prominence is the smallest rise or drop against the neighbouring plateaus, as a share of the largest smoothed volume. Untraded prices count as zero volume, so a gap between traded prices is a valley, found as one span however wide. Rows of equal smoothed volume form one plateau, reported once at its lowest row. TradeProfile::nodes takes the sensitivity, whose default compares neighbouring rows as before. FootprintConfig::value_area_high and value_area_low draw the VAH and VAL guides on the outer edges of the shaded rows, each with its own Stroke or hidden with None. Migration: FootprintConfig literals add value_area_high, value_area_low and node_sensitivity, and TradeProfile::nodes callers pass NodeSensitivity::default(). (#1079)

  • Book size, the liquidity heatmap and the depth ladder count individual resting orders through one data::OrderFilter: a minimum order size applied before aggregation, a minimum resting age measured from the placement time the feed supplies, and excluded participants. RestingOrder::with_participant and with_placed carry that metadata, never inferred. OrderFlowStudy::with_order_filter (and the study’s Minimum order size and Minimum resting seconds inputs) filter book size, DepthHistoryConfig::orders samples the heatmap from the accepted orders instead of the aggregate prices, and Chart::set_order_book_view applies chart::overlays::OrderBookView to the heatmap’s profile and the ladder: the profile measures the total resting size or the largest known individual order at each price (BookProfile), and two OrderSizeTiers highlight prices whose largest known order is notable or large, in the profile and the ladder’s size cells. OrderQueue::filtered gives hosts the same summed book. With aggregate depth only, or when no order carries the participant or placement time the filter needs, book size has no value, the heatmap has no column, the ladder shows no sizes and the pane says so (OrderFilterUnavailable), rather than showing unfiltered sizes. Migration: DepthHistoryConfig literals add orders: None or use ..Default::default(); RestingOrder is #[non_exhaustive] and gains participant and placed. (#1073)

  • cargo bench --bench heatmap measures the liquidity heatmap of a book of 1,000 levels a side at a 50 ms column cadence: sink time per delta, frame time, texture upload, textures and heap, with the history filled to every resolution. docs/order-flow.md documents the configuration, the measured budget on a stated machine (a frame under 5 ms and 56 MB of heap) and the degradation policy. DepthHistory now shares its columns, so LiquidityHeatmap tells a changed column by identity instead of keeping a copy of every column and comparing each frame: for 1,000 levels a side and a full history its heap falls from 110 MB to 56 MB and its median frame from 9.8 ms to 2.1 ms. (#1112)

  • Footprint studies take a FootprintStudyConfig and report where each level stands. delta_percent and ratio mark bars whose absolute delta, as a share of all volume with unknown side included, or buy-to-sell volume ratio reaches a threshold (equality counts; a side with volume against none meets any ratio) as FootprintStudyKind::DeltaAsk, DeltaBid, RatioAsk and RatioBid, drawn as triangles above or below the bar. min_delta gives the delta POC a minimum absolute net delta, with ties still going to the lower price. UnfinishedAuction is replaced by UnfinishedHigh, marked when sell volume traded at the bar’s high, and UnfinishedLow, when buy volume traded at its low, even with the other side empty; both extend into later bars until a revisit, like stacks and naked POCs, and extend_bars expires any of them after that many later bars. diagonal false builds imbalance zones from the same price instead of the adjacent one. FootprintStudy::state is Local, Unvisited, Revisited or Expired, and render_footprint_studies dims revisited and expired levels. Migration: footprint_studies(flow, ratio, stack, cluster_share, single_print_max) becomes footprint_studies(flow, &FootprintStudyConfig { imbalance_ratio: ratio, stack, cluster_share: Some(share), single_print_max: Some(max), ..Default::default() }), where a share outside 0 to 1 or a maximum of zero is still off, UnfinishedAuction matches become UnfinishedHigh | UnfinishedLow, and FootprintStudy literals add state. (#1076)

  • Footprint cells offer more presentation choices through FootprintConfig. FootprintColor::Fixed fills every cell with the neutral colour and DeltaOpacity colours by the sign of the delta with opacity following its share of the bar’s largest; FootprintMode::DominantSide shows only the larger of the sell and buy volume, at the left or right of the cell. abbreviate writes 1.2K and 3.4M, show_zero false leaves zero volumes blank, and font_size sizes each row’s number by its volume between two limits held within 8 and 24 points, leaving out a number whose size exceeds its row’s height. extreme_ratio writes the ask/bid ratio above the highest and below the lowest row of each bar, or A/B n/a when the bid is zero, and pullback outlines the rows chosen by overlays::pullback_range: from the close to the extreme the bar left, none when it closed on that extreme. Executed totals are never changed, Footprint::level_of gives the level a price falls in, and FootprintConfig and its enums are serializable, with fields missing from older documents taking their defaults. Migration: FootprintConfig literals add the new fields or use ..Default::default(), and matches on FootprintMode and FootprintColor add the new variants. (#1075)

  • Volume bubbles take their grouping from VolumeBubblesConfig::grouping: BubbleGrouping::Automatic keeps one bubble per bar and price level, Ungrouped draws every execution at its own time and price, so fills of one instant and price stay separate circles, TimeWindow and Executions group by a window of time or a number of consecutive executions whatever the bar interval, and PriceStep sets the height of a level. Bubbles that do not sit on a bar’s centre are placed in its slot by their time; groups of executions keep their edges as the bounded trade store evicts the oldest trades. BubbleColor gains Split (a circle per side, sized by its own volume), AbsoluteDelta (the sign picks the side, the absolute delta sets the opacity against the largest visible one), DeltaPercent (the delta as a share of all volume, unknown side included) and Volume (one colour). VolumeBubblesConfig and its enums are serializable, and fields missing from older documents take their defaults. Migration: VolumeBubblesConfig::price_step: Some(step) becomes grouping: BubbleGrouping::PriceStep(step); None becomes BubbleGrouping::Automatic. (#1074)

  • services::AlertEngine, behind the new alert-engine feature, is an Alerts service that keeps alerts in memory and evaluates them on the bars the host feeds it through update(symbol, timeframe, bars, now, value), where value resolves study and drawing sources at a bar index. It needs no egui, so a server can run the same code. Crossings compare each value with the previous evaluation of the same alert and symbol, every rule is judged on the same bar, an update that changed nothing or whose newest bar is older than one already evaluated does nothing, so reloads, replay rewinds and timeframe switches never fire again, and tick(now) expires alerts without data. with_alerts and alerts restore and persist the list, and set_watchlist supplies the members of a watchlist alert. Alert::timeframe names the timeframe an alert is evaluated on; the engine fixes an alert that has none to the first timeframe it evaluates it on, and the demo fills it from the chart. Stored alerts load unchanged. (#1132)

  • Chart::alert_value(source, bar) returns the value an alert source has at a bar of the main series: the close for price, the volume for volume, the study output named by its series identifier in decimal, and the level of a drawing named as Drawing::alert_source does, so a chart can feed AlertEngine::update or any other evaluator. Chart::alert_sources lists every output of every study and every level of every completed drawing with the names the alert dialog shows, for AlertDialog::sources. Both need the drawings feature. The demo uses them instead of its own copies. (#1133)

  • Alert::expand_message fills {{symbol}}, {{timeframe}}, {{time}}, {{open}}, {{high}}, {{low}}, {{close}}, {{volume}}, {{value}} (the first source’s value) and {{output_N}} (output N of the first source’s study) from the evaluated bar; an unknown placeholder stays as written and a missing value becomes empty text. AlertEvent::TriggeredForSymbol::message carries the result, which AlertEngine fills on every trigger, and AlertEngine::on_trigger gives the host the alert and the event on each one, for email, push notifications or web requests. The alerts panel shows the message in the popup and the log, AlertTrigger::message keeps it and the CSV export gains a final message column. AlertsPanel::set_sound takes the user’s alert sound, or none when sound is off, and take_sound returns it after a poll that received a trigger, as Trading::take_execution_sound does for fills; the demo plays it from there. Migration: AlertEvent::TriggeredForSymbol literals and patterns add message (use String::new() or ..); AlertTrigger literals add message; readers of the CSV export expect five columns. (#1134)

  • The demo evaluates alerts with AlertEngine instead of its own copy of the rules, so it shows what a host gets from the crate. The bars of each symbol and timeframe its alerts watch, from the hidden monitors of live charts, are fed to the engine once a frame through Chart::alert_value, and a chart in replay is not fed, so no alert fires again on entering or leaving replay. tick runs every frame and the demo repaints at least once a second while an alert with an expiry is active. The demo keeps the alerts with its other session data, restoring them with with_alerts, and delivers trigger notifications through on_trigger. (#1136)

  • The volume profile studies take a Source interval input. A finer interval than the chart’s is requested from the host through Indicator::data_requests, and each finer bar is distributed over its own price rows in place of the chart bar’s high to low estimate, for the visible range, fixed range, session, periodic, anchored and auto anchored profiles alike. A chart bar without finer bars keeps the estimate so no volume is lost, a reply for another interval is dropped, and profile_inputs returns for each profile the share of its bars the finer data covers. The default, chart bars, is unchanged. A connected feed pages that finer history back only to the first chart bar of the profiles in view, through the new Indicator::data_start, which states the oldest time a study reads from each history it requests; the chart pages again when the view moves to earlier profiles and requests nothing when it moves later. The default, None, keeps paging to the chart’s first bar, as do all histories on price-based chart types, whose studies run on elements. The six volume profile studies state the first chart bar of their profiles in view, or the newest bar when none is in view. (#1087, #1440)

  • ChartPatterns::new(PatternFamily::Reversal), registered as Reversal Chart Patterns, finds cup and handle, inverted cup and handle, double and triple tops and bottoms, and head and shoulders and its inverse, on the same confirmed swing pivots, rules and formations() results as the continuation patterns. Tolerance, depth, handle pullback and length limits are study inputs and the rules are documented on ChartPatterns. A formation confirms on the first close beyond its neckline or rim from the bar its last pivot is known, so a neckline broken before then confirms on that bar, and no confirmation reads a later bar. Reversal formations draw only their neckline or breakout level. (#1085)

  • ChartPatterns::new(PatternFamily::Continuation), registered as Continuation Chart Patterns in the Patterns category, finds bull and bear flags and pennants, rectangles and ascending, descending and symmetrical triangles in the bars. Swing pivots confirm strength bars after the pivot; each formation’s pivots, boundary segments, direction and confirmation bar are returned by formations(), developing formations apart from confirmed ones, and a confirmed formation reads no bar after its confirmation bar. Strength, minimum and maximum length, tolerance, touches per boundary, pole size and a toggle per formation are study inputs, confirmations are marked and labelled, and boundaries are generated as drawings. The retained pivots, developing and confirmed formations are bounded. (#1084)

  • BollingerBands takes a basis, simple by default, through with_basis and the Basis MA type input: exponential, weighted, smoothed or volume weighted. It sets the middle band and the centre of both outer bands, while the deviation stays the population deviation about the window’s simple mean. BollingerBandsWidth adds Highest Expansion and Lowest Contraction outputs, the rolling highest and lowest width over lookbacks of 125 bars each by default, set through with_lookbacks and two inputs. A bar with a non-finite close is skipped in the width and its extrema, so later values equal those of the series without it. Migration: BollingerBandsWidth now has three lines instead of one, so colour lists of one entry keep only the width colour. (#1088)

  • ChartEvent::MarkClick { id, series, time } reports a primary click on a bar mark that has a Marker::id, through Chart::drain_events. The hit area is the one that shows the mark’s tooltip, so only visible marks respond; of overlapping marks the one painted on top is reported, and the click neither selects nor deselects a series or study. Drawing tools and the eraser take the click first. (#1106)

  • KineticScrollOptions::mouse continues a released mouse drag with the same damping, speed limits, minimum movement and cancellation as touch inertia, which enabled keeps controlling on its own. Migration: KineticScrollOptions literals add mouse: false or use defaults. (#1065)

  • The study catalogue lists Lunar Phases, which marks each new moon with an upward triangle at the low and each full moon with a downward triangle at the high of the bar whose interval holds it, the two styled and shown independently. studies::lunar_phases returns the new and full moons between two UTC instants for 1900 to 2100 from the algorithm of Meeus, chapter 49, converted with the ΔT polynomials of Espenak and Meeus; its times are within about a minute of the published almanac times. Marks depend only on the bar times, so paging history, scrolling or restoring a template never repeats or moves a phase. (#1120)

  • Woodies CCI columns show three stages by the run of CCI 14 values on one side of zero: a first value or a zero is neutral, two to five values are a transition, and six or more are established, in the columns colour above zero and the new Established down colour below it. Bars without a value are skipped and a zero ends the run. The established down, neutral and transition colours are study inputs, and a saved columns colour is kept. Columns were two-coloured by the five previous values before, so the bar that crosses zero after an established run is now neutral and the bars before an established run are no longer coloured by their sign. (#1118)

  • DrawingToolbar::show_floating lists the favorite tools in ToolbarState::favorites, so starring or unstarring one changes the strip at once, instead of six fixed tools. The strip can be dragged, ToolbarState::floating_pos holds where it was left, and its close button clears ToolbarState::floating_visible. CrosshairStyle::Magic and CursorType::Magic select a trail that follows the pointer while the primary button is held, which then does not pan the chart, and fades after release, without creating drawings; switching cursor drops the trail. Alt+Shift+R selects the rectangle tool by default, is listed in the shortcut help and is replaced by a rebinding in ShortcutMap. Migration: match arms over CrosshairStyle and CursorType add Magic; ToolbarState literals add the two floating fields. (#1052)

  • DrawingToolbar::show and show_with_action draw the favourite tools strip beside the toolbar and return a tool picked on it like one picked in the toolbar, so a host no longer has to place it; show_floating remains for hosts that position the strip themselves and draws nothing a second time in the same pass. A dotted grip at the strip’s leading edge drags it, kept on screen, and tool buttons click without moving it. A star button after the Hide menu shows and hides the strip, selected while it is shown, and starring a tool shows it again. A new ToolbarState starts with no favourites, so the strip appears with the first starred tool, and the strip no longer carries a magnet toggle or tool menu. UserSettings::drawing_favorites_hidden and drawing_favorites_pos keep the strip’s visibility and position with drawing_favorites, and the demo restores them. (#1194)

  • Ghost Feed projects candles along its clicked path: GhostFeedConfig::spacing sets the bars each candle spans, wick the extra wick as a fraction of its range, and GhostFeedConfig::candles returns the open, high, low and close of each, at most MAX_GHOST_CANDLES. They are drawn through the active time and price scales, rising ones filled and falling ones hollow in the translucent drawing colour, and follow path edits, copy and paste, undo, templates and saved drawings because they are built from the path and the stored config. The drawing dialog edits the spacing and wick; non-finite values are refused on save. Migration: Drawing literals add ghost_feed. (#1109)

  • Gann squares draw their grid, fan and arcs independently, each shown or hidden by GannConfig::show_grid, show_fan and show_arcs. fan_ratios and fan_direction (forward from the first anchor, reverse from the opposite corner or both) set the fan lines, and arc_ratios sets arcs around the first anchor as fractions of the side, cut at the square’s edge. They replace the fixed diagonals, cross lines, circles and degree markers, are edited in the drawing dialog, are checked for positive finite ratios, and are kept in templates, undo and saved drawings; older saved drawings take the defaults. Migration: GannConfig literals add the new fields or ..Default::default(). (#1110)

  • Four support and resistance studies join the catalogue. IntradayPivotPoints takes the levels of each block of an exchange trading session, of a chosen number of minutes from the session’s first bar, from the block before it in the same session. ProjectedPivotPoints draws, beyond the last bar, the levels the next period will use if the current one ended now, beside the confirmed lines of Pivot Points Standard. MissedPivots keeps the swing highs and lows that price has not returned to, confirmed right bars after their bar and revisited when a bar reaches them within a percentage tolerance, drawing each from its pivot to its revisit. KeyLevels clusters swing highs and lows within a percentage tolerance into levels of a minimum number of touches, drawing each and listing it with its contributing pivots in a table. Left and right pivot bars, tolerance, touches and source period are study inputs that persist with templates. (#1091)

  • Applied VWAP studies edit and persist their bands and event anchors through study inputs. “Bands” sets the number of bands, up to ten, and “Band n multiplier” each finite non-negative multiplier in the unit chosen by “Percentage bands”; new bands continue the sequence 1, 2, 3. “Event time zone” names the IANA zone or fixed offset in which “Events” and “Event n” write local times as YYYY-MM-DD HH:MM:SS; the event anchor mode applies them sorted and deduplicated, a skipped local time is rejected and a repeated one takes its first occurrence. Templates, copies and undo restore both, and ConfiguredStudy::apply_settings keeps the styles of existing plots and gives plots added or removed by an input the study’s own styles. InputKind::Text and InputValue::Text carry a single line of text a study parses itself, and the study settings dialog edits it. with_std_dev_bands and with_percentage_bands keep at most ten bands. Migration: code matching InputKind or InputValue adds a Text arm. (#1092)

  • TrendStrengthIndex plots the rolling Pearson correlation of the source price with bar position over its own period, from -1 to 1 in its own pane with a zero line, and is listed in the catalogue as “Trend Strength Index”. A bar has no value during warmup, when its window holds a missing price, or when the window’s prices are all equal; the latest value equals LinearRegressionChannel::correlation for the same period. (#1115)

  • PPO and PVO choose their short and long averages and their signal line independently as OscillatorAverage::Exponential or Simple through the “Oscillator MA” and “Signal MA” study inputs and with_averages. Both default to exponential, which keeps the former values; the choices persist with the study inputs, templates and snapshots, and changing either recomputes the history. A simple average is the mean of the last length defined values and is defined once that many exist, like the exponential one. (#1116)

  • Floating, held and tracking data readouts lead with the instrument’s symbol, and follow a change of instrument. The main series’ legend title row offers hide or show, settings and remove buttons that run the chart’s typed operations on SeriesId::MAIN, leaving studies and other series in place; settings arrive through Chart::take_indicator_settings_request as SeriesId::MAIN. A hidden main series keeps its dimmed title and buttons so it can be shown again, and the buttons are reachable with Tab. (#1063)

  • SeriesStyle::alerts (SeriesAlerts: visible, labels, color) holds how one series’ alert levels are drawn, and the series settings dialog edits it under Scales and lines, Alert levels, through SeriesSettings::alerts. The host passes labels and color to render_alert_levels for the alerts it resolves to the series and draws none while visible is unset. The main series’ choice is read and applied by Chart::series_settings and apply_series_settings, kept by ChartSnapshot::main_series_alerts (older layouts take the defaults) and by undo and redo, and another series’ choice is read and written through Chart::series_style and series_style_mut, which its options keep through undo. Migration: SeriesStyle, SeriesSettings and ChartSnapshot literals add the new field or use defaults. (#1128)

  • Chart::export_svg and Trading::export_svg write the frame of export_image as an SVG document of the options’ size: text stays text, fades keep their gradients and the frame’s textures, such as legend icons, are embedded as PNG. Host paint callbacks, host-bound textures without supplied pixels, rotated or underlined text and gradient strokes return an error that names them instead of being left out, and export_png likewise fails on host paint callbacks and host-bound textures without supplied pixels, such as a watermark image, that it used to leave out. ImageExportOptions::include_watermark (default on, as on screen) omits the symbol watermark and set_watermark text independently of the title and timestamp, in PNG, SVG and frame exports, and the export dialog offers it as a checkbox and ExportFormat::Svg to hosts that list it. Images now include the footprint, volume bubbles, order book and liquidity heatmap that the chart’s feed holds. Migration: ImageExportOptions literals inside egui-charts add include_watermark (the struct is non-exhaustive, so hosts are unaffected); match arms over ExportFormat add Svg. (#1050)

  • ImageExportOptions::textures holds the pixels of the textures a host binds itself, using linear filtering and edge clamping, so export_png and export_svg (and the Trading variants) draw images of them, such as a legend badge or watermark image from a user texture, instead of failing; a texture without an entry still fails with an error that names it. Invalid pixels and ids that collide with the offscreen frame return named errors; TextureId::User avoids those collisions. Supplied pixels also travel with ChartImage frames. SVG embeds each texture with its tint and opacity, so light-theme and toolbar icons export too. Chart::export_layout_image, export_layout_png and export_layout_svg capture a whole layout of library widgets: the closure draws the toolbars, panels and trading overlays around the chart it is given and shows it, and the frame, encoders, options, feed-backed order-flow visuals and errors are those of the chart image. (#1050)

  • Chart::data_table returns the cells of export_csv as a DataTable (headers, rows, and csv and tsv of chosen columns), and DataTableDialog lists them with a column menu, copy of the displayed columns as tab-separated text and a DataTableAction::Export carrying their CSV for the host to save. Only the visible rows are painted, so a long history stays smooth, missing values show as an en dash and stay empty in copied and exported text, and the table lists only loaded bars, the replay cutoff’s bars during replay and the source bars on price-based chart types. The chart context menu offers ContextMenuAction::OpenDataTable, which the host answers with DataTableDialog::open. The table rebuilds when the symbol, interval, bar count, first or last bar, replay cutoff or study list changes. Migration: match arms over ContextMenuAction add OpenDataTable. (#1093)

  • StudyEditor is a study source editing panel that embeds in any layout: it holds a document title and text, shows an unsaved-changes mark, lists host Diagnostics (Severity, message and byte span) and selects and scrolls to a span when its message is clicked. StudyEditorAction carries the open, save and apply requests with the title and text; the host answers with open_document, mark_saved, set_diagnostics and apply_result, and a rejected apply leaves the edits in place. The library does not own the study language, files or compilation. (#1057)

  • IdeasPanel is an ideas composer and feed that embeds in any layout: it edits a title, body and attach-chart choice for the symbol and interval set with set_context, lists Ideas and short posts (IdeaKind) with author, time, instrument and attachment, pages with add_page and IdeasAction::LoadMore, and emits Publish, Open and OpenChart intents. The host answers a publish with publish_succeeded (identifier and link) or publish_failed, which keeps the draft, and set_publishing and set_browsing hide the controls of a service the host does not offer. Accounts, storage and the network stay with the host. (#1095)

  • PriceAxisOptions::show_symbol_name and show_study_names, and the Scales and lines settings checkboxes of the same names, write the symbol or study name before its last value tag on the price scale, so equal values of different series stay apart. They are off by default, independent of the legend titles and the value visibility flags, and persist with the settings. Added series write their own name on their tags. Migration: PriceAxisOptions and ScalesAndLinesSettings literals add show_symbol_name: false and show_study_names: false or use defaults. (#1064)

  • Point and Figure builds from high/low input, as before, or from closes through ChartTypeParams::pnf_source and the series settings Symbol tab. The choice is part of the cached build, so a change rebuilds the columns, and it persists with the chart type parameters. Migration: ChartTypeParams literals add pnf_source: PriceBasedSource::HighLow or use ..Default::default(). (#1062)

  • The HLC area chart’s fill opacity and close line width are set through ChartTypeStyles::hlc_area and the series settings Symbol tab, and persist with the chart type parameters. Defaults keep the former look; opacities outside 0 to 1 are clamped and a non-positive width hides the line. Migration: ChartTypeStyles literals add hlc_area: HlcAreaStyle::default() or use ..Default::default(). (#1103)

  • A star on each chart type menu row adds the type to the favourites or removes it. The toolbar then shows a button for each favourite in menu order, the last selected non-favourite and a menu chevron, with the same rules as the interval buttons. A new selector has no favourites. ChartTypeSelector::preferences and set_preferences exchange serializable ChartTypePreferences for host user settings, and ChartTypeAction::ToggleFavorite reports a toggle; the demo saves and restores them through application storage. (#1042)

  • The documentation status page shows feature completion by area from the maintained feature list, as a feature map coloured by status and one table per area. The same build produces per-area status badges and the feature map image for embedding. (#1129)

  • Terminal of the egui-charts-terminal package in terminal/ assembles the top toolbar, the chart context menus and one or more chart slots in a ChartLayout on the host’s Datafeed, and performs their actions: chart type, undo and redo across the whole chart history, the light and dark theme (following the system appearance until the user chooses one, on every slot) and fullscreen. Terminal::show performs what the controls emitted in that frame, in order, and returns the actions the host intercepted through with_intercept, the Host entries of the toolbar and menus, and every action the terminal has no default for; Terminal::run performs an action whatever the intercept says, waiting for the first frame when called before it. Action wraps each component’s own action enum unchanged. Services are passed as Arc<dyn Trait> (with_storage, with_marks, repeatable with_signals, with_symbol_search, with_alerts, repeatable with_broker, with_quotes, with_notifications, with_chats) and files and sounds as callbacks (with_file_export, with_sounds); with with_storage the theme, symbol and interval persist through SettingsStore. Controls of features the terminal does not perform yet stay hidden, and hide hides any other. terminal/examples/terminal.rs runs it on the synthetic feed. The package uses only the library’s public API and is not published. (#205)

  • Terminal performs the indicator dialog, which also lists the metrics the feed offers, and indicator settings, chart settings from the top toolbar, the chart and series menus, a double click on the main series and the price axis, symbol search when the host passes with_symbol_search, the keyboard shortcuts dialog and the study menu’s host entries (add a study from a study, add to favourites, copy, settings). Starred studies are saved with UserSettings::indicator_favorites, settings the chart rejects leave the previous ones in place and are reported, and the series menu’s Copy price copies the clicked price at the instrument’s precision. (#205)

  • Chart::set_study_limit caps the studies a chart takes from the interface, with Chart::study_limit to read it and Chart::try_add_indicator, which refuses a study beyond the cap with an error. Pasting a copied study respects it, add_indicator does not, and IndicatorDialog::set_full makes the dialog say so and add nothing. Hosts call terminal.chart_mut().set_study_limit(Some(n)). (#205)

  • Terminal shows the drawing toolbar beside the chart and keeps it in step with the active chart every frame, and performs its actions, the drawing menu, the drawing properties dialog’s Delete and Clone, and the object tree’s actions as undoable chart edits; zoom stays outside undo, and a colour dragged in the object tree ends as one step when the pointer is released. The object tree and the data window open in the side panel from the rail’s Object Tree icon and from the chart and study menus, and the data window reads the hovered bar. Pasted drawing text is added through the chart’s drawing clipboard. The per-tool drawing defaults saved from the properties dialog persist in UserSettings::drawing_defaults. Hide all and lock all drawings set the state the toolbar shows instead of toggling the drawings’ current state. (#205)

  • Chart::set_signal_sources connects several Signals services to one chart, each with its own stream, so that a Clear or a lagged stream of one source leaves the signals of the others. set_signal_source remains for a single source. (#205)

  • UserSettings keeps indicator and interval favourites, drawing tool defaults, watchlists and the replay session to resume; documents written before read with their defaults. (#205)

  • ElliottWave (“Elliott Wave”, Support and resistance) finds five-wave impulses in confirmed swing pivots under the supported rules: wave 2 stays above the start of wave 1, wave 3 passes the end of wave 1, wave 4 does not overlap wave 1 and wave 3 is not the shortest of waves 1, 3 and 5, mirrored for bearish impulses. A construction is developing from wave 3, with its wave number as the label of the latest anchor, and is invalidated by a close beyond the end of wave 1 or by a later pivot that breaks a rule. It is confirmed on the bar that confirms its fifth anchor, and confirmed constructions never change. The table lists the developing construction and the last history confirmed ones with the price of every anchor and the confirmation time. (#1117)

  • RisingWedge and FallingWedge (“Rising Wedge” and “Falling Wedge”, Support and resistance) detect converging trendlines through confirmed swing pivots. The latest touches pivot highs and lows must keep the wedge’s direction, the lines must converge by at least convergence percent and the anchors span at most max_bars bars. The developing lines are output on every bar until the close leaves the wedge: below the lower line of a rising wedge or above the upper line of a falling one confirms it, the other side or the lines meeting ends it. The table lists the developing wedge and the last history confirmed ones with their anchor and confirmation times. A found or confirmed wedge does not change with later bars, and a confirmed wedge consumes its pivots. (#1086)

  • AdxBreakout (“ADX Breakout”, Trend), KnoxvilleDivergence (“Knoxville Divergence”, Momentum) and Reversal (“Reversal”, Support and resistance) add signal studies with separate upward and downward outputs, editable periods and thresholds, and documented rules. ADX Breakout marks a close beyond the high or low of the last range bars after an ADX at or below the threshold. Knoxville Divergence compares consecutive price pivots with the momentum at them, gated by an oversold or overbought RSI, and marks the confirmation bar of the second pivot. Reversal marks a new extreme of the lookback that closes beyond the previous close. Each signal is final on the bar that shows it and does not depend on later bars. (#1090)

  • Ratio, Spread and Correlation (“Ratio”, “Spread” and “Correlation Coefficient”, Statistics) combine two series, each a price source of the chart symbol or of a host-supplied symbol at the chart’s interval, chosen by the symbol_0, source_0, symbol_1 and source_1 inputs. Series align to chart bars by interval; a bar where either has no bar or a non-finite value has no output, and nothing is carried forward or taken from the chart in its place. The correlation is the Pearson correlation of the last length values, or of log returns with the log_returns input, and has no value while its window holds a missing bar. A zero ratio denominator, a non-positive price in the log-return mode and a series constant over the window are unavailable. Hosts supply the histories through Chart::study_data_requests and set_study_data; no market data service is included. (#1081)

  • TechnicalRatings (“Technical Ratings”, Momentum) scores the buy, sell and neutral votes of simple and exponential moving averages of three lengths and of the RSI, Stochastic, CCI, MACD and Momentum from -1 to 1 as separate moving-average, oscillator and summary outputs, each with its coverage, the share of enabled components that had a vote. A component in its warm-up or on a bar with a non-finite high, low or close has no vote, so it leaves the mean and lowers the coverage. Every component, its period and the toggles for the averages and oscillators are study inputs. The table shows the latest score, its Strong Buy, Buy, Neutral, Sell or Strong Sell rating at the thresholds of 0.5 and 0.1 and the coverage of each group. (#1119)

  • Trading settings persist line extension, left, centre or right label placement, and whether Trading::export_image and export_png include visible trading overlays. Migration: TradingSettings literals add extend_lines: true, label_alignment: TradingLabelAlignment::Right and include_in_image: false, or use defaults; TradingLineOptions literals add extend_lines and label_alignment. (#994)

  • The snapshot menu offers Download image, Copy image and Open in new tab. Hosts with publishing enable TopToolbarState::can_publish_image and handle Copy link, Post image and Publish through their service. The demo copies images or opens them in a browser tab or native viewer. Migration: TopToolbarState literals add can_publish_image: false or use defaults. (#1006)

  • The save menu offers Save layout, Download chart data, Create new layout and Open layout as 32-point rows, retaining rename, save-as, image export and autosave. The demo routes data download and layout opening through its existing handlers. Save and snapshot menus scroll in short windows. (#1005)

  • The object tree creates named folders from selected drawings, nests folders and moves selected drawings between folders or back to the root. Folder visibility and locking apply to all descendants as one undoable edit. Drawing folder paths persist with drawing identities, independently of host groups; hosts retain empty folders through ObjectTreeState::folders. Migration: Drawing and SourceItem literals add folder: Vec::new(); ObjectTreeState literals use ..Default::default() for its folder and rendered-order state; copy Drawing::folder into live drawing rows. Older saved drawings start at the root. (#978)

  • Scales and lines settings expose currency and unit headers, scale-mode and price-action visibility, a numeric price-to-bar ratio lock, label overlap policy, and symbol, study and extended-session value colours and visibility. Units come from host metadata without converting data. (#993)

  • Alert settings filter active levels and set trigger notification lifetime. Inactive levels can be shown dimmed; the existing local sound controls apply the selected volume. (#995)

  • Event settings independently show earnings badges and dashed earnings breaks, news badges and host news notifications, and supplied ideas. The demo delivers enabled headlines through its notification service and suppresses repeated requests while they remain in its recent log. Economic-event visibility is preserved. (#996)

  • Symbol settings independently hide candle bodies, borders and wicks, colour candles by the previous close, and request dividend-adjusted history from the host. Candle borders draw inside the body; older saved settings retain borderless defaults. Status line settings show the supplied logo and last day change and set the study legend backdrop opacity, including studies in separate panes. Zero opacity hides the backdrop. (#992)

  • Alert expiry uses separate date and 24-hour time fields in AlertDialog::timezone (UTC by default), with a No expiry choice. Invalid or past times block saving; skipped local times are rejected and newly entered repeated times use their first occurrence. (#981)

  • ChartType::VolumeFootprint and ChartType::SessionVolumeProfile draw the bid and ask volume at each price of every bar, and the volume at each price of every session of the visible bars with its point of control, value area and developing point of control. Both are summed from the trades the feed sends and keep up with them while it streams. They need a time-based interval and the instrument’s tick size; unsupported intervals and bars before the first held trade draw as candles, and the session profile needs the studies feature. The chart type menu lists them around Time Price Opportunity, followed by Heikin Ashi, Renko, Line break, Kagi, Point & Figure and Range, with 13 point gaps between its groups. The demo drops its synthetic footprint and trade profile menu items, which paused the feed, for the chart types. (#967)

  • The broker picker’s compare button shows brokers side by side, two at first, with an Add broker control for other offered brokers and a Connect button under each. BrokerTile::facts supplies their rows, such as pricing, leverage and features, as BrokerFact::Value or BrokerFact::Supported. Each label gets one row across the brokers; a broker without it shows a dash read as not available, unlike the cross of an unsupported feature. The demo gives its brokers example facts. (#1003)

  • ui::financials::FinancialsPanel shows a company’s host-supplied CompanyFinancials in place of the chart: a pill per FinancialPage, a column chart of the chosen row over the page’s periods and the table of all its rows, with a Back to chart button, and a message when the host has no figures. The symbol details panel’s More menu offers Financials, which SymbolDetailsPanel::take_financials_request reports. The demo opens synthetic statements and statistics for its stocks. (#1002)

  • Symbol search validates arithmetic expressions such as AAPL-MSFT, reports invalid symbols and syntax, and returns a synthetic instrument. services::SymbolExpression evaluates expressions and aligns component histories by timestamp; the demo charts spreads in their own panes. (#976)

  • Symbol search offers an exchange source menu through SymbolSearchDialog::set_sources and expands instruments sharing Instrument::root. Results and recents retain separate exchange listings, and selection returns the exact instrument. The demo includes two futures expiries for drilldown. (#975)

  • Compare lists recent symbols through CompareSymbolsDialog::set_storage, including with a local catalog. Aligned 56-point rows show host marks, descriptions, type badges and optional Instrument::country. Rows offer Same % scale, New price scale and New pane, with an Add menu in narrow windows. Migration: match CompareAction::AddSymbol(symbol, placement); ComparePlacement::SamePercentScale preserves the former behaviour. (#999, #962)

  • The indicator templates menu has Indicators and Templates pages for one-click study additions and saved-template application. Hosts supply starred studies through TopToolbar::favorite_indicators and handle TopToolbarAction::AddIndicator. Save indicator template remains available, and empty pages explain how to fill them. (#1004)

  • Alt+Shift+Left and Home navigate to the first bar; Alt+Shift+Right and End return to the latest, preserving zoom. Period, Alt+D and Alt+Shift+E request Open layout, Data window and session switching through ShortcutMap; text fields keep their keys. The demo scrolls its saved-layout chooser and toggles SAMPLE between regular and extended hours, including from its initial 24/7 session. Continuous markets retain their session. (#983)

  • The drawing bar’s text group and the demo command search offer the image, post and idea drawings in a content section. Placing or double-clicking one opens an editor for its content, kept in the drawing’s text: an image drawing shows the picture at that address, fitted inside its frame, through the image loaders the host installs, with an empty, loading or failed state instead of sample art, and the post and idea cards show the supplied author or title on the first line and the text after it, growing to fit. The demo installs the PNG and JPEG file loaders. (#985)

  • The table drawing is offered with the text and note tools and in the demo command search. Placing or double-clicking a table opens a cell editor that adds and removes rows and columns; the cells are saved in the drawing’s text, one row per line and one tab-separated cell per column, and the table paints them with its first row as the header and each column as wide as its widest cell, instead of fixed sample cells. (#984)

  • The drawing bar’s projection group and the demo command search offer the ghost feed tool, which places and edits its path through the existing multi-point anchors. (#986)

  • The drawing context menu and the object tree row menu move a drawing to the price pane or another existing pane with Chart::move_drawing_to_pane, as one undoable edit that keeps its anchors and style; Chart::drawing_pane reports the pane drawing it and SourceItem::with_panes lists the choices of a tree row. Migration: SourceItem literals add panes: Vec::new(). (#977)

  • The drawing context menu offers an alert on the price crossing a drawing with price levels, and FloatingSelectionToolbar::set_alert_available adds an Add alert button. Drawing::alert_levels evaluates a line, a horizontal level, a rectangle’s top and bottom, a position’s entry, target and stop and each visible Fibonacci retracement or extension level at a bar; Drawing::alert_source and alert_level name a level by the drawing’s stored identity, so alerts keep their level after a save and restore. The demo lists every level as an alert source and evaluates them from the current drawing geometry. (#980)

  • Interval entries can be hidden and restored from the menu without changing the selected interval. Hidden entries are unpinned and persist through host-owned TimeframePreferences, including across source changes. Migration: TimeframePreferences literals add hidden_timeframes: Vec::new() or use ..Default::default(); older saved preferences default to no hidden entries. (#974)

  • Chart::set_bar_limit optionally keeps only the newest bars of each series, including feed history, streaming ticks and retained replay history. The default remains unlimited. remove_oldest_bars returns evicted bars explicitly. Replay eviction also drops the matching finer-source slots. Studies restart their warm-up on the retained window, drawings keep their timestamps and the viewport keeps its time position where possible. Full windows pause feed scroll-back until the limit is raised or cleared; markers, raw trades and host data retain their independent lifetimes. (#945)

  • Chart::forget_symbol releases an inactive symbol’s drawings, markers and storage reader without deleting host storage. Pending local storage edits must finish first. Symbol changes no longer cache empty drawing managers, marker lists or inactive empty storage readers; pending drawing sync notifications are retained. (#949)

  • The demo quick search runs a sample backtest on completed synthetic bars, marks equity at their closes and opens the strategy report below the chart. Reports can be replaced or cleared; selecting a trade restores its symbol and interval, scrolls to its bars and highlights its span. Entry and exit markers share the signals service with the API samples, including in newly added chart slots. Trades CSV is saved or downloaded by the host. Strategy execution, market data and storage remain host-owned. (#225)

  • The documentation site at /egui-charts/docs/ brings installation, first-chart and feature guides together with the all-feature Rust API reference at /egui-charts/docs/api/. Existing guides are included directly, Rust samples compile in CI, and the searchable guide follows system light/dark preferences with responsive navigation, installation steps and feature choices. The demo URLs are unchanged. (#929)

  • Study menus publish source preselection through Chart::take_indicator_source_request, read alert values from displayed price-based elements, and pin studies and overlay volume to shared right, left, additional or hidden scales with StudyScale::Shared. Shared groups keep their pane’s units and participate in scale fitting. Interval ranges also apply to custom durations and trade-count families through StudyIntervalRange. Migration: exhaustive StudyScale matches handle Shared; StudySettings literals add interval_range: Default::default(), while older saved settings retain their exact hidden intervals. IndicatorDialog::open_for_chart offers price fields and chart study outputs as sources, with optional preselection for adding a study on another study. Added studies retain their source and edited parameters; unavailable outputs are rejected and studies without a source input cannot silently ignore a preselection. Host-supplied source inputs keep their own validation, and rejected inputs show an error without closing the dialog. Long source captions truncate within the configuration panel. Favorites appear first in each matching indicator list. The demo passes chart sources through toolbar, shortcut and study-menu opens. The Add control stays reachable in narrow windows. The demo routes study actions to its alert service, clipboard and selected object-tree row. (#850)

  • Primitive::draw_merged receives the chart’s physical-pixel merge factor and PrimitiveView::point_groups supplies aligned source ranges for custom aggregation, with no groups for empty views; existing renderers keep their draw behavior. Hovered added series and mixed study/series panes follow hovered_series_on_top with timestamp-aware hit testing and visual ordering. Cached merge groups also supply exact visible price ranges without scanning every bar each frame. The demo saves encoded PNG bytes directly, with optional crosshair inclusion. (#834)

  • Chart::set_volume_formatter formats volume readouts, widget-only volume axis tags and volume-formatted studies; set_series_formatter overrides one bar series’ raw prices while relative scales keep the percentage formatter. Chart price and percentage hooks also reach OHLC legends and tooltips, and image exports retain the hooks. Indicator::set_value_formatter lets configured studies retain host formatting. Migration: Legend literals add formatters: ValueFormatters::default() or use Legend::new; StudyValue literals add formatted: None; render_tooltip_with_options takes ValueFormatters::default() as its final argument for the existing formatting. Hosts supply numeric separators and currency conventions through their formatters. (#203)

  • Pointer events include hidden added series and their payloads. Unchanged whitespace slots emit no repeated move events, while changes to their host payloads remain observable. Chart::set_pointer_kind lets host input integrations identify pens, which egui does not distinguish from touch. None restores automatic mouse/touch detection. The demo API samples render a host legend and its tooltip from the saved event alone. (#829)

  • ui::strategy_report::StrategyReportPanel renders a replaceable host report with summary metrics, equity and drawdown curves, a virtualized trade list and run properties. It returns original-index trade selection intents and valid-trade CSV for the host, and draws no controls without a report. Fill prices and timestamps retain their precision; undefined metrics and overflowing percentages display as N/A. StrategyPerformance adds largest winning/losing trades and consecutive win/loss runs in exit order; StrategyReport::comparison computes fee-free buy-and-hold and bar-resolution MAE/MFE from host source bars, counting invalid input. equity_curve shares curve validation with the view. The backtesting example opens the standalone report with ui and retains its headless workflow. Chart navigation and terminal mounting remain host integration work. (#225)

  • localization::set_translator installs a host-owned UI text lookup for one egui context; clear_translator restores English. Toolbars, menus, dialogs, panels, shared controls and accessibility names resolve text before layout, including when the language changes while a dialog is open. Missing translations retain the crate’s existing English text. Searches accept translated labels and original English names. localization::text shares the lookup with host controls, and format_text substitutes named message values after translation without interpreting braces inside those values. Hosts supply other languages and fonts; chart date and number formatters remain independent. (#204)

  • Standalone examples cover custom studies, timestamped drawing save/load, a host-run backtest, host script evaluation and UTC chart synchronization across intervals. The historical examples share one generated OHLCV helper, and existing CI checks compile every declared example. The demo retains its execution-based history. Data feeds, durable storage, strategy execution and scripting runtimes remain host-owned. (#249)

  • docs.rs builds all features and labels optional modules with their feature requirements. The builder guide is published in rustdoc and covers history, streaming, custom studies, drawing persistence, chart synchronization and host strategy and script integration. Study descriptions appear on their public types, and missing documentation is linted in studies, drawings, widget and ext. (#248)

  • A compact frame_time --regression <scenario> suite covers three history sizes, smoothed candles, tick and new-bar frames with and without studies, batch study calculation and 500 drawings. Pull-request CI compares Cachegrind instruction deltas against the same workloads compiled with the base revision and rejects growth above 5%, subtracting setup and warm-up. The existing bare-chart check and baseline are unchanged. (#246)

  • Datafeed::options_volume optionally streams complete call/put contract-volume snapshots at each strike for an underlying and an inclusive expiry range. Existing feeds supply none by default. OptionsVolumeProfile::new subscribes explicitly with a host repaint callback and draws the figures on the price pane, calls and puts in separate colours, with lengths relative to the largest combined row total. Rows are centered on strike multiples of the chosen price height; coarser rows sum nearby strikes without spreading their volume. Snapshots replace earlier totals, empty snapshots clear the profile, and dropping the last study clone deactivates its sink. VolumeProfile::from_options exposes the same grouping for host calculations, with calls in up() and puts in down(). The demo’s “Options volume profile” quick-search action connects a live synthetic options feed. Options data and expiry selection remain host-owned; recreate the study to change its query. Profiles hide when chart metadata names another underlying; the demo retains options queries across symbol changes. (#550)

  • Datafeed::metrics, metric_history and subscribe_metric expose host-published instrument metrics with names, units and value formats; existing feeds offer none by default. MetricStudy draws each series in its own pane, holding the latest point at or before each chart bar without looking ahead, and its output can feed another study. Live corrections refresh both the metric and its consumers through the existing study subscription path. IndicatorDialog::set_metric_source lists the current instrument’s metrics and ignores old replies after a source change. The demo supplies synthetic five-minute open interest; external metrics remain host-owned. Migration: StudyDataRequest literals add metric: None for price histories or the host’s metric key for metric histories; saved requests default to price histories. Direct hosts convert MetricPoint into Bar for Chart::set_study_data. (#547)

  • studies::helpers exposes scalar-series simple, exponential (first-value and SMA-seeded), Wilder and weighted averages, rolling sum, highest, lowest, population standard deviation, change and crossing tests. studies::Stepper lets custom studies resume after a changed last bar or appended bars, including without the studies feature. Built-in studies share these definitions while retaining their seeding and reference outputs; the driver example checks both update cases against a fresh calculation. (#545)

  • data::ReplayClock merges trades, quotes and depth for multiple symbols by timestamp and sequence, advances at a host-selected speed and seeks depth from periodic snapshots. ReplayEvent::push_to uses the live feed path; Sink::reset_replay clears future bars, order flow, streaming study values and their heartbeat on rewind. RecordingWriter and RecordingReader persist compact versioned binary events through host-owned streams, preserving nanosecond times, ids and conditions. See docs/order-flow-replay.md for routing, recording and seek integration. (#240)

  • Trade-based Timeframe::Volume, Range and Delta intervals build bars directly from executions and appear in the interval menu, subject to the source interval list. Volume and absolute signed delta split fills exactly at the threshold; raw fills stay intact. Typed interval changes also update the demo interval button. Range is measured in instrument ticks and closes on the first real fill reaching it, with possible overshoot across skipped prices. Parse 100v, 10r or 100delta; trade-based bars keep exact opening times and have no countdown or time-based resampling. Migration: exhaustive Timeframe and TimeframeUnit matches handle the new variants. (#239)

  • Sink::push_order_snapshot and push_order_event accept sequenced resting orders, modifications, cancellations and executions. Chart::order_queue exposes queue priority, the largest order at a price and levels filtered by minimum order size; the usual aggregated book and depth history continue to work. Known execution trades carry Tick::resting_order_id. Gaps, invalid events and the 10,000-order per-side limit require a fresh snapshot, with bounded buffering during resync. (#555)

  • Datafeed::depth_history optionally pages recorded depth through DepthRequest and DepthPage. Charts with a depth history load past columns and request older pages when visible time reaches the oldest depth column, preserve live columns on overlap, retain time gaps and stop at the end of history or when a page adds no older column. Depth times whose cadence boundary exceeds the nanosecond range are rejected without overflowing. Feeds without recorded depth keep their existing behaviour. (#554)

  • Tick::with_aggressor_order_id identifies fills of one aggressive order. Chart::combined_trades and data::combine_trades expose their retained size, first and last prices, volume-weighted price and fill count; fills without an id stay separate, and raw trades continue to feed per-price volume. (#553)

  • The factory adds “Quoted Spread” (last, arithmetic mean and maximum in instrument ticks), “Book Size” (last synchronized bid/ask sizes and their difference over a level count or price distance), “Trade Rate” (bar total, rolling and instant rates for execution count or volume) and “Levels Traded Through” (absolute bid/ask movement in ticks, per bar or rolling seconds). Each has a separate pane. Indicator::order_flow_input connects their bounded OrderFlowInput before quotes and depth are coalesced; executions use the feed’s deduplicated historical/live join. Missing streams stay missing, book loss clears its current values and breaks the movement path, and heartbeats expire idle rates. Hosts can also push events through the input handle. Changed aggregation inputs start a new source; charts replay retained executions for newly added rates without resetting other live sources or their idle clock. Clearing a source or evicting its oldest bar also clears earlier cached plot values. Shared sources receive each event once. Heartbeats expire rates after queued trades are merged and expire rolling inside-market movement without consuming event capacity; newly attached rates keep that idle clock. See order-flow integration for definitions and retention limits. Order counts require host-side fill grouping using explicit aggressor order ids; Trade Rate counts raw executions. (#552)

  • studies::{TradeProfileRanges, trade_profiles} builds bid/ask and delta profiles from exact footprint rows over host-supplied session ranges. Profiles retain unknown volume, developing POC, value area and local high/low volume nodes. chart::overlays::render_trade_profiles draws them on the price pane, and ui::trade_profile_menu merges neighbouring profiles or splits one at a selected bar boundary. The footprint demo exposes these commands for the last clicked bar and its profile. Session boundaries and historical/streaming trades remain host-owned. (#241)

  • Chart::set_liquidity_heatmap draws retained texture tiles from the feed’s DepthHistory, with logarithmic per-column contrast, sampled bid/ask paths and a current-book size column. New or changed columns use partial uploads; expired columns release their slots and tiles stay within the backend’s texture limit. The demo menu enables it with execution bubbles. HeatmapStrip::add_cell now normalizes its cells and volume_weighted uses volume for gradient intensity or solid opacity, and solid cells without delta stay transparent. (#235)

  • VisibleAveragePrice (“Visible Average Price”) averages the selected price source, close by default, over the visible bars and follows pan, zoom and resize before the price scale is fitted. Indicator::set_visible_range supplies the end-exclusive source range and is forwarded by configured studies. UpDownVolume (“Up/Down Volume”) sums host-supplied intrabar volume by candle direction, using the previous intrabar close for dojis, with up volume above zero, down volume below and a delta marker coloured by the prevailing direction. The study declares intrabars through Indicator::data_requests and consumes update_data; connected feeds load and subscribe automatically, while hosts supplying bars directly use Chart::study_data_requests and set_study_data. Missing histories stay unavailable. Subsecond and tick-count charts have no lower-timeframe request. The library does not fetch a market data feed. (#176)

  • Seasonality adds its yearly monthly-change heatmap, including the developing month and the monthly average, population standard deviation and positive percentage. Its final projection reaches the next month boundary in future whitespace through Indicator::projections and StudyProjection, with fractional time-axis endpoints so missing dates do not lengthen the box. Projected bands participate in selection and autoscaling, including future whitespace. Projection statistics still use earlier years only. Configured studies forward both tables and projections. (#176)

  • Performance shows percentage changes over one week, one, three and six months, year to date and one year in a labelled table on the chart. A period’s starting close is the last finite close on or before the target trading date in the instrument’s calendar, clamping shorter months to their last day; insufficient history or a zero starting close displays N/A. On an interval shorter than a day it declares the chart symbol’s daily bars in Indicator::data_requests, which a connected feed answers and other hosts supply with Chart::set_study_data, so the longer periods fill without scrolling back. A period then starts from the later of the last daily close and the chart’s own last close on or before the target date, the daily one on the same date, so daily history that stops early or has gaps falls back to the chart’s bars. Daily and longer charts, and hosts that supply no daily bars, use the chart’s loaded bars, and daily bars out of time order count as not supplied. Indicator::table supplies a StudyTable independently of plots, forwarded by configured studies and drawn over the pane and overlay plots, including image exports. Tables scroll within narrow or short panes and stack above the study geometry. (#568, #1495)

  • ui::widget_bar::MarketHeatmapPanel renders host-supplied symbols as a grouped weighted treemap, with theme-based diverging percentage colours, values on hover and a selected-symbol intent. Its public entries accept updates without reconstructing the panel. RightBarIcon::MarketHeatmap adds its rail entry, and the demo feeds synthetic weights and live quote changes. Layout checks use hand-computed tile areas across groups and updated weights, including large finite inputs. Market data remains host-owned. (#557)

  • Charts consume Signals through set_signal_source, rendering host markers, levels and zones in theme colours with hover text and click callbacks. Time anchors follow history replacement, zoom and price-based elements, and priced markers can appear in visible whitespace; symbol and interval changes end old streams immediately, and lagged streams start fresh. The Signals menu hides categories without losing their data. The demo supplies live synthetic analytics through its feed when API samples are enabled. Analytics and external services remain host-owned. (#381)

  • Datafeed::price_targets optionally answers services::PriceTargets: high, average and low estimates, analyst count, publication and horizon dates. Unsupported feeds silently show nothing. The Symbol chart setting enables horizon-anchored projections from the last close, price and percentage labels and details on hover; stale symbol replies are ignored. Targets participate in automatic price fitting only where projections reach the visible time range, and their visibility participates in undo and layout copies. Labels use the host price formatter in instrument units on every scale, stay below the chart legend and quote controls in narrow views and retain their hover details when the horizon is offscreen. Hosts leave future whitespace in the logical range to show the horizon. The demo supplies targets for SAMPLE and has a daily-view quick-search action. Migration: ChartSettingsState literals add show_price_targets: false or use ..Default::default(); saved settings default it to false. (#556)

  • Symbol and comparison dialogs consume services::SymbolSearch, ignore superseded replies and request another page as the user scrolls. Without a service the supplied symbol list still works. Symbol search keeps recently opened instruments through Storage in StoreKind::RecentSymbols; failed reads prevent replacement. Empty searches with a category or exchange filter query the host catalog rather than restricting the results to recents. The demo connects its sample instrument catalog and application storage, including quick search. Migration: SymbolQuery literals add offset: 0; services apply offset before limit. (#380)

  • Right-clicking a TPO chart profile offers merging with the previous or next profile and splitting a composite back into its sessions. Commands update ChartTypeParams::tpo_composites as one undoable chart action, including neighbours outside the visible range; existing chart settings save the result. Hit testing shares the renderer’s placement and row widths, including profiles clipped at the plot’s left edge. Split extended-hours profiles can be merged across trading days. Migration: exhaustive ContextMenuAction matches handle MergeTpoPrevious, MergeTpoNext and SplitTpoProfile; ChartMenus has already applied these actions before returning them. (#106)

  • Studies declare source, colour, interval and symbol inputs alongside numbers, choices and toggles, with defaults retained separately from edited values. The settings dialog uses these declarations for editing, validation and resetting; CustomIndicator::with_inputs supplies validated inputs to a host calculation. ConfiguredStudy exposes a source, plot offset and calculation symbol/interval for single-series studies. Price sources include open, high, low, close, hl2, hlc3 and ohlc4; StudySource::Study selects another study’s undisplaced output by stable chart id and column. The chart calculates dependencies before their consumers, including hidden sources, and refreshes them after edits, live bars, undo and export. Substituting a source retains the input bars’ colours and host payloads. Chart::set_indicator_source rejects missing plots and cycles. Migration: StudyInput literals add default or use StudyInput::new(...).with_default(...); exhaustive InputValue and InputKind matches handle Source, Color, Timeframe and Symbol. Hosts restoring studies into a different chart remap stored source ids to the newly created studies. The demo stores template source positions and remaps them after loading; layout restoration uses its saved study-id map for source references as well as drawings. Single-study clipboard paste rejects chart-local study output references, which need host remapping. Existing numeric source choices remain accepted by studies that previously used them. (#168, #174)

  • Indicator::data_requests and update_data let studies consume additional host histories. The chart resolves, loads and subscribes to requested symbols and intervals through its connected Datafeed; hosts supplying bars directly use Chart::study_data_requests, set_study_data and study_data_error. Requested bars align by their calendar slots even when stamped inside them, missing slots leave gaps, and resuming a paused feed reloads missed history. Higher-interval calculations appear after the source bar closes; turning off “Wait for interval close” exposes the newest developing value on the latest chart bar. Advance/Decline Ratio divides advancing by declining issues, Advance/Decline Line accumulates their difference, and Cumulative Volume Index accumulates advancing minus declining volume. These studies use the close of each host-supplied market series, leave gaps for missing pairs and zero ratio denominators, and keep their running total across gaps. Hosts map the editable advancing/declining symbol keys to their own data service; no market data service is included. (#175)

  • Visible, fixed, session, periodic, anchored and auto-anchored volume profile studies draw horizontal up/down histograms with total-based POC, value area, VAH and VAL. Visible profiles use only the current viewport; saved fixed and anchored times survive prepended history, and session/calendar profiles include the whole exchange trading period. Inputs set row count or price height, value area and volume display and retain their declared defaults for resetting; the host supplies bars and instrument session metadata. VolumeProfile::from_bars also computes distributions directly from host-supplied finer bars. Studies and drawings share the same calculation and rendering, including negative prices and flat bars. Migration: the old per-bar volume-bin columns of VolProfileVisible and VolProfileFixed are removed; read Indicator::volume_profiles(visible_range) for source spans, price boundaries, total/up/down volumes and POC/value area. VolProfileFixed::with_range and VolProfileAnchored::with_anchor take UTC times. (#167)

  • Volume profile drawings can use a fixed price height per row through Inputs or VolumeProfileConfig::with_row_size. Rows align to multiples of that height and grow at the edges on new highs and lows, reusing completed-bar volume. Equal rows over the span remain the default and old saved drawings retain it. Nonpositive or nonfinite heights are rejected; a span needing more than 10,000 fixed rows is not drawn. (#359)

  • Volume profile drawings offer Total, Up / down and Delta displays. Rows split volume by bar direction (unchanged closes count as up), retain total-based POC and value area, and follow a forming bar when its direction changes. Display mode and direction colours are editable in Inputs and persist with the drawing; older files retain the Total default. (#565)

  • The drawings feature separates drawing tools, geometry, hit tests, history and persistence from widget; ui enables it, so default builds retain their tools. Widget-only charts keep series, studies, markers, primitives and keyboard action variants. config exports DrawingToolType, DrawingInteractionMode, ParseToolTypeError and FontWeight; their existing drawing imports remain available with drawings. Migration: applications using drawing APIs with default-features = false add drawings alongside widget. Drawing keyboard actions do nothing without the feature; Delete still removes a selected study. (#449)

  • DrawingToolRegistry registers stable host ids, names, anchor counts and shared DrawingRenderer implementations. Drawing::custom retains the id and JSON settings; the manager supplies multi-click placement, coordinate projection, handles, undo and storage, dispatches rendering and authoritative hit tests, and applies the renderer’s settings editor through show_custom_settings. Unknown ids remain stored until their implementation is registered. ChartBuilder::with_drawing_registry installs the catalogue before construction. Built-in availability filters registry picker entries and rejects disabled creation; clone the registry into DrawingToolbar::registry to hide or disable its drawing rows, glyphs, measure button and shortcuts. Hosts build custom pickers from custom_tools and activate entries with set_custom_tool. Migration: Drawing literals add custom_tool: None and custom_settings: serde_json::Value::Null, or use Drawing::new. DrawingRenderer now receives the current drawing and chart view; implementations provide render, hit_test and optional settings, while the manager supplies anchor handles. Its existing rendering-module import is retained. (#152)

  • Chart::create_drawing creates validated drawings from UTC times and prices using Drawing for style, locking, layer and study ownership. drawing_points and set_drawing_points round-trip and edit those anchors; the existing drawing_point_at and drawing_point_time conversions are public. DrawingManager::add_drawing validates chart-coordinate creation and records undo. Drawings add selectable, saveable, listed and a host-defined group; listed_drawings, group_drawings, set_group and select_group support host object lists and group actions. Non-saveable drawings stay out of chart saves and persistence notifications, including undo, while remaining visible. Existing anchored text and notes use screen_anchor pane fractions. Hosts own durable storage and retain or remap study ids. Migration: Drawing literals add the four fields, or use Drawing::new; older saved drawings default to selectable, saveable and listed, without a group. (#154)

  • ZigZag::pivots exposes the source-bar indices, prices and high/low kinds used by its drawn swings; the last pivot remains provisional. With drawings and studies, AutoDrawing registers trend line, parallel channel, Fibonacci retracement and extension, and pitchfork studies, each with Swing size, ATR multiple, ATR period, Zig Zag deviation and depth inputs. AutoDrawing::with_atr sizes swings by volatility: a reversal counts when it moves from the last extreme by at least a multiple of the average true range over a period, taken as a percentage of the confirming bar’s close, and bars before the average is defined, or without a finite positive close, confirm none. The catalogue registers these studies with 3 times the 10-bar average and a depth of 10, so they draw on minute, hourly and daily bars alike, where a fixed 5% swing left short intervals empty, and AutoDrawing::new keeps the fixed percentage. Editing the deviation or depth clears the study’s values, as the Indicator::set_input contract requires, and a template saved before the swing size input restores on the fixed percentage with its saved deviation, so saved studies keep their anchors. Trend lines join the latest same-kind pivots; channels pass their parallel through the intervening pivot; retracements use the latest confirmed swing and extensions project that swing from the moving last extreme. Indicator::drawings exposes their results, and the study renderer and hit test reuse the existing drawing geometry and pane mapping. Updating host bars replaces the anchors. Anchor and Fibonacci level prices participate in autoscaling even when the anchors are outside the visible bars. Custom presentation wrappers forward drawings, as ConfiguredStudy does. (#178, #1496)

  • FibonacciConfig::logarithmic measures retracement and trend-based extension levels in logarithmic price, with the same prices used for lines, labels, bands and hit testing in every price scale. It defaults to off, including in older saved drawings, and the Fibonacci properties page edits it. Nonpositive anchors retain arithmetic levels. Extensions project the logarithmic swing from the third anchor. Level labels sit above their lines and omit overlapping labels when levels crowd together. Migration: FibonacciConfig literals add logarithmic: false or use ..Default::default(). (#564)

  • Trading::show draws fills in the chart’s symbol as buy/sell arrows outside their bars. Fills on one side of a bar share a mark with up to ten chevrons; optional labels give total quantity and weighted average price, and crowded neighbouring labels group together. Hover lists every fill’s side, quantity, price and time. Marker labels retain the chart background for contrast. Trading::poll announces fills, partial-fill progress and rejection reasons; the host plays requested execution sounds. (#551)

  • Trading lines have joined quantity, P&L and close cells, separate reverse and dotted TP/SL controls, teal/orange brackets and connectors. Working orders have outlined price tags; projected orders offer Buy/Sell submit buttons. Drag previews remain until confirmation or discard. Hidden layers retain the account context needed to value brackets and avoid duplicate exits. The legend offers filled quote buttons, a quantity calculator and a ticket dropdown. Bid and Ask labels stay visible on either price axis. Trading notifications wrap in narrow windows.

  • The Trading settings tab controls positions, orders, executions and their labels, P&L units, reverse controls, quote labels, instant placement, notifications and host-provided execution sounds. Settings persist with ChartSettingsState; omitted fields use their defaults. Migration: handle SettingsTab::Trading, TradingLineAction::Exit and QuoteSide::Ticket in exhaustive matches. The ticket intent opens a ticket even with instant placement enabled. Trading::one_click moves to Trading::display.instant_orders; TradingSettings::show_buy_sell_btns is replaced by StatusLineOptions::show_quote_boxes. TradingLineOptions literals add show_orders, show_positions, submit, reverse, take_profit, stop_loss, pnl and bracket_pnl; use submit only for projected orders and handle TradingLines::submitted. TradingLines::outlined identifies outlined tags. UiColors adds take_profit and stop_loss; Toast adds optional trading details. Brokers push an order before its fills and preserve OrderRequest::position_bracket on position exits. The paper account keeps those exits from increasing exposure after a close or reversal and rejects exposure beyond the balance at its configured leverage.

  • The order ticket is a panel beside the chart. Its header holds the symbol, a menu with the presets and one-click trading (the same Trading::display.instant_orders setting), and a close button above an Order and DOM switch. The Order tab shows the bid and ask as Sell and Buy halves with the spread on the seam, the chosen side filled; Market, Limit, Stop and Stop limit tabs; the price with its distance in ticks from the ask or bid, or the distance itself after the swap button; the quantity in units or as an amount with the order’s value, and on market orders the risk at the stop loss in percent of the account’s balance; collapsible exits with their risk to reward ratio, each exit switched on and off and entered as a price, ticks, a percentage or money while it keeps its price; the time in force; and the order’s estimated margin against the account’s balance, leverage, tick value, trade value, reward and risk, above a two-line send button in the side’s colour. BracketMode::Money enters an exit as the profit or loss at it, TimeInForce::{Week, Month} request expiry at the end of the week or the month from brokers that advertise them, and TradingRules::leverage estimates the margin an order needs. Migration: call Trading::show_ticket before laying out the chart, since Trading::show no longer draws the ticket; exhaustive BracketMode matches handle Money. Risk sizing takes a percentage of the account’s balance instead of an amount of money. The broker contract accepts one exit pair per order.

  • The ticket’s DOM tab is a depth ladder of the chart’s order book: the bid and ask sizes at each price as tinted cells, prices above the last trade in the sell colour and below it in the buy colour, the price of the last trade marked, a level’s order count and latest observed size change on hover, and the totals of the sizes in view. A profile behind the prices sums the feed trades retained by the chart; each level’s tooltip separates volume traded at bid, at ask and of unknown side. The latest account fill for the symbol is outlined separately from the last trade. Clicking a bid or ask cell places a limit order on the passive side of the market and a stop order beyond it, the user’s working orders show as LIMIT and STOP tags in the margin of their side at their price, and dragging a tag moves its order and right-clicking it cancels it, each after confirmation. Orders at the same price share a tag with a chooser for the order to drag or cancel. The ladder centres on the current bid/ask midpoint, or the last trade without quotes, and scrolls, keeps prices fixed through a press or drag, and its lock keeps it from re-centring. Short panels scroll to the controls. Below it, the user cancels every buy or every sell, sees the position and its profit or loss, flattens, cancels all orders and reverses, buys and sells the ladder’s quantity at market and sets the time in force. Bulk cancellations also wait for confirmation. A new order from the ladder waits for confirmation unless one-click trading is on. (#236)

  • Chart::snapshot and restore keep the symbol, interval, chart type, display and interaction settings, study inputs and styles, pane order and collapse state, manual scales, view and timestamped drawings. SavedLayout writes version 2 documents and reads version 1 with defaults for the newly saved fields. Unregistered studies fail before saving. The layout menu lists, opens, saves, renames and deletes layouts through Storage, offers debounced autosave and handles Ctrl+S (Cmd+S on macOS) in the demo. Storage requests run in order. Migration: build snapshots through Chart::snapshot; literals of ChartSnapshot and SavedPane need the new fields, and SavedPane is cloned rather than copied. (#197)

  • Chart::set_storage saves and restores timestamped drawings per symbol through the host service, including edits made while a read is pending or before switching symbols. Unreadable documents are kept intact and failed writes retain the drawings in memory and report one error per run of failures. SettingsStore restores versioned UserSettings for the theme, last symbol and interval, drawing favourites and open layout, then saves after a one-second debounce. Its exit flush finishes available replies before writing the latest settings. The demo implements Storage with eframe persistence on native and web builds and imports its earlier drawings. (#198)

  • ui::trading::BrokerPicker is the dialog in which the user chooses a broker: a grid of the host’s BrokerTiles, each with a name, an optional logo, subtitle or rating, a featured badge and a favourite star the user toggles, after the built-in paper account, with a search and a “Need a broker?” link that returns BrokerPickerAction::NeedBroker. Picking a tile shows its connect card, whose Connect button returns BrokerPickerAction::Connect with the tile’s id for the host to connect Trading, such as to a PaperAccount for BrokerTile::PAPER. Trading::show_account_panel shows the account panel in a host panel: a tab named after the broker with a Trade button and minimize and maximize buttons, an account selector that switches between the host’s AccountPanel::accounts or disconnects, a currency, a settings button, and the account’s balance, equity, realised and unrealised profit and loss, margin, available funds and orders margin as the broker reports them. Its Positions, Orders, Order History, Balance History and Trading Journal tabs list what the broker pushes; Order History switches between orders and individual executions, each with its own CSV export, with right-aligned figures, profit and loss in the rising and falling colours, the chart’s symbol highlighted, a column chooser and an export as comma-separated values; clicking a symbol returns AccountPanelAction::SelectSymbol, and a hovered position or order offers to close it or cancel it after confirmation, or to change an order’s quantity, prices and brackets. Trading::disconnect and is_connected end and report the connection. The demo’s Trade button and Buy and Sell buttons open the picker until an account is connected, after which Trade shows or hides the account panel under the chart, and its settings button resets the paper account. (#220, #216)

  • services::PaperAccount is a ready-made Broker that simulates an account. The host chooses its currency and starting balance, and with leverage and commission the leverage its margin follows and the commission each fill pays as a fraction of its value. Fed the last prices with set_price, live or replayed, it fills market orders at the last price and limit and stop orders at the first price that reaches them, a limit at that price or better, works a triggered stop-limit order on as a limit order, turns an order’s take profit and stop loss into exit orders that cancel each other, nets one position per symbol at its average price, and books the realised profit or loss and the commission of each fill to the balance. It reports the equity, the realised profit or loss, the margin of the positions and of the working orders and the available funds, values each position at the last price with its trade and market value, leverage and margin, and keeps the most recent 1,000 finished orders, executions, balance changes and journal entries, which it pushes again on every connection; reset returns it to the starting balance. Account gains realized_pnl, margin, orders_margin and available_funds, Position gains last_price, trade_value, market_value, leverage, margin and expiration, and Order gains fill_price, placed and closed, all optional, and AccountEvent::Balance and AccountEvent::Journal carry a BalanceChange and a JournalEntry for brokers that keep history; the terminal skips pushes with non-finite values. The demo trades the same paper account live and during replay, feeding every traversed replay close, including when playback skips several bars. During replay the order ticket uses that close instead of the live bid and ask. (#221)

  • The top toolbar ends with Publish, Trade and a host call to action, as the right end of the default layout does. Publish, a light bulb with a plus, emits TopToolbarAction::Publish for the host to capture the chart with Chart::export_image and share it through its own service; Control::Publish hides it. Trade, an outlined pill, emits TopToolbarAction::ToggleTrading, which Trading::toggle_ticket answers by opening the order ticket for the chart symbol or closing it; it shows only while TopToolbarState::can_trade reports an attached broker and Control::Trading leaves it visible. TopToolbar::call_to_action takes an id and label for a filled pill after the host actions that returns TopToolbarAction::Host(id); it is None by default and then nothing is drawn. The demo copies a published image to the clipboard, turns Trade on with its paper account and keeps it available during replay, and reports its Upgrade call to action. Migration: exhaustive matches on TopToolbarAction handle or ignore Publish and ToggleTrading. (#844)

  • A quote contract feeds the watchlist, the symbol details panel, the symbol header and the order ticket. model::Quote holds a symbol’s last price and previous close, from which change and change_percent follow, its update time, session volume, best bid and ask, and latest pre-market or post-market trade (ExtendedHoursQuote). The host streams quotes through the new services::Quotes service: WatchlistPanel::set_service attaches it, and WatchlistPanel::poll, called each frame, subscribes to the symbols of the active list and the selected symbol, subscribes again with a new stream when they change or the stream lagged, which stops the previous one, and applies the pushed quotes. WatchlistPanel::quote reads a symbol’s quote back for SymbolDetailsPanel::set_quote, SymbolHeader::quote and the new Trading::set_quote, with which the ticket enters a market buy at the ask and a market sell at the bid instead of the last price. WatchlistPanel::set_price_decimals sets a symbol’s price decimals. The demo streams its watchlist through a quote service. (#222)

  • The order_flow bench pushes the order flow of a busy instrument into a chart’s feed: a synthetic book of 200 levels a side with 2,000 trades a second, each followed by its depth delta, 6 orders added or cancelled near the touch and a quote, 18,000 messages a second, drawing a frame for every 1/60 s of market time. It checks that the chart’s book matches the generator’s and prints the messages pushed per second, the frame time, the heap allocations per message and the heap the chart holds, with the depth history sampled every second and with one filled to all its resolutions: cargo bench --bench order_flow. Over 300 s of market time it pushes about 6.5 million messages a second with 0.02 allocations per message, all from the per-frame trade queue, and holds 7.8 MB, or 22 MB with a filled depth history. The demo’s live feed pushes the same synthetic book: each trade takes the liquidity in its way, the book quotes again around the new last price, orders come and go near the touch, and the quote is the book’s best bid and ask with their sizes. (#228, #229)

  • Chart::set_depth_history keeps the order book the feed sends over time in a data::DepthHistory, read with Chart::depth_history: columns of the resting size per price row on a fixed time grid, for liquidity heatmaps. DepthHistoryConfig sets the cadence (1 second by default), the rows kept per side nearest the touch (100), the ticks grouped per row (1) and the columns kept at each of 8 resolutions (600). The book is sampled as feed updates arrive, at the end of each period, so a column does not depend on the frame rate, a book that did not change for several periods gives one column spanning them, and an update stamped more than a minute after the feed’s time samples nothing. When the newest columns overflow, the two oldest merge into one spanning both, each row’s size averaged over their spans, so the history spans at least 42 hours in about 15 MB with the defaults. OrderBook::is_crossed reports a best bid above the best ask. (#229)

  • Trades carry the sale conditions the exchange reports: Tick::conditions holds TradeConditions flags (OFF_EXCHANGE, AUCTION, ODD_LOT, OUT_OF_SEQUENCE, EXTENDED_HOURS), set with Tick::with_conditions and tested with intersects, so studies and overlays can leave out prints such as off-exchange or auction trades. (#228)

  • Horizontal axes other than time, such as option strikes and yield curve maturities. A scales::HorizontalScale decides which keys of the horizontal axis are labelled, how they read and how the crosshair label reads, and Chart::set_horizontal_scale sets one; the time-based chart uses the same trait through its TimeFormatter. A key is the time of a bar, an instant that sorts as the key does, so price scales, panes, series, the crosshair, markers, price lines and drawings work on any scale, and scales::key_time and scales::time_key encode numeric keys. PriceHorizontalScale labels prices with a set number of decimals, multiples of 100 first, then of 50, 25, 10, 5 and 1, then half prices. MaturityScale labels months as 3M, 2Y or 2Y6M, multiples of ten years first, and its whitespace bars give the main series a slot every month, so curves added as series are spaced by maturity. On these scales the most significant marks in view are bold. Session breaks, extended-hours shading and the time spans of the measuring tools are drawn on the time scale only, and Chart::format_time and the time column of Chart::export_csv format a key as the crosshair does. The volatility_smile and yield_curve examples draw an implied volatility smile by strike and a yield curve by maturity with the public API alone. Migration: TickMark literals add bold, which the time axis sets for day, month and year marks; chart::render_crosshair_full takes a &dyn HorizontalScale in place of a &dyn TimeFormatter, so pass &formatter for a Box<dyn TimeFormatter>; drawings::rendering::ChartView literals add time_axis: true. (#835)

  • Chart::set_time_formatter, set_price_formatter and set_percentage_formatter take host formatters for the time axis, crosshair, tooltip and price scale labels, and set_locale and set_date_format set the language of month and weekday names and the strftime pattern of crosshair and tooltip dates. A time formatter writes axis marks with TimeFormatter::format, which receives the tick mark type, and hover labels and Chart::format_time with format_crosshair, in the chart’s time zone. The price formatter writes crosshair labels and price tags with PriceFormatter::format and axis ticks with the new PriceFormatter::format_tick, which defaults to format, on every price scale in the normal and logarithmic modes; the percentage formatter does the same with the percentage or index value in the percentage and indexed-to-100 modes. Studies keep their own formats. LocaleTimeFormatter now writes month and weekday names and the AM/PM marker in its locale’s language instead of English and honours show_seconds; the localized names come from chrono’s locale tables behind the new locales cargo feature, on by default, and without it, as in a build with default-features = false, they stay English. TimeFormatterBuilder::with_date_format and with_formatter expose the same options. Migration: DefaultTimeFormatter struct literals add date_format: None or use ..Default::default(), LocaleTimeFormatter literals add show_seconds: true and date_format: None, and chart::price_axis_width takes the price formatter as a fourth argument; pass None for the built-in labels. (#203)

  • A Bar can stand for a single value, hold an empty slot of the time axis, carry colours of its own and carry the host’s own data. Bar::from_value makes a point of a line, area, baseline or column series without filling OHLC. Bar::whitespace, whose values are all NaN (Bar::is_whitespace), keeps its slot when a series is loaded or updated, so a gap such as a halted session stays visible and a time of another series has a slot: nothing is drawn there, lines, areas and baselines break across it, the crosshair moves through it without a magnet snap, the legend and tooltip show no values for it, and the last-price line, countdown, previous close and percentage base use the nearest bar with a value. Studies take it as a bar without a value, as they take other non-finite input, price-based chart types and their ATR box sizes skip it, and trades in its slot fill it. Bar::colors holds an optional BarColors: the body (color), border and wick of a candle, the colour of an OHLC bar, a column or a line marker, the colour of the line from the bar to the next on line, step line, area and HLC area charts, and the top and bottom line and fill colours of a baseline segment; a candle border takes its colour when the series draws borders, and the last-value tag takes the bar’s color. Bar::payload holds an Arc<serde_json::Value> the chart does not read, which comes back with the bar from Chart::bars and in ChartPointer::bar and series_bars; at an empty slot ChartPointer::bar is the whitespace bar. JSON and CSV bars accept a date alone, such as 2024-03-15, as midnight UTC, the open of its day bar. A JSON bar with missing or null values is whitespace, and colours and payloads round-trip through JSON. Resampled bars leave out the colours and payloads of their source bars. Migration: Bar literals add colors: None, payload: None, or use Bar::new; struct updates from a borrowed bar, Bar { time, ..*bar }, become ..bar.clone(), since the new fields are not Copy. A bar whose values are all NaN, formerly dropped as invalid, is now kept as whitespace. (#826)

  • Chart::export_png renders the image of Chart::export_image on the CPU and returns it encoded as PNG, so a host needs no renderer or GPU readback. ImageExportOptions::include_crosshair draws the crosshair where the pointer last placed it over the plots, or where Chart::set_crosshair_position or a synchronized chart placed it since, and the export dialog offers it as “Crosshair”. Migration: build ImageExportOptions with ..Default::default() where every field was listed. (#834)

  • Chart options change at runtime: Chart::set_chart_options replaces the options that Chart::chart_options reads back and keeps the view unless the bar spacing, its bounds or the right offset change. Chart::set_size gives the chart an explicit size in points instead of the space show is given. Chart::set_crosshair_position shows the crosshair at a time and a main-pane price, with the horizontal line and price label at that price. ChartOptions::hovered_series_on_top draws the main series or overlay study under the pointer above the others, in the priority a click selects them. Migration: build ChartOptions with ..Default::default() where every field was listed. (#834)

  • A study’s legend row adds a more-actions button after its hide, settings and remove buttons, and the remove button shows a bin. The button, or a secondary click on the row, outlines the row and opens the study’s menu, the one a secondary click on the study’s plot now opens, in the chart menu’s style with its icons and shortcut column. Its rows add an alert on the study’s value at the legend’s bar, open the indicators dialog, add the study to the dialog’s favorites, and open submenus for the visual order, the visibility on intervals (the chart’s interval and above, and below, alone, or every interval, kept in StudySettings::hidden_intervals), moving the study to a new pane above or below its own, to another pane or to the main pane, and pinning it to the pane’s price scale, a new left scale or no scale. Copy, Hide, Remove, Object tree and Settings follow. Context menu rows can open submenus, which open beside their row on the side with room. ChartMenus applies the chart’s own actions as one undoable user action and returns every action as ChartContextAction::Study; StudyContextMenuAction::AddAlert carries the boxed Alert for the host’s alerts service, on the study’s output or, for volume, on AlertSource::Volume. Chart::reorder_indicator takes a VisualOrder for a study’s place in the draw order of its pane, where the main pane’s price series is one of the items and takes clicks before the studies drawn under it, Chart::set_indicator_scale and Indicator::set_scale pin a study to a StudyScale, and Chart::copy_indicator and Chart::paste_indicator carry a study with its inputs, styles, interval visibility, placement and scale to another chart as clipboard text. Delete and Backspace remove the selected study when no drawing is selected. The demo saves the alert, opens the indicators dialog, the favorites and the object tree with the study selected, and copies and pastes studies with Ctrl+C and Ctrl+V. Adding an indicator does not yet take the study as its source, studies have no shared left scale, and a volume overlay keeps its own band. Migration: PaneTarget::Pane uses the stable PaneId of an existing pane; StudyAction adds Menu { index, pos } and is no longer Eq, and PaneInteraction adds menu; exhaustive matches on StudyAction and ChartContextAction add the new variants, and a host that handled a study’s ChartContextAction::Series actions handles ChartContextAction::Study. (#850)

  • Primitives draw host content inside the chart. Chart::attach_primitive attaches a Primitive to the main series, an added bar series or a study, and it draws in the pane of that series on its price scale: behind the series and studies, above them, or above the drawings as well (PrimitivePass), inside the price and time axes behind their labels, and as PriceAxisLabel and TimeAxisLabel tags that the axis labels give way to. Its autoscale range joins the fit of the series’ scale, its hit_test reports the pointer as PointerTarget::Primitive and sets the cursor, and its attached, detached and data_changed hooks follow the series, with the egui context to request repaints. Chart::add_custom_series adds a series type the host defines: a study supplies the values that the legend, crosshair, last-value tag and autoscale read, and a primitive draws its points in place of the study’s plots and hit tests them, selecting the series. Image exports draw the same primitives. examples/primitives.rs shades the regular session behind the bars with labels on the time axis, and draws the range of each bar as a custom series in its own pane. (#830, #88)

  • The rest of the widget bar’s panel set. HotlistsPanel shows the hotlists the host names (such as top gainers) through the new Datafeed::hotlist, answered as HotlistEntry symbols with their last price, change in percent and optional price decimals, and returns HotlistsAction::SelectSymbol. NotificationsPanel shows the log the new services::Notifications service pushes as Notifications (time, title, text and symbol), keeps the most recent 1,000, counts entries not yet shown for the bar’s badge and starts over after a lagged stream. ChatsPanel shows the rooms and messages the new services::Chats service pushes as ChatEvents and posts what the user writes through Chats::send; a posted message appears once the host pushes it. ProductsPanel lists the host’s Products and returns ProductsAction::Open. Accounts, rooms, moderation and the products themselves stay with the host. The demo feeds every entry of the bar: synthetic hotlists, a log of its messages and alert triggers with a badge on the Notifications entry, two chat rooms that echo what the user posts, and a launcher of its own panels. (#845)

  • ScreenerPanel shows the rows the feed answers through the new Datafeed::screen in a table with the host’s column sets (ScreenerColumnSet of ScreenerColumns). The user picks a set, adds filters on its columns (ScreenerFilter: a column, ScreenerOp::Above or Below, a value) and sorts by clicking a heading; every change asks again with a ScreenerQuery of the set’s columns, the filters and the sort, and the feed screens, sorts and limits. ScreenerRow carries the symbol and one formatted value per column. The panel returns ScreenerAction::SelectSymbol, ExportCsv with the shown rows (every field quoted) and SendToWatchlist with their symbols. The demo screens its catalog symbols on their synthetic quotes and sends results to a new watchlist. (#224)

  • CalendarPanel shows the economic, earnings, dividend and IPO calendars the feed answers through the new Datafeed::calendar, grouped by day with each event’s time, country, importance and figures. The user picks the calendar, the days (yesterday, today, tomorrow, or this or next Monday-to-Sunday week, in UTC), the least importance of economic events and, with CalendarPanel::set_countries, the countries; every change asks again with a CalendarQuery and the feed applies the filters. CalendarEvent carries the kind, time, country, title, symbol, Importance and the actual, forecast and prior figures already formatted. A company event returns CalendarAction::SelectSymbol. The demo answers synthetic releases, earnings, dividends and offerings. (#244)

  • NewsPanel shows the headlines the feed answers through the new Datafeed::news for the chart’s symbol or the whole market, and NewsPanel::highlights shows short summaries under their headlines in the same way. NewsQuery carries the symbol (None for the market), whether highlights are wanted and a limit, and NewsStory the id, publication time, headline, source, text, symbols and link of a story. Each symbol or scope change asks again and only the latest answer shows; a feed keeping the FeedError::NotSupported default gets a notice. An opened story shows its text and returns NewsAction::ShowOnChart with its time, which the host passes to Chart::scroll_to_time, or NewsAction::OpenUrl. The demo shows synthetic highlights and headlines for its catalog symbols. (#243)

  • The widget bar has built-in entries for the full panel set: RightBarIcon::Watchlist (the watchlist with the symbol’s details) before Alerts and the Object Tree, and a second group at the foot of the bar of Highlights, Screener, Hotlists, Calendar, News, Notifications, Chats and Products, above the line and Help. WidgetBar::default still shows Alerts, the Object Tree and Help; a host adds the entry of each panel whose feed it supplies to WidgetBar::icons, and entries draw in RightBarIcon order whatever their order in that list. Products, the launcher, draws as a filled round button. New glyphs on the 24 unit grid: WIDGET_BAR_WATCHLIST, WIDGET_BAR_HIGHLIGHTS, WIDGET_BAR_SCREENER, WIDGET_BAR_HOTLISTS, WIDGET_BAR_NEWS, WIDGET_BAR_NOTIFICATIONS, WIDGET_BAR_CHATS and WIDGET_BAR_PRODUCTS. The demo shows the watchlist through the built-in entry and the data window in the Object Tree, and no longer has a Data Window entry. Migration: RightBarIcon is #[non_exhaustive], so a match on it adds a wildcard arm.

  • Studies can draw price bands as StudyZone values, a band between two source bars in the style of one of the study’s outputs, returned by Indicator::zones and stored per zone instead of per bar. The visible zones of a study count in its price autoscale. Gaps draws its gaps as zones, one per extent a gap has held, with “Up gaps” and “Down gaps” outputs for their style, so its memory follows the gaps shown rather than the bars and it shows up to 500 gaps. (#842)

  • SeriesStyle sets a bar series’ last value label, its price line’s visibility, PriceLineSource (the newest bar or the newest bar in view), colour, width and style, a base line at 0% or 100 on percentage and indexed scales, an AutoscaleProvider that replaces the range the series contributes to its scale’s fit, and the click tolerance of the main series. Chart::series_style and series_style_mut reach the main series’ style and each host series’ SeriesOptions::style; the chart-wide show_symbol_last_val and show_price_line switches still hide every label and price line. Host series draw a price line only when asked. Migration: struct literals of SeriesOptions set style or use ..Default::default(). (#832)

  • AreaStyle::invert_filled_area fills the Area chart from its line up to the pane top, and turning off relative_gradient spreads top_fill to bottom_fill over the whole price pane instead of between the line’s visible extreme and the edge the fill reaches. ChartTypeParams::columns_base draws Columns up and down from a price instead of up from the pane bottom. Migration: struct literals of AreaStyle and ChartTypeParams set the new fields or use ..Default::default(). (#832)

  • LinePlotStyle::line_type draws the Line, Line with markers, Area and Baseline charts as LineType::Curved, a Catmull-Rom spline through every point, or with straight segments. ChartTypeStyles::crosshair_marker_radius marks the hovered bar on the line of the line-based charts, ringed in the chart background, and last_price_animation pulses at their last price continuously or once per update with LastPriceAnimation. Both are off by default. Migration: struct literals of LinePlotStyle and ChartTypeStyles set the new fields or use ..Default::default(). (#832)

  • ChartTypeStyles::bars styles the Bars chart: BarsStyle::open_visible hides the open tick, and thin_bars, on by default, draws bars with the chart’s wick width at every zoom level; without it the stroke is half the bar width, at least 1.5 points. Migration: struct literals of ChartTypeStyles set bars or use ..Default::default(). (#832)

  • CrosshairMode::MagnetClose snaps the price pane’s crosshair to the bar’s close only; volume and study panes snap to their values as with Magnet. CrosshairStyle::Hidden draws neither crosshair lines nor axis labels while legends, the data window and tooltips keep following the pointer. CrosshairOptions styles each line with vert_line_style and horz_line_style and colours each axis label with vert_label_background_color (time axis) and horz_label_background_color (price axis). Migration: replace line_style with both line style fields and label_background_color with both background fields; exhaustive matches on CrosshairMode and CrosshairStyle add the new arms. The settings dialog’s single crosshair style sets both lines. (#832)

  • ChartConfig::grid_line_style sets the grid’s line style, dotted by default, and vertical_grid_line_style overrides it for vertical lines, as vertical_grid_color does for colour. Migration: struct literals of ChartConfig set both fields or use ..Default::default(). (#832)

  • LineStyle::LargeDashed and LineStyle::SparseDotted add long dashes and widely spaced dots to drawings, series, price lines and their settings menus. CrosshairLineStyle, SessionBreakStyle and the study PlotPattern gain the same two styles. LineStyle::name gives each style’s menu name. Migration: exhaustive matches on these enums add arms for the two styles. (#832)

  • Panes are reachable from the API. Chart::add_pane creates an empty pane, remove_pane removes one with its series and studies, panes lists them from top to bottom with PaneId::MAIN for the price pane, and pane_series and series_pane map panes to the series and studies they draw. move_series_to_pane places a host series or a study in any pane; below the price pane a host series uses the pane’s price scale and draws its line, price lines, markers, legend row and last-value tag there, and crosshair and click events report values in its units, snapping to its close in magnet mode. move_pane and swap_panes reorder panes, the price pane included, which the pane menu can now also move. Expanded panes share the height by stretch factor, 3 for the price pane and 1 for the others by default: set_pane_stretch_factor sets it, set_pane_height turns a height in pixels into one, and pane_height reads the height drawn in the last frame. set_preserve_empty_pane keeps a pane after its last series or study leaves it. PaneOptions, set with Chart::with_pane_options or pane_options_mut, turns separator dragging off and sets the separator and hover colours. The demo’s quick search adds a symbol in a new pane above the price pane. (#827)

  • ChartConfig::price_axis takes PriceAxisOptions, which draw a border between the plot and the price axis in the theme’s border colour or a chosen one, a tick beside each label, and labels for the prices at the top and bottom of the pane in place of the ticks next to them, and choose whether labels the pane edges cut are hidden (the default) or shown clipped. PriceScaleOptions::tick_marks gives each scale its PriceMarkGeneratorConfig, so target_density sets the number of labels and grid lines; PriceMap::marks generates them. Chart::price_axis_width returns the width of the left or right price axis at the last frame. Migration: render_price_labels and render_price_labels_at_pos take the PriceAxisOptions after the colours; ChartConfig and PriceScaleOptions literals add the new fields or use ..Default::default(). (#833)

  • Chart::set_watermark paints a host Watermark behind the series of the price pane, alongside the symbol watermark of ChartConfig: an optional egui::Image above any number of WatermarkLines, each with its own text, size, FontWeight and colour, aligned together at any Align2 with a padding from the pane’s edges. The image fits the pane less the padding, keeping its aspect ratio, unless its max_size is smaller; its tint sets its opacity. Watermarks are kept in exported images. (#831)

  • Chart::set_change_markers marks, on a bar series, where a live update raised or lowered the close of a stored bar: a dot at the new close with a chevron above it for a rise or below it for a fall, in the ChangeMarkers up and down colours, for its duration (5 seconds by default). Updates from update and from a connected feed count; unchanged closes, new bars and history do not, and replacing the bars with set_data drops the marks. (#831)

  • MarkerPos::{AtPriceTop, AtPriceBottom, AtPriceMiddle} anchor a marker to Marker::price (set with Marker::at_price) just above, just below or across that price instead of to its bar, on the main and on added series. Chart::set_marker_options takes MarkerOptions per bar series: auto_scale (default true) widens the autoscaled range to the price-anchored markers in view, and z_order paints the markers with their series (Normal, the default), over every series and study (AboveSeries, where main series markers were painted before) or over the price lines and drawings too (Top). Chart::markers reads back the markers set on a series. Migration: Marker struct literals add price: None, and exhaustive MarkerPos matches handle the three new positions. (#831)

  • Chart::add_price_line adds one price line to a bar series and returns a PriceLineId handle; update_price_line moves or restyles that line in place, remove_price_line removes it and price_line reads it back. set_price_lines still replaces the whole list and retires the handles of the lines it replaces. The demo moves or removes a level line through its handle from the chart menu. It opens on a plain chart; Toggle API samples in its quick search adds the level line at the recent high, marks a fill and a stop at their prices, marks live changes of the close and signal bars, and shows a two-line watermark with an image. PriceLine::axis_label_color, axis_label_text_color and title_color colour the axis tag and the title independently of the line, on the main and the added series’ axes. Migration: PriceLine struct literals add the three fields as None or use ..PriceLine::new(price, color). (#831)

  • Pointer events carry what a host legend, tooltip or context action shows. ChartPointer adds the rendered slot index, the UI-point pos, the pane counted from the top, the main series bar and previous_close at that slot, the bars of visible added series at its time, the visible study plots with the id of each study, the drawing, series or study line under the pointer as a PointerTarget in click priority, the held modifiers and the PointerKind. ChartEvent::DoubleClick follows the click that completes a primary double click. CrosshairMoved also reports a stationary cursor whose bar or modifiers change. egui reports pens as touch. The demo’s data window reads the hovered values from the crosshair payload. Migration: ChartPointer is no longer Copy and is #[non_exhaustive]; clone it where it was copied and read its fields rather than building it. (#829)

  • The study catalogue adds eight oscillators under their conventional titles: AcceleratorOscillator (“Accelerator Oscillator”, Bill Williams’ AO minus its 5-bar average, columns green when rising and red when falling or unchanged), AroonOscillator (Aroon Up minus Aroon Down over 14 bars, -100 to 100 with a zero level), AverageDailyRange (the 14-bar average of high minus low), BBTrend (John Bollinger’s comparison of 20 and 50-bar bands at 2 deviations, columns shaded by sign and direction), ChaikinOscillator (EMA 3 minus EMA 10 of the Accumulation/Distribution line, seeded with the first value), BullBearPower (high plus low minus twice the 13-bar EMA of the close, as Elder Ray seeds it), AdvanceDeclineRatioBars (“Advance/Decline Ratio (Bars)”, up bars over down bars against their open in the last 9 bars, without a value when no bar closed down) and UlcerIndex (Peter Martin’s root mean square drawdown from the 14-bar highest close). Their lengths are editable inputs, except the fixed 5, 34 and 5 of the Accelerator Oscillator; each skips bars with non-finite inputs and is checked against values computed independently from its published definition. (#176)

  • Built-in oscillators PriceMomentumOscillator (Swenlin’s doubly smoothed one-bar rate of change with an EMA signal, 35/20/10), PringsSpecialK (Pring’s twelve weighted rate-of-change averages with a twice-smoothed 100/100 signal), RciRibbon (short, middle and long rank correlation lines, 10/30/50, levels at +80, 0 and -80), RelativeVolatilityIndex (Dorsey’s RVI of the 10-bar close deviation with 14-bar EMAs, levels 80/50/20 with a filled band), SMIErgodicIndicator and SMIErgodicOscillator (Blau’s true strength ratio with its EMA signal, and their difference as a histogram, 20/5/5) and WoodiesCCI (turbo 6 and 14-bar CCI of the close, with columns coloured by the five previous values, levels at +100, 0 and -100). Each is in the factory catalogue under its conventional title and checked bar by bar against an independent calculation. (#176)

  • Six price studies join the catalogue. WilliamsAlligator draws Bill Williams’ jaw, teeth and lips, smoothed averages of the median price over 13, 8 and 5 bars displaced 8, 5 and 3 bars ahead, with editable lengths and offsets. ChandeKrollStop draws Chande and Kroll’s short and long stops (ATR length 10, coefficient 1, stop length 9). VolatilityStop draws Wilder’s ATR stop and reverse (length 20, multiplier 2) as crosses coloured by trend. Median draws the 3-bar nearest-rank median of the bar midpoint, its EMA with a green or violet fill between them, and bands two 14-bar ATRs away. ChopZone colours a unit column per bar in nine bands by the angle of the 34-bar EMA of the close. BollingerBars redraws each bar at full width through Indicator::candles, with the wicks as blue blocks behind an up or down body. (#176)

  • TimeWeightedAvgPrice (Time Weighted Average Price) is the mean of a price source, ohlc4 by default, over the bars since the start of each anchor period, and VwapAutoAnchored (VWAP Auto Anchored) draws one volume weighted average price, of hlc3 by default, from an anchor bar to the latest bar: the first bar of the last session, week, month, quarter, year, decade or century, or the most recent bar with the highest high, lowest low or highest volume among the last length bars (20 by default). Its Auto anchor takes the period from the chart interval: the session below a day, the month at a day, the quarter up to 10 days, the year up to 60 days and the decade above. Both count periods in the instrument’s exchange trading days as VWAP does, through AnchorPeriod. (#176)

  • Volume24h (“24-hour Volume”) sums the volume of the bars opened in the last 24 hours on any intraday interval, giving the bar’s own volume on daily bars and no value on longer ones. RelativeVolumeAtTime (“Relative Volume at Time”) divides the volume of the current day, week or month so far (or of the bar alone in Regular mode) by its average at the same point of the previous 10 periods, with trading days from the instrument’s time zone and session, as columns around a level at 1. TradingSessions (“Trading Sessions”) shades the bars that open within the Tokyo, London and New York exchange hours, or three host-defined sessions in their own time zones, on intraday charts. Seasonality projects each month from the previous month’s close and the average change of that calendar month in earlier years, as a filled box with the average, standard deviation and month count as hidden plots; the yearly heatmap table and the future part of the current month are left to the host. (#176)

  • CandlestickPatterns (“All Candlestick Patterns”) marks 44 bullish, bearish and neutral candlestick patterns, from doji, hammer and engulfing to the star, three-method and tasuki-gap formations, each with its own toggle. A PatternTrend input requires the conventional downtrend or uptrend against SMA(50), or SMA(50) and SMA(200), or ignores trend, and a PatternType input limits the marks to bullish or bearish patterns. Bullish patterns are marked under the low, bearish over the high and neutral ones over the high, each labelled with the abbreviations of the patterns on the bar. (#177)

  • Four event studies join the catalogue. WilliamsFractals (“Williams Fractals”, 2 periods) marks Bill Williams’ fractals with up and down triangles, accepting up to four equal highs or lows just before the fractal bar. PivotPointsHighLow (“Pivot Points High Low”, 10 bars on each side for highs and lows) marks swing highs and lows and labels each with its price through plot_text. Gaps (“Gaps”) draws each gap of at least 30% of the 14-bar average range as a green or red zone that extends until price enters it, with inputs to shrink a partly filled gap, cap the number of gaps shown (15, at most 500) and limit their length (300 bars, off). RsiDivergence (“RSI Divergence Indicator”, RSI 14, pivots 5 by 5, 5 to 60 bars apart) draws the RSI with its regular divergences, and optionally its hidden ones, as segments joining the two RSI pivots and “Bull” or “Bear” marks. (#176)

  • Indicator::plot_text labels a circle, cross or triangle plot at a source bar, drawing the text under an upward triangle and over the other shapes in the shape’s colour. Configured studies forward it, so pattern, fractal and pivot studies can name what they mark. (#176, #177)

  • Chart::fit_content, reset_time_scale, scroll_to_real_time and scroll_to_position fit every bar, restore the configured bar spacing and right offset, and scroll to the latest bar or to a right offset in bars, optionally animated over 400 ms to the latest bar and one second to a position. Scrolling to the latest bar does not enable tracking mode, and any other change of the view ends an animation. visible_logical_range and set_visible_logical_range read and set the fractional model::LogicalRange, including whitespace. index_to_time, time_to_index, index_to_x and x_to_index convert between UTC times, fractional logical indices and screen x, interpolating between bars and extrapolating into whitespace. time_scale_size returns the time axis size, and drain_events reports ChartEvent::VisibleLogicalRangeChanged and ChartEvent::TimeScaleResized. TimeScaleOptions::right_bar_stays_on_scroll now keeps the right offset when zooming with the wheel, a pinch or the keyboard, uniform_distribution shows time marks of one weight all or none, and allow_bold_labels turns off bold day, month and year labels. The new tick_mark_max_character_length spaces labels for longer custom formats, minimum_height sets a minimum time axis height, and border_visible with border_color draws a line along the top of the time axis. TickMarkGenerator::with_uniform_distribution exposes the same mark selection. Fitting the content, also through its shortcut, now leaves the configured right offset, in bars or pixels, free of bars, with every bar in view. Migration: TimeScaleOptions literals add tick_mark_max_character_length, minimum_height, border_visible and border_color, or use ..Default::default(); render_time_labels takes &TimeScaleOptions in place of its ticks_visible flag. (#828)

  • SymbolDetailsPanel shows the chart symbol in bold with layout, edit and more actions, its name and exchange with a link to the page in SymbolDetails::url, the host-supplied regular-session quote large with its currency, change and last update time in the time zone given to set_timezone, the pre-market or post-market trade given to set_extended_hours with its change from the regular last price, the session and 30-day average volume given to set_volume above a bar split between the two, the key statistics and profile the feed answers through the new Datafeed::symbol_details, and the user’s notes on the symbol. The layout menu shows or hides the volume, statistics, profile and notes, and the edit button moves to the notes. SymbolDetails carries statistics and profile as labelled values in display order; an empty section, or a feed keeping the FeedError::NotSupported default, shows nothing, and an answer for an earlier symbol is ignored. Notes are kept per symbol in a versioned StoreKind::SymbolNotes document: read before the first write, written as they are edited with one write per document at a time, and never written over after a failed read. The demo shows the details of the chart symbol below its watchlist, with synthetic statistics, volume and notes kept in its app storage, and reports SAMPLE trades outside its regular hours as pre-market or post-market.

  • The TimePriceOpportunity study draws each session’s TPO profile on the price pane of a time-based chart, starting at the session’s first bar, as letters or blocks with the point of control, value area and initial balance, for the visible sessions or only the latest one. Its inputs set the period, ticks per row, value area percentage and extended-hours split. Indicator::tpo hands its TPOConfig to the chart, which builds the profiles through the TPO chart type’s code and cache, so a session’s profile equals the chart type’s under the same settings; the study plots no values. The demo lists it with the other studies. (#571)

  • TPO profiles follow the chart’s sessions, the instrument’s exchange sessions or calendar days in its time zone, and calendar days in the chart’s time zone without one, instead of the UTC date, and cover the whole sessions of the visible bars instead of the visible bars alone. TPOConfig::split_sessions gives separate pre-market, regular and post-market profiles, and TPOConfig::composites combines the sessions opening within a range into one profile: a range over adjacent sessions merges them, removing it splits them back, and a range over many sessions builds a composite. Periods are at least the bar interval, so hourly bars take the letters A, B and C instead of A, C and E. The value area shading spans the widest row instead of every period, the initial balance is drawn beside each profile, and a profile narrows its columns to fit within its session, switching to blocks when letters no longer fit. The Symbol tab edits the period, ticks per row, value area percentage and extended-hours split, which serialize with the chart type settings as ChartTypeParams::{tpo_period_minutes, tpo_row_ticks, tpo_value_area, tpo_split_sessions, tpo_composites}. Migration: to_tpo_profiles takes the bars’ BarClock, such as Chart::bar_clock; pass &Timeframe::Min1.into() for the previous UTC days. render_live_tpo takes the full bars, the visible range and the clock. TPOConfig and ChartTypeParams literals add the new fields or use ..Default::default(), and CandleDataContext literals add clock and tick_size. (#106)

  • Trading::show draws broker orders, brackets and positions with price tags, P&L, cancel, close and reverse actions. Accounts with Capabilities::modify can drag lines to tick prices through Broker::modify; its default reports unsupported. Changes require confirmation, which is discarded when the order or position changes. chart::render_trading_lines exposes the renderer without the ui feature. (#217)

  • ui::trading::Trading connects Buy/Sell buttons to a broker-backed ticket with market, limit, stop and stop-limit orders, unit/value/risk sizing, price/tick/percent brackets, time in force and saved presets. Ticket and one-click quantities follow Broker::rules; unsupported rules default to whole units and day orders. Prices snap to instrument ticks. The host persists presets and owns the connection; refusals and fills appear as notifications. The demo supplies a session-only paper account whose bracket exits reduce the remaining position. (#219)

  • WatchlistPanel shows named watchlists fed by host quotes. WatchlistQuote supplies the last price and the previous close, from which the panel derives the change and the change percent over the absolute previous close. Lists hold symbols and sections, sort by any column inside each section with missing values last, reorder by dragging while unsorted, take colour flags from the row menu, collapse and expand under their section titles, and import and export comma-separated text with ### section titles through Watchlist::from_text and to_text. The header shows the list name in bold as the list menu, then add symbol, advanced view and more buttons: add symbol returns WatchlistAction::AddSymbol for the host to pick a symbol and pass it to WatchlistPanel::add_symbol, advanced view returns WatchlistAction::AdvancedView, and the more menu adds sections and imports or exports the list. Clicking a symbol, or the up and down arrow keys after a click, returns WatchlistAction::SelectSymbol; file dialogs and persistence of lists stay with the host. The demo feeds synthetic quotes, keeps its lists in application storage, switches the chart symbol from the panel and adds the symbols picked in its symbol search. (#223)

  • TimeAndSalesPanel lists the latest 10,000 trades the host pushes from its stream, newest first, with buys and sells in the rising and falling colours and trades of unknown side neutral. Size filters edited in the panel restrict the list to trades reaching one of them, and push returns the matching filter with sound that has the largest threshold, so the host can play its sound. TimeAndSalesConfig sets the price and size decimals and the time zone. The demo feeds the executions of its synthetic stream and shows a notification in place of a sound. (#237)

  • HigherIntervalCandles overlays higher-period candle bodies and wicks across their source bars, coloured by direction, with editable interval and extended-hours inputs. It uses the shared session aggregation, includes the forming period and rebuilds on live corrections. Indicator::set_bar_clock shares the source calendar and Indicator::candles exposes period OHLCV and source ranges; ConfiguredStudy retains the geometry through styling and cloning. The demo’s Indicators picker includes the study with daily defaults. Hosts supply the chart bars; another interval from a feed remains host-owned. (#546)

  • data::resample_with_session derives intervals from host-owned base bars using the instrument’s exchange hours, holidays and overnight trading dates. Intraday buckets start at the first selected session window, and the short last bar stops at its session close. Calendar labels use UTC by default; pass source and target BarClock values for another selected calendar. Inline parsed arguments name .parse::<Timeframe>(). Gaps remain empty and the forming period includes every available input. Instrument::native_timeframes reports the intervals a source supplies without aggregation; unknown metadata stays None. BarClock::with_session and the chart feed preserve those intraday opens through historical and live merging. The demo declares its native minute history. Hosts own fetching and retaining their base data. (#97)

  • Chart::export_csv exports loaded source bars with freshly calculated visible study plots, plot displacement, gaps, chart time zone offsets and instrument/study precision. Chart::export_image renders an isolated egui frame with chart title, export timestamp, pixel dimensions and transparent background options, retaining drawings, their interval visibility, comparisons, study panes, loaded source marks and typed events with their visibility settings without changing the live chart or polling feeds. Late image results do not change a reopened export dialog. Hosts render the returned meshes/textures and own encoding and delivery; the demo wires offscreen GPU rendering, PNG/clipboard delivery and CSV saving. The export dialog offers these implemented image options; SVG remains absent. Migration: ExportConfig literals add image: Default::default() or ..Default::default(). (#200)

  • Chart::set_mark_source requests host bar annotations, time-axis badges and typed events through services::Marks for the visible UTC range, including whitespace. Stale replies are ignored; empty answers clear source marks while manual markers remain independent. Hosts refresh with reload_marks and read failures with take_mark_error. Bar marker hover text is displayed, and colliding time badges stack with independent hover and click targets. The demo supplies synthetic marks from its own bars and retains event visibility and sources in copied layouts. (#76)

  • model::{TimeScaleEvent, EventKind, EventVisibility} describes host earnings, dividends, splits, economic releases and news with UTC timestamps, headlines, details and stable click IDs. Chart::set_time_scale_events accepts events directly; event_visibility and the settings dialog’s Events tab filter every category without discarding data. Accounts, news and economic data services remain host-owned. Migration: exhaustive SettingsTab matches need Events; EventsSettings is now an alias of EventVisibility, and struct literals add show_news or use ..Default::default(). Saved settings default missing event fields. (#242)

  • Chart::set_replay_time retains host history behind an exclusive completion cutoff, hides future bars and live quotes, and restores retained updates and the previous feed pause state on exit. Studies and price-based elements use the same window; rewinding clears future study results. Tick-derived overlays stay hidden during bar replay. set_replay_source builds partial chart candles from completed finer bars using the source calendar. ChartLayout::set_replay_time drives one cursor across a synchronization group, including hidden slots. ReplayStartPicker emits chart-click, UTC-date, random, first-bar and resume intents. ReplayController::{cutoff, seek_cutoff, session, restore_session} connects source playback and serializable, symbol-checked checkpoints; restoration pauses and requires the saved timestamp. The demo wires these choices, offers minute updates on coarser charts and saves checkpoints through application storage. Hosts own historical/finer data, randomness and durable storage. Bar timestamps are authoritative in ReplayController; its separate timestamp vector remains accepted for compatibility. Migration: exhaustive ReplayControlAction matches need SetUpdateInterval(Timeframe); supply available source intervals through FloatingReplayControl::set_update_intervals. (#213)

  • WidgetBar::register_panel accepts host widget metadata and a stateful content callback. show_panel renders the active registered panel with the shared header, close button and a resizable width retained by egui. Host and built-in selections remain exclusive; replacing a registration preserves its strip position. Existing id-only widgets remain available. The demo registers session notes alongside the data window and built-in panels. Hosts own panel data and persistence. (#206)

  • ChartMenus::host_entries appends conditional HostMenuEntry rows to the chart, series and drawing menus. ChartContextAction::Host returns the registered id and original target, UTC bar time and clicked value; time is absent outside loaded data. TopToolbar::host_entries renders themed buttons and dropdowns in registration order and returns TopToolbarAction::Host. The demo lists its research and symbol-copy actions in its main menu; the research action reports the last chart click time and price. The strip scrolls when controls cannot fit. Dropdown choices are one level deep. Hosts supply the services behind these actions. Migration: exhaustive action matches handle the two new Host variants. (#566)

  • Control now names every top-toolbar button and the Object Tree and Help rail buttons. set_control_visible removes controls from the strip and overflow without leaving separators; hiding an active rail entry clears it. Chart and series menu rows share the Settings, Indicators and ObjectTree controls and add ResetView, CopyPrice and ExportData switches; axis menus honor Settings, TimeZone and Session. Empty menus close, and ContextMenus disables all turnkey menus. ChartOptions continues to govern interaction behavior. ChartBuilder::with_theme now retains the theme for local rendering, so text sizes and overlay palettes no longer come from another chart’s context theme. Chart::set_theme_override replaces or clears this local style; set_theme still themes egui and clears the local override. Component configs retain their public dimension overrides. (#202)

  • Chart::drain_events reports UTC visible-range changes, crosshair moves and exits, plot clicks with time and pane values, successful history loads, and symbol and interval changes. Setter notifications retain occurrence order; unchanged views and stationary cursors emit nothing. Existing polling APIs remain independent. visible_time_range and apply_synced_time_range already read and set UTC plot edges, including whitespace. The basic example records host-owned click state. Hosts supply history and streaming data. (#201)

  • Sector collects its center, radius endpoint and end ray, sweeping clockwise on screen with selectable borders and optional fill. ArrowMarkLeft and ArrowMarkRight place directional marks in one click. Sticker places bundled vector illustrations through the glyph picker. Path drawings end in an arrowhead by default. Arrow Marker already uses two points, and the presentation cursor already highlights pointer movement. Migration: exhaustive DrawingToolType matches need the four new variants. Their toolbar artwork is exported from icons::icons alongside the existing drawing icons. (#147)

  • The Icons/Emojis flyout groups bundled vector icons, Unicode emoji and stickers in a searchable grid, with session recents first and an independent size control. Bundled icons and stickers render without host fonts or image loaders; Unicode emoji retain the host font fallback. The existing Drawing::font_size saves the size, and keep-drawing mode retains the picked glyph and size. Migration: handle DrawingToolbarAction::InsertGlyph { icon_name, size } by calling DrawingManager::start_icon_insertion and setting the prepared drawing’s font_size; InsertEmoji remains available for existing callers. ToolbarState literals add glyph_picker, or use ..Default::default(). Hosts continue to own durable drawing storage. (#742)

  • Chart::add_series attaches host-fed close-price lines with stable ids, independent history and streaming updates, markers and price lines. SeriesScale assigns bar series to shared right or left axes, hidden overlays or additional labelled scales; set_series_scale and series_price_scale_mut also accept the main series. add_comparison defaults to a shared percent range with a separate first-visible-close reference for each member. set_series_visible and remove_series cover every bar series, including the main one; hidden members do not stretch auto-scale ranges. Removing the main series pauses its feed and retains its time axis for the remaining series and drawings. Secondary times project onto that axis, including whitespace and price-based elements. Hosts own data feeds. The demo uses native comparison series and retains them across layout copies. (#87)

  • Added bar series take every time-based chart type of the main series through SeriesOptions::chart_type, with up_color and down_color for rising and falling bars and the baseline sides, and columns_base for Columns that rise and fall from a price, which their scale’s fit includes, as ChartTypeParams::columns_base does for the main series; their scales fit the lows and highs of the OHLC types. In a pane other than the price pane a series keeps its chart type and draws the crosshair above its bars, its legend row hides or removes it or hands its id to take_indicator_settings_request, and series_price_scale returns the pane’s scale. set_series_options changes the options of an added series at runtime, and series_order and set_series_order set the draw order that series follows. pop_bars removes the last bars of any bar series, bar_index_at finds the bar at a time or its nearest neighbour on either side, and bars_in_logical_range returns the bars inside a range of logical indices with the bars before and after it. ChartEvent::DataUpdated reports live bars from update or the chart’s feed and removals, once per series in a row. series_price_map converts between the prices of any bar series and pixels in whichever pane draws it, and format_series_price formats them as its scale does. The symbol the demo’s quick search adds in a new pane is drawn as candles, on the left scale once moved to the price pane, and keeps its pane across layout copies. Migration: struct literals of SeriesOptions set chart_type, up_color, down_color and columns_base or use ..Default::default(). (#825)

  • Renko, Kagi, Line Break, Point and Figure and range charts calculate a separate set of study results from element OHLC, retaining the source-bar results for hosts and time-based views. Element outputs share the existing refresh budget, update from the first changed element and drive overlays, pane scales, selection, magnets, legends and readouts. Markers and retained drawing times use element completion intervals, with quiet trailing history on the last element. Point and Figure uses column start intervals so quiet bars stay in the current column. Repeated completions choose the first slot unless a drawing already retains another matching slot. Newly placed drawing anchors retain element times across chart-type switches. Chart::study_values_at returns displayed element outputs; indicators continues to expose source-bar results. The hidden-annotations notice is removed. (#712)

  • Drawings can be created, selected, dragged, erased and edited in study panes using each pane’s own scale, including manual, inverted and logarithmic ranges. Pane ownership survives drawing storage, undo, pane resizing, maximisation and study merging; hidden or collapsed panes leave no drawing hit targets. Magnet targets use the studies in that pane. Drawing::pane identifies the owning study, with None retaining the main price pane; hosts restoring studies retain or remap those ids. Migration: add pane: None to Drawing literals, or use Drawing::new. Older saved files default to the main pane. (#151)

  • Drawing properties expose Inputs for Fibonacci levels, pitchfork levels, Gann divisions, position sizing, volume profile rows and value area, regression bands and channel midlines. Coordinates open with every anchor and accept finite prices and UTC times, retaining fractional and repeated-time anchors. Invalid drafts stay open without changing the chart. DrawingPropertiesDialog::open_for_chart and show_and_apply read and apply edits in the library with undo, lock checks and persistence notifications; Apply is then a notification the host must not apply again. Common style edits still reach the unlocked selection, tool inputs reach matching tools, and coordinate edits affect only the opened drawing. Save as default retains per-tool properties in DrawingManager::tool_defaults; the demo persists these through application storage. New drawings stay visible when the saved default came from a hidden drawing. DrawingTemplate is also available under drawings, with its existing UI import retained. Hosts own durable storage. Migration: remove the unused DrawingProps::show_price field; Fibonacci price labels are edited per level. DrawingProps literals add symbol, tool_settings, coordinates and save_as_default, or use ..Default::default(); construct CoordinatePoint through Default; dialog literals add error, and exhaustive PropertiesTab matches handle Inputs. (#142)

  • Indicator::value_format declares price, abbreviated signed volume, percentage or fixed-decimal units; scale chooses the main scale, an independent scale or an independent fit without labels. CustomIndicator sets both through builders. Pane axes, legends, cursor tags, tooltips and data-window rows share the format; settings precision overrides retain the units, and only price values inherit instrument precision. Built-in volume totals and percentage studies declare their units without changing placement. Independent overlays reserve separate left-axis gutters that shrink in narrow windows, share their mapping with selection and leave the main price range and magnet unchanged. Study units stay independent of instrument precision in overlay legends. Migration: add format to StudyValue literals. (#570)

  • Studies declare step lines, pitch-sized columns, crosses, areas, triangles, per-bar colours, bar/background colouring and bands between plots or levels. Both pane and overlay renderers share the geometry, preserve gaps and apply per-output offsets, including scaling and selection in visible future whitespace. Crossing fills split at their intersection without seams between bars; bar colours preserve candle bodies on inverted scales. Displaced values also drive last-value tags, alerts and drawing magnets; pane markers use the displayed range. MACD uses columns, Awesome Oscillator colours columns by momentum and Parabolic SAR uses dots; Bollinger and Keltner bands have a 20% fill. Existing Supertrend direction outputs and RSI level shading are retained. Migration: handle the new PlotType variants in exhaustive matches. Ichimoku values() now retains unshifted source calculations, including the latest leading spans; use plot_value for displayed values or plot_offset when drawing. Displacement counts the current bar, so 26 periods shifts 25 bars. (#165)

  • Placing or double-clicking a text annotation, note or callout opens an inline multiline editor. Ctrl/Cmd+Enter or a click outside commits one undoable edit; Escape discards the draft, and locked annotations cannot be edited. Long drafts scroll within narrow panes, and clicks inside the editor keep it open. Anchored text and notes retain a pane-relative position through pan, zoom, resize, dragging and persistence; older drawings adopt their first displayed position. Drawing::update_pane_coords and DrawingManager::update_pane_anchors support standalone rendering. Migration: Drawing struct literals must set screen_anchor: None, or use Drawing::new; saved files default the new field. Clones of anchored annotations move right by 2% of pane width. (#150)

  • Shift-click toggles drawings in a group selection. Dragging a selected body moves the unlocked group without panning or snapping to its own anchors; deletion, cloning, and demo property edits apply to the group with one undo step. DrawingManager::{selected_ids, is_selected, toggle_selection, edit_selected, paste_drawings} exposes the same operations to hosts. Chart::copy_selected_drawings returns versioned clipboard text with timestamp anchors, and paste_drawings validates it before adding fresh copies three bars to the right. The demo forwards native copy/paste events; clipboard text survives a lost session cache and maps to the current interval of the same symbol. (#148)

  • Study panes have draggable separators, maximise/restore controls and menus for ordering, collapsing, removal, merging and moving studies between panes or the main chart. Initial and resized axis sizing retain the configured horizontal zoom policy. Heights survive collapse and maximisation; resizing keeps adjacent panes above their minimum size. Each pane has its own draggable price axis, double-click auto-scale reset, scale modes and inversion. Chart::move_indicator_to_pane exposes study placement to hosts. Indicator::pane supplies StudyPane defaults and reference levels without matching names; custom presentation wrappers forward it and implement set_overlay to accept placement changes. ConfiguredStudy already does both. Migration: RenderedIndicatorPane literals add mapping; use that complete mapping for vertical coordinates in manual, logarithmic, percentage and indexed scales. hit_test_pane_indicator takes its range from that mapping; remove its two range arguments. Pane menu edits and study placement participate in chart undo and redo. (#89)

  • Chart::save_drawings exports the current symbol to DrawingStorage; load_drawings restores a JSON file with the chart’s time mapping and returns its skipped records. Restoring can run before history arrives and rejects a different symbol without changing drawings. Loading preserves drawing controls, and saving rejects timestamps that loading cannot retain. The demo saves and restores per-symbol drawings through application storage. Filesystem, accounts and cloud storage remain host-owned. (#373)

  • Chart settings Save as prompts for a name. SettingsDialog::templates exposes its serializable settings catalog, and ui::dialogs::templates::{TemplateStore, TemplateDialog, StudyTemplate, DrawingTemplate} supplies named save, list, load and delete for host chart, study and drawing templates through Storage. Documents are versioned, writes wait for reads and outstanding requests, failed saves retain edits, failed deletes retain rows, and unreadable or unknown-version catalogs cannot be overwritten. The demo connects its settings dialog and study and drawing toolbar intents to application storage; drawing templates edit selected drawings without changing anchors or identity, and study templates retain typed inputs and presentation. Long names and catalogs fit short and narrow windows. Accounts and remote storage remain host-owned. Migration: replace ui::model::{TemplateManager, SettingsTemplate} with TemplateStore<ChartSettingsState>; handle the new StoreKind::{ChartTemplates, StudyTemplates, DrawingTemplates} namespaces in host storage and DrawingToolbarAction::ManageTemplates to open a template catalog. (#199)

  • studies::Volume, registered as “Volume”, draws up/down columns with an optional SMA or EMA, editable length, open or previous-close colouring and price-overlay or separate-pane placement. An unchanged close counts as up; the first previous-close comparison uses the bar’s open. Volume uses its own zero-based scale, 80% pitch columns and a one-pixel moving average with a magenta value tag. The demo uses a 12% overlay band. (#572)

  • With the studies feature, ChartConfig::show_volume adds a default Volume study on the next frame; disabling it removes that study. User actions restore its settings and pane placement through undo and redo. Its stable id is available through Chart::indicators for editing or removal; closing it clears the volume switch. Hosts supplying their own Volume study can turn off the default switch before adding it. Widget-only builds retain the volume band. Indicator::is_volume identifies the three volume outputs for independent scaling and interaction; custom study wrappers forward it.

  • Chart::undo, redo, can_undo and can_redo share one ordered history for user drawing edits, study additions/removals/settings, chart type, interval and chart settings. Shortcuts, chart navigation buttons and the demo toolbar use this history; navigation undo restores the prior view and scale. Host UI/intent handlers wrap edits in Chart::user_action (or paired begin_user_action/end_user_action); direct programmatic API calls and feed/data updates are not recorded. Unchanged actions keep redo; new user edits clear it. Undo restores the affected study or settings snapshot, preserves study ids and unrelated studies/drawings, and keeps drawing persistence notifications. Hosts use take_history_changed to synchronize controls and reload their own interval data after undo/redo. Migration: use the chart history API for chart Undo/Redo; DrawingManager history remains available for standalone drawing managers. (#108)

  • Chart::shortcuts and shortcuts_mut expose an editable ShortcutMap, seeded from config::KeyboardAction::shortcuts (egui::KeyboardShortcut values). The dispatcher consumes exact modifier combinations and shares bindings with menu hints and shortcut help. Earlier bindings take precedence in input and hints; shadowed bindings are omitted. take_shortcut_requests returns host actions, typed symbol and interval entry, and clipboard text; hosts supply their own dialogs, layouts and clipboard formats. dispatch_shortcuts lets the active chart run before toolbars, and suppress_shortcuts reserves a pass for host dialogs. The demo cycles keyboard focus through its visible chart slots, wires these intents and keeps drawing copies for the current symbol and interval within its session. (#113)

  • Alerts retain a name, host watchlist, typed price, study, drawing or volume source and additional conditions required on the same bar. Conditions include channels, signed value and percentage moves and output comparisons; frequencies include once per bar and once per bar close. The shared dialog creates and edits model::Alert, accepts host catalogs and persists named presets through Storage. Its form fields fill the available control column, its default body height fits the editor, and smaller windows scroll before the shared Save/Cancel footer with validation feedback, in both themes. (#293) Old single-symbol alerts keep loading. Migration: Alert literals add name, source, watchlist and additional_conditions, or use Alert::new; AlertCondition is no longer Copy. Dialog Create carries Box<Alert>; replace the old string form structs and tab-specific data with AlertDialog::alert, sources and watchlists; AlertDialog::open(symbol, price) now requires the last or hovered price; AlertTab and the obsolete AlertData alias are removed; use model::Alert. AlertDialogConfig retains only width and the maximum scrolling-body height. Handle AlertPanelAction::EditAlert and the new condition, frequency and StoreKind::AlertPresets variants. (#207, #209)

  • Chart::study_values_at returns each visible plot’s title, value, precision and colour, retaining gaps as missing values. DataWindowInfo::from_chart populates OHLCV, previous-close change, chart-formatted time and visible study rows from the hovered rendered bar, with latest-bar fallback. The demo uses this library population, and floating and tracking tooltips include the same study rows within their plot bounds. Price-based charts omit source-indexed studies. Migration: DataWindowInfo literals include studies or use Default. (#119)

  • TimeframeSelector::set_supported_timeframes restricts presets and custom choices to the connected source’s intervals, retaining unavailable saved preferences. Hosts update it when their source or symbol changes; None permits all intervals. TopToolbarAction::ChartStyleSelected now carries model::ChartType directly. Migration: consume that typed value instead of parsing a display string. (#103)

  • Interval-menu stars pin and unpin presets and custom intervals without selecting them. Add retains custom intervals without duplicate rows. TimeframeSelector::preferences and set_preferences exchange serializable TimeframePreferences for host user settings; unavailable favourites are retained. The demo saves and restores these lists through application storage. (#104)

  • widget::ChartLayout renders one to sixteen host-owned charts in grid presets or tabs, with active-chart selection, a two-point inside border, two-point row gaps and edge-to-edge columns. Each chart retains its feed, studies, drawings and scales. Its corner menu assigns named synchronization groups and detaches charts into immediate viewports, embedded when the backend cannot create native windows. ui::multi_chart re-exports the working container and its types. (#115)

  • Layout groups synchronize symbol and interval changes, crosshair timestamps, scrolling and zooming, explicit date ranges and drawing edits. Drawing anchors map by time between intervals; synchronization is limited to matching symbols and groups, preserves unrelated drawings and leaves host persistence queues intact. Hosts supplying bars directly replace them after synchronized symbol or interval changes.

  • The top toolbar shows the grid selector beside indicator templates and a named-layout menu at the right. LayoutAction::SelectGrid selects presets; save, save-as, rename, open and delete actions are host intents. The demo owns session layouts in a tab strip, routes its toolbars and range bar to the active chart and gives new charts independent synthetic subscriptions without regenerating their common history. Persistent and cloud storage remain host-owned.

  • Migration: exhaustive ChartLayoutMode matches must cover the new five and seven through sixteen chart presets and Tabs; exhaustive LayoutAction matches must handle SelectGrid. ChartSyncOptions literals must add sync_date_range or ..Default::default(). LayoutMenu now emits save and catalog intents without mutating host-owned names or lists; update curr_layout and layouts after handling an action. Its initial name is Unnamed and its initial catalog is empty.

  • Price-based chart settings offer BoxSizeMethod::Fixed, Wilder Atr { period, multiplier } and Percentage for Renko, Kagi, Point and Figure and Range. Chart::set_chart_type_params resolves the selected methods from loaded history, waiting for the ATR seed when needed, then freezes the sizes through streaming updates, corrections and feed prepends. Reapplying parameters or replacing the dataset with set_data recalculates them; changing the symbol or interval reloads history and recalculates too. Percentage uses the absolute latest close, with 1 meaning 1%. Renko, Kagi and Line Break accept PriceBasedSource::Close or HighLow; without intrabar ordering, a continuation takes priority when both thresholds are crossed. renko_wicks paints the brick’s actual high and low; close input tracks close extremes and high/low input tracks bar extremes. The Symbol tab edits these parameters, which serialize with chart type settings. Migration: chart parameter literals add the method, source and wick fields or use defaults; RenkoConfig, KagiConfig and LineBreakConfig literals add source or use their constructors; RenkoBrick literals add high and low. SeriesSettingsAction::Apply carries its settings in a Box; callers constructing that action wrap settings with Box::new, and readers can borrow or dereference them. RenkoConfig::from_atr and KagiConfig::from_atr now use Wilder smoothing and require a complete seed instead of averaging the latest ranges. (#633)

  • ChartTypeParams::styles retains independent line, step line, marker, area and baseline colours, widths and line styles; Area has separate top and bottom fill stops, Baseline has separate line and fill colours on each side, and markers have a configurable radius. The series settings Symbol tab edits the current type. Chart::series_settings reads the current values for opening the dialog, and applying them leaves candle colours independent. Chart types, parameters and styles support serde for host-owned saved settings. Migration: ChartTypeParams literals add styles or use ..Default::default(); SeriesSettings literals add chart_type and chart_type_params, or use the defaults. (#562)

  • Visible study outputs have last-value axis tags in their line colours, including separate panes and left axes; hiding both axes hides their tags. Tags are 15 px high at the default axis font size. Colliding tags move to the nearest free row. High/low and host bid/ask labels and lines have independent switches, and volume uses a magenta axis tag. Countdown labels advance with the feed’s server clock, respect session closes and calendar months, and accept Chart::set_server_time and set_bar_close_time for direct-data and irregular-session hosts. set_right_margin and the settings dialog apply scale margins; the quick ratio-lock checkbox reaches the scale engine. Migration: ChartConfig literals need show_bid_ask, show_high_low and lock_price_to_bar_ratio, or ..Default::default(). Study ticks, legends and axis tags share StudySettings::precision; bounded RSI and Stochastic presets retain two decimals by default. (#112)

  • Right-clicking either price axis or the time axis opens scale and session controls through ChartMenus. Price menus apply auto/manual scale, regular, percent, indexed and logarithmic modes, inversion, placement, label visibility and a price-to-bar ratio lock; time menus apply UTC, local or exchange time and session choices. PriceScale exposes the ratio lock for hosts composing their own controls. Long axis menus scroll inside short windows. (#110)

  • Price axes show the instrument currency in a tick-sized button above their labels. The menu checks the current currency and emits host conversion choices through Chart::set_currency_choices and take_currency_choice; hosts supply converted bars and metadata together. chart::render_axis_currency supports composed axes. (#734)

  • ObjectTreePanel::apply_to_chart applies drawing and study visibility, locking, duplication, removal, selection operations, one-step layer moves and drawing focus. Bind series rows with SourceItem::with_series_id, using SeriesId::MAIN for the data source. Drawing names live in Drawing::label, survive storage and participate in undo; the shared prompt renames drawings. Layer moves are one undo step, including tied layers, and drawing copies have their own undo and save entry through the shared manager creation path. Selected drawings show handles together. Property dialogs and colour gestures remain host intents. Migration: SourceItem literals set series_id, Drawing literals set label, and exhaustive matches on DrawingCommand handle Reorder. Constructors use the defaults. (#149)

  • Chart::set_main_series_visible hides the price series, volume, readout and hit targets while retaining its bars, studies and drawings; is_main_series_visible reads it. The object tree’s main-series eye uses this operation. Main-series removal and duplication are not offered.

  • Duplicating a study from the object tree retains its input caption. Locked drawings can be hidden or renamed while their geometry and style remain protected.

  • AlertsPanel connects to a host services::Alerts with set_service, lists host-reported states and retains the latest 10,000 triggers with CSV export. Call poll(ctx, &mut toasts) each frame, including while hidden, and render that shared notification list once. Stream recovery preserves pending save and removal replies. Creation returns AlertPanelAction::CreateAlert for the shared dialog; save submits the completed model::Alert, and ExportLog carries CSV for host delivery. The demo supplies session-only storage. Migration: replace show(ui, &AlertManager) with show(ui), attach a service and poll each frame. The obsolete alert types and AlertManager in ui::model, inline forms and getters, AlertType, AlertStatusWidget and AlertNotification are removed; use model::Alert, the shared dialog and notification components. AlertsPanelConfig now contains only max_height. (#208)

  • Chart::bar_clock shares the resolved chart, exchange or system-local calendar with host rebuilds. BarClock::with_timezone and with_local_timezone align intraday and calendar windows, including repeated hours and short or long days. HistoryRequest::clock and Subscription::clock give hosts the same boundaries as the chart; changing the chart timezone reloads the series. resample and aggregate_trades accept either a timeframe for UTC or a supplied clock. Migration: inline parsed arguments to those functions specify .parse::<Timeframe>(); subscription destructuring includes clock or ...

  • Sink::advance_time opens an empty current time bar on a trusted feed heartbeat, carrying the last close with zero volume until the first execution sets its OHLC. Count intervals wait for executions. data::aggregate_trades rebuilds chronological trade history with the same aggregation, validation and duplicate-id rules as the live sink.

  • The native and web demos backfill to the current clock and stream deterministic synthetic trades and best bid/ask quotes through the public feed API. The default one-minute candle grows on every execution; the interval menu rebuilds second and count bars from a bounded trade buffer, with seven days of minute history built from the same executions for coarse views. Session filtering uses the instrument windows and the chart’s extended-hours choice. A small pause/resume control freezes the feed. The footprint sample pauses streaming while it is inspected. Timed repaints follow executions and countdown seconds, with no worker thread.

  • Chart::set_feed_paused suspends requests and unsubscribes while a host supplies replay bars. Resuming reloads the selected symbol and interval from the host feed. The demo retains replay when switching intervals and restores the preceding pause state when leaving replay.

  • Timeframe::Ticks(NonZeroU64) and the interval menu offer 1, 10, 100 and 1000 execution bars. Sink::push_tick counts accepted trades across frames, retains exact OHLCV and keeps replayed ids from consuming a count. Replaying retained executions rebuilds the partial final bar when changing intervals. Count bar timestamps keep nanosecond precision, advancing by one nanosecond when opening times would collide. Migration: exhaustive Timeframe and TimeframeUnit matches need a tick arm. duration_ms() and duration() return zero for count intervals, which have no time duration; check the variant before stepping time. Timeframe::all() continues to list time intervals only.

  • Applied studies expose typed StudyInput schemas and validated setters, including independent average-combination lengths, formulas and sources. IndicatorSettingsDialog stages Inputs, per-plot Style and interval Visibility edits; Apply targets the original study id and Cancel discards them. ConfiguredStudy applies complete edits atomically and retains serializable StudySettings, per-plot colour, width, stroke pattern, line/histogram/circle geometry, visibility and precision. Charts wrap studies once, report legend and pane settings intents through take_indicator_settings_request, and exclude hidden plots from scaling, snapping and selection. Hosts supply schemas for their own studies and persist settings themselves. The demo’s existing settings action edits the selected study. (#169)

  • IndicatorDialog::preferences and set_preferences export and restore serializable IndicatorPreferences, including favourites for temporarily unavailable host studies. Hosts save this value in their user settings when ToggleFavorite fires; the library owns no storage. Study defaults, editable Keltner and Stochastic parameters and tab filtering were already corrected in #692. (#170)

  • MACombination combines two to fourteen AverageLines with independent simple, exponential, weighted, Wilder, volume-weighted or Hull formulas, lengths, sources and colours. MACross, EMACross and MultipleMA share its calculations with their existing defaults. The factory adds SMA/EMA Cross, Triple MA and MA Ribbon; the ribbon has twelve evenly spaced lengths, individual direction colours, a thicker slowest line and a fading purple bottom fill, with a muted variant available directly. Crossing markers identify changes of side, ignore touches and disappear when a live correction cancels the cross. (#549)

  • LinearRegressionChannel fits the trailing window with upper, middle and lower lines, residual deviation bands with an n - 1 denominator, selectable price source, Pearson correlation label and optional right extension. Updates clear expired bars and refit the trailing window on every live change, independently of history length. Right extensions project prices before mapping to the axis, including logarithmic and inverted scales. Drawings share the same headless least-squares maths. (#548)

  • Charts pass instrument time zones and sessions to studies when added and when metadata arrives or changes, so a dialog-created VWAP follows the exchange session. Clearing metadata restores the study’s configured time zone and session. VWAP supports quarter and year anchors, percentage bands, and with_event_anchors for earnings, dividend or split timestamps supplied by the host. Event anchors reset on the first bar at or after the timestamp, including after a market gap. (#163)

  • data::Footprint, FootprintBar and FootprintLevel aggregate chronological executions per UTC bar and integer price row, with separate bid, ask and unknown volume, intrabar delta extremes, POC, contiguous value area, horizontal and diagonal imbalances and inclusive trade-size filtering. Invalid, out-of-order or overflowing executions return an error without changing the aggregation; executions with unknown aggressor never contribute to delta.

  • studies::trade_delta computes exact execution-based delta and cumulative delta candles, with host-defined session or period resets and independent rolling volume and delta totals. chart::series::render_trade_delta draws, in a supplied pane, delta histograms, per-bar candles (TradeDeltaStyle::BarCandles) or cumulative candles (TradeDeltaStyle::CumulativeCandles). A per-bar candle opens at zero, closes at the bar’s delta and has its wick from the lowest to the highest running delta of the bar’s executions, carried as TradeDeltaValue::delta_low and delta_high, so the wick spans the bar’s own range even when earlier bars leave a non-zero cumulative total. The existing bar-estimated CVD remains available separately. (#1480)

  • chart::overlays::render_footprint draws up to four bid/ask, volume, delta or delta/volume columns per bar, with profile or cell fills, volume, delta or imbalance colours, POC and value-area highlights, manual or automatic row grouping and cached text layouts hidden below the minimum row height. Both dominant diagonals retain their side colours, and sub-unit volumes stay nonzero in labels. Chart::show_footprint replaces the price series while keeping the legend, cursor and studies above it. The demo’s Menu exposes a Footprint toggle using deterministic synthetic executions from its fixture; turning it off restores the previous time scale.

  • studies::footprint_studies identifies stacked diagonal imbalance zones, unfinished auctions, naked POCs, delta POCs, volume clusters strictly above the configured volume share and small extreme prints using a host-supplied size threshold. Stacks and naked POCs extend until the first later traded range revisits them. chart::overlays::render_footprint_studies and render_footprint_statistics paint the annotations and per-bar volume, bid, ask, delta, delta extremes, cumulative delta, delta percentage and ask/bid ratio.

  • data::Sink::push_quote coalesces best bid/ask quotes per frame and connects the latest matching quote to the chart legend. Invalid, mismatched or older quotes do not replace the current or pending quote; reloading the feed clears it.

  • Drawing::pitchfork stores per-level colour, visibility and line style, with mirrored levels at 0, 0.5, 1 and 1.5 and filled bands by default. Hidden levels remove both adjacent bands. Old drawings use the defaults. Parallel channels support channel_midline, fill_color, extend_left and extend_right, with selection following the lines and filled area. Migration: Drawing struct literals set pitchfork and channel_midline, or use Drawing::new.

  • Session::with_extended_windows and with_holidays describe host-owned trading hours and closures. ExchangeSessionProvider starts each trading date at its earliest regular or extended window, handles overnight sessions, and resolves repeated opens to their first instant and missing opens to the clock jump. Chart::set_session_provider accepts host break logic.

  • Extended-hours bars are shaded independently of session dividers, including throughout a repeated hour after an overnight open. ChartConfig::show_extended_hours switches shading off, and extended_hours_color overrides the faint active-theme accent. Migration: chart configuration literals need these fields or ..Default::default().

  • Chart::set_extended_hours chooses regular hours or regular and extended hours, reloading history and the stream together. HistoryRequest::extended_hours and Subscription::extended_hours carry that choice to the host feed, including older history pages. Migration: add extended_hours to request and subscription literals and destructuring, or use .. when ignoring it in a pattern. Feeds must honor the field (false requests regular hours); hosts supplying bars directly replace their data after a choice.

  • Chart settings now retain and apply title format, quote controls and independent study title/input/value visibility. Chart::set_indicator_inputs supplies study input captions, retained through host templates; status-line volume no longer hides the histogram. The settings dialog keeps one top edge across tabs through Modal::top.

  • Price scale placement and independent current/previous close labels and lines now reach rendering on either axis. Countdown visibility is honoured, with its default enabled to retain the existing displayed countdown. Migration: add ..Default::default() to ChartConfig, settings_menu::data::StatusLineOptions, ScalesAndLinesSettings and IndicatorPaneConfig literals, or set the new visibility fields explicitly. Construct Legend with Legend::new and set its public fields; it has no Default implementation. Previous close is the last bar before the latest trading date.

  • TopToolbar::indicator_templates accepts host-owned saved study names and ids. Its anchored menu emits save/apply intents; the demo keeps cloned study sets in memory for the session. Migration: replace TopToolbarAction::OpenIndicatorTemplates matches with SaveIndicatorTemplate and ApplyIndicatorTemplate(id) handlers. Opening the popup emits no action.

  • Symbol::with_market supplies an exchange and optional instrument kind for symbol search. Empty queries list the host catalog, with host-supplied recents first, category chips for available kinds and kind/exchange metadata in each row. Migration: Symbol struct literals need exchange and symbol_type, or use Symbol::new.

  • TabBar::pills renders rounded tab chips through the shared tab component; the indicator browser uses them.

  • top_toolbar::buttons::toolbar_tooltip attaches compact toolbar tips with optional platform shortcut chips. Modal::rounding and Modal::fill preserve per-dialog styling, and an empty modal title lets a search row serve as the header.

  • Chart::set_instrument, set_legend_badge, set_legend_statuses and set_quote connect host metadata and current bid/ask to the responsive legend. Historical OHLC and study values follow the pointer independently of quotes, including over the axis add cell. take_quote_action retains buy/sell intents until taken; changing symbols clears supplied metadata and quotes. The demo labels generated data with SIM and records quote intents without submitting orders.

  • Chart::set_session_quote and set_events connect independent session prices and event badges. take_event_click and take_scale_settings_request route clicks to the host; the price-tag add cell opens the existing context menu at the displayed price, including in Magnet mode. Current close tags include a countdown when a supplied quote belongs to that bar, and volume has a separate tag at the pane bottom.

  • CrosshairStyle::Demonstration and CursorType::Demonstration draw a fading pointer trail that expires while stationary. TooltipOptions::on_long_press restricts values to a held pointer, waiting half a second for touch; the floating panel shows OHLC, absolute and percentage change from the previous close, and volume, with one snapped guide and hollow series points. Chart::set_tooltip_enabled connects the values switch. Migration: exhaustive cursor matches need a Demonstration arm; tooltip struct literals need on_long_press or ..Default::default().

  • The demo exposes the hovered Data Window in the right rail, quick search, a Trade intent notice and Publish through the existing export dialog. show_data_window is exported for hosts that display it independently of the object tree.

  • icons::COMPARE_ADD and icons::LAYOUT_SINGLE provide original comparison and single-pane layout glyphs.

  • chart::render_event_band draws host-supplied Markers as 22 px badges above a supplied time-axis baseline, aligned to the first bar at or after each event time. It uses the event’s text, colour, tooltip and ID, and returns the clicked ID to the host. Events outside the supplied data or plot are left out; existing bar annotations keep their appearance.

  • chart::render_quote_tags paints independent current close, host-supplied model::quote::SessionQuote and abbreviated volume readouts, separating colliding tags and returning each rectangle for input and tick occlusion. chart::price_axis_width measures ticks and supplied formatted tag labels. Row spacing follows the host font, and off-scale prices do not hide the other quote values. Short panes keep the close before the session and volume rows. Hosts composing their own axes can route chart::crosshair_price_action to an add-at-price menu and chart::axis_settings_button to scale settings; the two controls require icons and return clicks to the host.

  • widget::Legend composes an in-pane instrument title, host badge and status marks, current outlined sell/buy quotes with spread, and collapsible volume and visible overlay study rows. Its bar and previous close are supplied independently of current quotes; quote clicks return QuoteSide for the host to handle.

  • TextSizes has separate chart_title, toolbar, ohlc, axis, price_tag and bottom_bar roles, defaulting to 16, 14, 13, 12, 12 and 14 points, with matching constants in styles::typography. scaled scales them with the general size scale; missing serialised fields use their defaults. Migration: add the roles to TextSizes struct literals or use ..Default::default(). Component call sites choose the roles independently.

  • WidgetBar::widgets accepts host widget icons, names, ids and top or bottom grouping. Clicks return WidgetBarAction::WidgetClicked(id) and switch the active entry independently of the built-in panels. The bar scrolls when its entries do not fit. Migration: an exhaustive match on WidgetBarAction needs a WidgetClicked arm.

  • Chart::set_price_lines(series, lines) draws horizontal lines at prices on a series, such as an entry, a stop or a target. A model::PriceLine has a price, a colour, a width, a line style, an optional title and a price axis label that can be turned off. The lines follow the series’ price scale in every mode, are hidden while their price is off the scale or not finite, and label the axis in the scale’s units. The setter accepts every bar series. model::LineStyle is the line style of drawings and price lines; drawings::LineStyle remains a re-export of the same type.

  • Chart::scroll_to_time scrolls the bar nearest a time to the centre of the chart without changing the zoom. A time outside the data shows the nearest end, and with a feed, an older time loads history until it is reached. The demo’s go-to-date dialog uses it.

  • The chart draws navigation buttons in a row at the bottom of the main pane: zoom out, zoom in, scroll left, scroll right, reset, and auto-scale, logarithmic and percent toggles that show the price scale’s current state. Zoom moves by KeyboardOptions::zoom_step around the right edge, scrolling by the visible bar count. ChartConfig::navigation_buttons (NavigationButtons::Always, OnHover or Never, Never by default) sets when they show, and the chart settings dialog’s Navigation row edits it. Migration: ChartConfig struct literals must set navigation_buttons or use ..ChartConfig::default().

  • IndicatorDialog::open_tab opens the indicator dialog on a given tab; open opens it on the Indicators tab.

  • IndicatorDialogConfig implements Debug and Clone.

  • ui_kit::modal::Modal::height fixes a modal’s outer height for content that fills it, such as a list in a scroll area. The modal keeps 24 px free above and below it in the window and follows the window when it shrinks; min_height sets only a floor, so filling content keeps a modal at its largest size.

  • studies::PercentageVolumeOscillator, registered in IndicatorFactory as “PVO” with lengths 12, 26 and 9: the percentage oscillator of volume, its signal line and its histogram.

  • Columns chart type: one column per bar from the bottom of the price pane to the close, coloured by the close versus the previous close.

  • ui_kit::EmptyState::icon shows an icon above the message, EmptyState::action adds a primary button below the text, and EmptyState::fill_height centres the empty state vertically in the rest of the Ui. The message is in the normal text colour at the body size; only the description is muted.

  • icons::DUPLICATE, two overlapping squares, which the floating selection toolbar’s Duplicate button shows.

  • tokens::SizingTokens::control_height, the minimum height of egui’s built-in controls, 18 in DESIGN_TOKENS; apply_to_egui applies it.

  • Theme::high_contrast() is a distinct preset: black surfaces, white text, every text colour except disabled text at 7:1 or better on panels and windows, control outlines at 4.5:1, and a light blue accent with black text. It was a copy of the dark theme.

  • Theme::with_accent sets the accent and derives its hover and pressed shades, the black or white text on it, and the selection colours. theme::presets() lists the three presets by name.

  • Theme::text, Theme::spacing and Theme::radius hold the type, spacing and corner radius scales; apply_to_egui takes the window and menu margins, item spacing and window and menu corner radii from them. TextSizes::scaled multiplies the type scale.

  • The serde feature derives Serialize and Deserialize for Theme. The dark flag and complete colour palettes are required; omitted text, spacing and radius scales use their defaults.

  • data::Datafeed, a callback contract for market data: a feed answers instrument and history requests once through a data::Reply (dropping it unanswered reports FeedError::Unanswered) and pushes live bars, trades, status and errors through a per-subscription data::Sink, from any thread, runtime or browser task. The sink rejects a bar or trade whose slot opens more than one slot and more than a minute after the feed’s current time (two weeks for bars of a day or longer), the time being reported through Sink::set_server_time or else taken from the system clock. Pushes coalesce on arrival into one bar per time slot, so memory follows the bars that changed rather than the update rate. Supporting types: HistoryRequest, HistoryPage, Subscription, SubscriptionId, FeedStatus, FeedError, FeedState and MaybeSend in data, Instrument and BarClock in model. FeedError’s messages name no source, since the host services answer with it too: NotSupported reads “not supported” and Unanswered reads “no answer”. A bar of a day or longer is identified by a period of HistoryRequest::clock, in UTC by default, such as its day, week from Monday or calendar month, so a feed stamps it inside that period, for example at midnight on its trading date, rather than at a session open on the evening before.

  • model::Bar implements PartialEq.

  • data::resample builds bars of a coarser interval from bars of a finer one, aligned to BarClock, so a feed that serves one base interval can back intervals such as 7 minutes or 2 hours. It returns None when the finer bars do not nest in the coarser ones, as 5-minute bars do not in 7-minute bars, or when the bars of one slot do not combine into a valid bar, as when their volumes add up to infinity.

  • theme::ThemeExt::active_theme, for egui::Context and egui::Ui, returns the theme last passed to apply_to_egui, or the dark theme if none was, so components resolve colours while painting.

  • tokens::UiSemanticTokens gains panel_bg_floating_dark, the fill of popups, menus and windows in dark themes. Struct literals of UiSemanticTokens must set it.

  • A theme toggle in the top toolbar emits TopToolbarAction::ThemeToggle.

  • Indicator::update(data, from) brings a study up to date after the bars from from onward changed or were appended, with exactly the values calculate gives on the same bars, and Indicator::is_incremental reports whether a last-bar update or an append costs time independent of the series length (an earlier change still recomputes in full). IndicatorRegistry::update_all updates every study. Both methods have default implementations (a full calculate, and false), so existing implementors still compile. SMA, EMA, BollingerBands, RSI, MACD, Stochastic, ATR, VolumeWeightedAvgPrice, OnBalanceVolume and SuperTrend update incrementally.

  • Icons CHECK, MINUS, CHEVRON_UP, CHEVRON_LEFT, CHEVRON_RIGHT, STAR_FILLED, CODE, USERS, CROWN, DATABASE, PENCIL and TEMPLATE in icons::icons.

  • ListItemContent::interactive lets content take its row out of pointer interaction. It defaults to true; a disabled ButtonContent returns false, so its row is neither highlighted nor clickable.

  • data::Sink::push_tick also keeps each trade, with its price, size, aggressor side and time, in a bounded store for order flow, and Datafeed::trades pages historical trades (TradeRequest, TradePage) so order flow can be rebuilt after a reload. The default answers FeedError::NotSupported. History and live trades join exactly when both carry the new Tick::id (an exchange trade id or sequence number that never repeats for the symbol), and a live trade whose id the subscription already took is dropped and counted in FeedState::repeated_ticks, so a feed may replay its last trades after a reconnect; without ids, trades at the boundary instant may be dropped but are never counted twice.

  • Order book depth on the Datafeed contract: Sink::push_depth_snapshot and Sink::push_depth_delta carry a sequence number; a gap, a delta before any snapshot or an invalid update clears the book until the feed pushes a new snapshot, which is asked for once through Datafeed::request_depth_snapshot. A delta numbered at or below the last one applied is ignored, whatever it holds. Deltas pushed while the book waits are held, up to 10,000 levels, and the snapshot applies those numbered above it, so a snapshot fetched while the stream runs heals the book. A level with size 0 is removed, and a book is limited to 10,000 levels per side. Rejected updates are counted in FeedState::rejected_depth.

  • model::Instrument describes the full name (description), exchange, instrument type, tick size, price decimals, currency, exchange time zone (model::TimezoneId) and trading hours (model::Session, model::SessionWindow), each unknown by default and set with a with_ method.

  • Instrument::data_status (model::DataStatus: realtime, delayed or end of day), set with with_data_status. The legend marks delayed data with D and end-of-day data with E, in the warning colour ahead of the host’s status marks, and names the status on hover. (#77)

  • Instrument::supported_timeframes, set with with_supported_timeframes, lists the intervals the feed answers history for; None, the default, keeps every interval available. A chart does not ask the feed for history of an interval its instrument rules out: it shows no bars, does not subscribe, and reports FeedError::NotSupported through FeedState::last_error. A page asked for before the symbol resolved is dropped, and an instrument that allows the interval again asks for it. Pass the list to TimeframeSelector::set_supported_timeframes so that the interval picker offers only those intervals. (#699)

  • model::Tick implements PartialEq.

  • DialogFooter::danger fills the primary action with the danger colour.

  • scales::TimezoneMode, the time axis timezone mode, now lives next to the time formatters that use it. config::TimezoneMode remains as a re-export of the same type.

  • ChartState::revision identifies the bars before the last one: it changes when one of them is corrected or bars are removed, and stays the same when bars are appended or the last bar updates.

  • Per-drawing settings: Drawing::volume_profile (drawings::VolumeProfileConfig, 1 to 1,000 price rows and the value area’s share of the volume, 24 rows and 70% by default), Drawing::regression_trend (drawings::RegressionTrendConfig, the band distance in standard deviations, above 0 and up to 10, 2 by default) and Drawing::position_size (drawings::PositionSize, a fixed quantity, or the quantity that loses a given amount or a percentage of an account size at the stop). None uses the defaults. The constructors of the two configs reject values out of bounds; a position size out of bounds reads as n/a.

  • Drawing, DrawingToolType, LineStyle, ArrowStyle, FontWeight, TimeframeVisibility, FibonacciLevel, FibonacciConfig, VolumeProfileConfig, RegressionTrendConfig and PositionSize implement serde Serialize and Deserialize. A tool type is written as its variant name; a Drawing leaves out its id, points and completion state; the volume profile and regression trend settings are checked against their bounds on load; the per-timeframe visibility set is written sorted, so saving the same drawings gives the same file.

  • services::Storage, a callback contract through which the host keeps named JSON documents for the library: it lists, loads, saves and deletes the documents of a services::StoreKind (Settings or Drawings) and answers through a data::Reply, from any thread, runtime or browser task. Nothing calls it yet. (#198)

  • services::SymbolSearch, a service the host implements to answer symbol searches from any source of instruments, separately from the feed: it takes a services::SymbolQuery (the typed text, optional instrument type and exchange filters, and a result limit) and answers with Instruments through a data::Reply. Vec<Instrument> implements it: it matches the text against symbol and description ignoring case, applies the filters, and lists an exact symbol first, then symbols that start with the text. Nothing calls the service yet. (#380)

  • services::Broker, a callback contract for one trading account at the host’s broker, real or simulated: it places and cancels orders, answering through a data::Reply, and pushes the account, orders, positions, executions and connection status as services::AccountEvents into an Events stream. The trading model is in model: OrderType, OrderRequest, Order, OrderStatus, Position (signed net quantity), Execution, Account and Capabilities (the order types the account accepts). The library holds no balances or positions. Nothing calls the service yet. (#216)

  • services::Signals, through which a host supplies markers, levels and zones from its own analytics (model::Signal, SignalShape, SignalId, Direction) as services::SignalEvents, pushed from any thread into a services::Events stream that holds at most 10,000 pushes between frames and ends when it lags or the chart stops listening (#381).

  • model::StrategyReport describes a strategy run from any source: its trades, each with the net profit the host computed, its equity curve and the settings to show. StrategyReport::performance computes the metrics with one definition each: net, gross and average profit, profit factor, win rate, maximum drawdown in money and as a fraction of the peak, and the Sharpe and Sortino ratios, annualised by the steps per year the equity curve covers and unavailable for a curve spanning less than 13 weeks. An undefined metric is None, invalid trades and equity points are skipped and counted, a non-finite number is saved as null in JSON and loads back as NaN, so a report with one loads with the same metrics, and StrategyReport::trades_csv exports the valid trades. Supporting types: StrategyTrade, StrategyExit, OrderSide and StrategyPerformance.

  • services::Alerts, through which the host keeps and evaluates price alerts: it pushes its alerts, their changes and their triggers as services::AlertEvents into a services::Events stream, including triggers that fired while the application was closed, and saves or removes the alerts the user edits, answering through a data::Reply. The alert model (model::Alert, AlertId, AlertCondition, AlertFrequency, AlertStatus) is serialisable so a server can store and evaluate the same type. The alerts panel consumes the service. (#211)

  • The Negative and Positive Volume Index plot their signal line, the 255-bar EMA of the index seeded with its first value, so it starts at bar 0 like the index. The index is unchanged. Migration: NegativeVolumeIndex and PositiveVolumeIndex output IndicatorValue::Multiple(vec![index, signal]) instead of Single(index), and report two lines and two colours; code that matched Single reads the index as the first value.

  • AlertKind::color and ToastKind::color return the theme’s status colour for an alert or toast kind.

  • MessageKind::Warning: status_message draws it in the theme’s warning colour. Migration: a match on MessageKind needs a Warning arm.

  • TopToolbarState::can_undo and can_redo disable the top toolbar’s undo and redo buttons, whose tooltips then read “Nothing to undo” and “Nothing to redo”; both default to true. Migration: struct literals of TopToolbarState set both fields or use ..Default::default().

  • Chart::set_data(series, bars) replaces the bars, for history or a replay window, and Chart::update(series, bar) merges one bar by the rules a feed’s Sink::push_bar follows, matched by open time, or by the slot of the timeframe for a chart built with a feed: a bar that matches a stored bar replaces it, a newer one is appended and an older one is inserted in order. Chart::bars(series) reads the bars, and Chart::feed_state(SeriesId::MAIN).rejected_bars counts the bars dropped as invalid. Only SeriesId::MAIN holds bars; a call with another id is ignored with a warning. SeriesId is re-exported from widget.

  • Chart owns its studies and drawings. Chart::add_indicator computes a study at once and returns a SeriesId that stays valid when other studies are removed; remove_series, set_indicator_visible, indicators and indicator_mut take that id. Chart::drawings and drawings_mut give the drawing manager. ChartElementId is re-exported from widget.

  • Chart::config, Chart::chart_options, Chart::price_scale_mut, Chart::set_markers(series, markers) and Chart::state give access to what the public fields held.

  • The bare_chart example shows one candlestick chart on generated sample data, with a live tick every frame and a new bar every 60, built from the widget feature alone: cargo run --release --example bare_chart --no-default-features --features widget. The bare_chart bench runs that example’s frame headlessly and prints its median and 95th percentile time: cargo bench --bench bare_chart --no-default-features --features widget.

  • CI checks the bare-chart build: on ubuntu-24.04 with the MSRV toolchain it builds examples/bare_chart.rs and benches/bare_chart.rs with --no-default-features --features widget and fails when the stripped size of the example grows by more than 1%, or the instructions of one bench frame under Cachegrind grow by more than 2%, over the figures committed in benches/bare_chart.baseline. The job summary reports both figures with the unchecked median and 95th percentile frame time and prints the baseline lines a pull request commits to accept growth. (#441)

  • The frame_time bench renders one chart of 5,000,000 bars zoomed out and zoomed in, four charts of 100,000 bars and eight charts of 100,000 bars with ten studies each, headlessly on sample data, and prints the median frame and tessellation time of each as a Markdown table, then the first frame and the median and 95th percentile of steady frames, of frames with a tick on the last bar and of frames with a new bar, for candles and the Renko, Kagi, Line Break, Point and Figure and range bar charts on 1,000,000 one-minute bars: cargo bench --bench frame_time. CONTRIBUTING.md describes how to compare two commits with it.

  • The stream bench feeds one chart 10,000 trades a second from a thread, with 10 or 30 studies on 100,000 and 1,000,000 bars and frames paced at 60 Hz on the wall clock, and prints the median, 99th percentile and longest frame of each, and how often a study that does not update incrementally is recomputed: cargo bench --bench stream.

  • FloatingReplayControl::set_dock_rect docks the floating replay bar in a rect, usually the chart’s: the bar opens centred 8 px above the rect’s bottom edge and can be dragged only within it. Without a dock rect the bar docks in the window’s content rect.

  • ReplayColors::from_theme builds the replay colours from a theme, and ReplayColors implements PartialEq.

  • ui::context_menu::ChartMenus shows the chart, series and drawing context menus for any Chart (feature ui): call menus.show(ctx, &mut chart) after chart.show(ui) to open the menu for the last right-click and read the chosen action. While a menu is open the chart draws no crosshair or tooltip under it.

  • ChartBuilder::with_feed drives a chart from a data::Datafeed. The chart asks for the instrument and the latest page of history without blocking, applies answers and live updates once per frame, asks for older pages as the user scrolls back until the feed reports the end of history, subscribes after the instrument resolves and unsubscribes on every symbol or timeframe change and when it is dropped. A push from any thread wakes the UI once per burst. Chart::feed_state reports loading, live status, the last error and dropped updates. After a history or instrument error the chart asks for nothing more until the symbol or timeframe changes.

  • Chart::set_timeframe, Chart::symbol, Chart::timeframe and Chart::instrument.

  • Chart::trades and Chart::order_book hold the trades and the order book the feed pushes; the chart asks the feed once for recent trades (Datafeed::trades) and for a new book snapshot when the book is lost.

  • examples/live_feed.rs: a feed that serves pages of history and streams trades from a thread.

  • ui::Control and set_control_visible on TopToolbar, DrawingToolbar, TimeframeToolbar, WidgetBar, ChartMenus and SettingsDialog: a host hides the controls it has no service for, such as alerts, trading, replay, layouts, templates, compare, time zone, session or dividend adjustment. A hidden control is not drawn and emits nothing, and a menu of it that is open closes; every control starts visible. In the chart settings dialog, Reset to defaults takes the place of the hidden template button.

  • The drawing bar uses the chart’s shortcut map for tool keys and hints; standalone toolbars use DrawingToolShortcuts. DrawingToolShortcuts::help_text formats those bindings as key labels such as “Alt+T”. Chart defaults and migration are listed below.

  • A star in a drawing bar flyout row adds the tool to the favourites or removes it, without selecting the tool; a favourite shows a filled star in the warning colour.

  • ToolbarState::lock_all and ToolbarState::hide_drawings, hide_indicators, hide_positions and hide_orders hold what the Lock button and the Hide menu show: the lock button is filled with a closed padlock while lock_all is set, and the Hide menu checks each hidden group. The bar sets them from the clicks it reports; a host that changes the chart’s state elsewhere sets them too. Migration: struct literals of ToolbarState set the five fields or use ..ToolbarState::default().

  • Time-synchronised charts of different intervals stay readable. A synchronised range was stored on the receiver as bar spacing and offset, so a coarser receiver turned a short span into a bar wider than the plot, a finer one dropped to the spacing floor, and a range with no bar in it left the receiver blank; an interval switch then reinterpreted the stale spacing at the new interval and broadcast it to the whole group. Chart::apply_synced_time_range now ignores a range outside the chart’s loaded bar slots, stops the fitted spacing at the configured maximum, or 50 px when there is none, and centres short spans. A ChartLayout remembers each chart’s UTC edges, refits the chart to them once its bars for the new interval arrive and holds back its range broadcast until then; a chart still loading adopts the latest range the group broadcasts meanwhile, so its arrival does not pull every chart back to where it stood before the switch. The layout passes the active chart’s interval with each range, so charts of the same interval fit it as manual zoom does, bounded only by their configured maximum spacing, and only a receiver of another interval falls back to the 50 px cap. (#1538)

  • Chart settings keeps its top edge in place across tabs, and its controls and the shared dialog chrome follow the theme. The dialog centred itself on every tab, so its top edge moved from y 142 on Symbol to y 30 and y 200 on the others and the tab list slid under a stationary pointer; it now takes the top edge of its tallest tab, centred in the window and recomputed on resize. Checkboxes are 18 px and fill with the text colour when checked, colour wells are 34 px, section headings are muted, and outlines and headings use the theme’s border_control and text_muted. The dialog frame, title row, footer and sidebar take new insets, glyph size, button sizes and a 40 px row pitch, and the light dialog loses its outline for a tighter shadow while the dark and high-contrast dialogs keep theirs. Indicator settings scroll sideways instead of widening the dialog when their inputs, such as those of Vol Profile, are wider than the window leaves room for. (#1559, #1563)

  • Quick search and symbol search are restyled. Quick search leaves the chart undimmed, spaces its search rules 41 px apart, drops the redundant placeholder and sets its centred instruction in the heading text size, and the close glyph of the shared title row is larger. Symbol search draws 56 px rows with 36 px discs, highlights matching substrings and keeps its category pills on one scrollable line beside the source filter, where dense results and wrapping categories pushed matches down the chooser; the host’s exchange choices, recents and root drilldown are kept. Light themes use a light veil behind the dialog and dark themes keep the dark modal overlay, and comparison captions and the placeholder follow the theme’s text roles. (#1557, #1561)

  • Undoing the removal of the main series brings the series back and resumes its feed. Removing it recorded only its visibility, so undo consumed the step while the series stayed absent and its feed stayed stopped. The history now keeps the series’ presence, price lines, formatter and bar limit and exchanges them before restoring visibility, retaining its bars and per-symbol markers. The host’s pause setting is tracked apart from removal and from replay pauses, so undo and redo resume the feed when they should, including after replay ends, and snapshots omit the retained markers while the series is absent. (#1351)

  • Fibonacci circles, speed resistance arcs, wedges and the spiral are built from the right points. Circles are ellipses around the midpoint of the swing between the anchors, scaled by its width and height, so they are round for a swing drawn at 45 degrees. Speed resistance arcs are centred on the first anchor, the level 1 arc passes through the second anchor, and they open towards its side. Circles, arcs and wedge arcs draw each level in its colour with its ratio, can shade the bands between levels and join the anchors with a trend line in the drawing’s style, and a new wedge has no radius 0 arc. The spiral also draws the ray from the first anchor through the second to the pane edge, which it is constructed from. Selection follows the painted shapes. (#1382)

  • Fibonacci time zones, speed resistance fans and trend-based time show their levels evenly. Time zone lines look alike in their level colour, the zones are shaded only when the background is on, each zone number, 0 included, sits at the bottom beside its line without a box, and a trend line in the drawing’s style joins the anchors. On the speed resistance fan, level 0 is the diagonal between the anchors and level 1 the horizontal (price rays) or vertical (time rays) through the first anchor, in either drawing direction; price and time rays share each level’s colour, the ratios are labelled at the edges of the box between the anchors, and the arcs and the extra trend line are gone. Trend-based time draws a line through its three anchors, labels each level at the bottom and can shade the zones between levels. (#1381)

  • Fibonacci retracements, extensions and channels measure and draw their levels as a trader reads them. Retracements and extensions draw a trend line through their anchors in the drawing’s colour, width and line style, dashed on new drawings, and level lines take a width and a line pattern of their own, FibonacciConfig::level_width and level_style, set with Level width and Level style under Inputs. Bands lie between levels adjacent by ratio, whatever order the levels were entered in. Extension levels run from the second to the third anchor, start without Extend and can be reversed, and channel levels move the base line towards the third anchor in time as well as price, so level 1 starts at the third anchor. Labels show the level and its price through the chart’s price formatter and sit outside the construction, beyond the end of each level line on the side labels_on_left chooses (the left on new drawings), moving back inside the pane when that end is extended to the pane edge; new drawings label levels as ratios. Saved explicit settings, including saved extension choices, are kept, and selection follows the painted lines. (#1380)

  • Order-flow studies update incrementally past 10,000 bars. Once an order-flow input held 10,000 bars, every new bar dropped the oldest one and reset the input, so the chart recalculated every study on that input from the first bar, cleared the sibling studies waiting for their turn for a frame, and moved the cumulative delta of every closed bar by the dropped bar’s delta. An input now keeps up to 11,000 bars and then drops its oldest down to the newest 10,000, the longest span of a flow sum, so the reset and the full recalculation come once per 1,001 new bars, and a bar that crosses no drop updates the studies from that bar and leaves closed bars unchanged. A cumulative sum such as Size-Filtered CVD starts again from the oldest retained bar after a drop. (#1282)

  • The drawing bar’s glyphs are even in size and its group rules are inset evenly. Glyphs ranged from 15 to 28 px of ink, the first one started 13.5 px below the bar’s top edge and the group rules were 36 px wide at x 8. Every default glyph is now sized so that its ink spans 22 to 23 px on the longer side, the 38 px button pitch is unchanged, the Text glyph is redrawn as a taller T that measures 15 by 18 px, and the group rules are 33 by 1 px, inset 9 px from the left edge and 10 px from the right. (#1523)

  • Chrome ink, hover tiles, the legend and the panel ground agree across the light and dark presets. The light preset draws text and axis text in black, with muted labels at #696969, disabled text at #7e7e7e and a lighter grid at #e5e5e5 while the watermark keeps its tone, and the dark border, the ground between panels, becomes #2e2e2e while the toolbar and bottom bar rules keep #4a4a4a. Unavailable history icons use the disabled colour without an extra fade, the two Save actions have independent hover and keyboard focus targets, default toolbar controls are 34 points and active widget bar entries take neutral fills. The legend insets its readout by large spacing, eight points by default, shows every study input in one muted colour, and draws its title and collapse button in the UI ink with a rule derived from the panel and text colours. Default chart titles are 13 points and bottom bar labels 12 points, where they were 16 and 14; saved explicit sizes and host overrides keep their values, and missing saved roles take the new defaults. Migration: set chart_title to 16 and bottom_bar to 14 in TextSizes to keep the former defaults. The demo restores the panel gaps, reserving 52 points plus a four point margin for the drawing bar, and the chart’s radius four corner after the chart paints its rectangular background. (#1518, #1522, #1524)

  • TPO profiles give the same point of control and value area on every build. The point of control was the last tied row in hash map order, so the same bars gave a different point of control and value area from one build to the next. Ties now take the lower price, as footprint bars and volume profiles do; when the two rows above and the two below hold equal TPO counts, the value area grows by one row on each side, as a volume profile does; and single prints are sorted by price. (#1280)

  • The TPO initial balance starts from the session’s first bar. An initial balance high of exactly zero was taken to mean that no bar had arrived yet, so the balance restarted at the next bar on instruments trading around zero. The session’s first bar now opens the balance and later bars of the initial balance period only extend it. (#1284)

  • Automatic TPO rows are whole instrument ticks. Rows fitted to the visible range ignored the instrument’s tick, so rows, counts and the point of control fell between tradable prices. The TPO chart type, the Time Price Opportunity study and the profile menu now round the fitted row up to whole ticks, within one part in a billion so that a row of exactly n ticks stays n ticks; a row height pinned in the settings is used as set. (#1281)

  • The account panel shows the broker’s connection status. Trading::apply dropped AccountEvent::Status, so the account panel, the order ticket and the depth ladder looked the same whether the broker was live or had dropped, and a user learned of a lost connection only when an order was refused. Trading now keeps the last status the broker pushed on the current stream, and the account panel’s tab marks a broker that reports that it is connecting or disconnected with the library’s connection indicator, “Connecting…” or “Offline” beside the broker’s name, until the broker reports that it is live; the tab shows at every panel height, so a minimized panel shows the mark too. Each stream starts without a status, as it starts without the account’s state, so a new stream, a new broker and disconnect clear it. Trading::has_broker tells whether a broker is set, connected or not, and the demo uses it to show the account panel and to choose between the broker picker and trading. Broker::connect documents the contract: a stream starts as connected, a status that is not live is pushed again on each new stream, and the orders the user confirms while the broker is not live are still sent, for the broker to refuse what cannot reach it. (#1484)

  • The properties dialog of a freehand stroke no longer lists its samples as coordinates. A brush or highlighter stores one chart point per pointer sample, so its Coordinates tab listed every sample as an editable row, often hundreds of them, and editing one moved that sample out of the stroke. The tab is now left out for tools that draw continuously, following the tool’s interaction mode so that a future freehand tool follows without an edit, and DrawingProps::from_drawing stages no coordinates for them, so neither the dialog nor apply_to_chart can move a single sample; every other tool keeps the tab. Migration: hosts that moved single samples of a stroke through DrawingProps::coordinates edit Drawing::chart_points instead. (#1469)

  • A footprint passed to Chart::show_footprint no longer slows the frame on a chart zoomed out below half a point per bar. The cells of such bars have no horizontal area, yet the renderer walked every visible bar and grouped its executions; they are now skipped before the executions are looked up. The default minimum bar spacing and wider views draw as before, and with executions on each of 100,000 visible bars at a minimum spacing of zero the frame takes about 3.8 ms instead of about 166 ms; cargo bench --bench frame_time -- footprint-host measures it. (#1449)

  • Depth history pages that fill a gap are merged to the resolution of the tier they join, whatever order the pages arrive in. Gap-fill samples took coarse-tier slots one by one, so pages that arrived out of order used up the history’s capacity much earlier and shortened its span. Contiguous finer runs now merge as scroll-back pages do, including the completion of a short held column at the newer boundary. Tier boundaries and overflow timing can still leave small differences in the retained span between arrival orders. (#1424)

  • An empty heartbeat candle opens at the close of the newest bar before it after a history page. A heartbeat candle took the last close the stream pushed through its sink, and history pages are merged by the chart and never reach the sink, so after a page whose newest bar was newer than anything the stream saw, the next empty candle opened at the stream’s older close and showed a gap until its first trade. After each merge that changes bars, every empty heartbeat candle from the first changed bar on now carries the close of the newest bar before it that is not whitespace, whether the heartbeat was merged after the page or the page was merged under candles already on the chart, for chart and study series alike. A candle with no such bar keeps the close the sink seeded. (#1421)

  • The horizontal, vertical and cross line shortcuts place their line at the pointer, through the pane’s coordinate and snap mapping, where they only armed the tool. A shortcut pressed with the pointer off the chart only selects the tool, and hovering later places nothing. Alt+C selects the cross line and Alt+J the horizontal ray, which had no bindings. (#1409)

  • Measure is a temporary ruler. It left a saved, undoable drawing behind; it now stays visible until the next chart click or cancellation, outside the saved drawings and undo, and finishing it returns to the selection tool even in keep-drawing mode. Shift-click on empty space starts a measurement, and Shift-click on a drawing still toggles its selection. (#1409)

  • Dashed and dotted lines lying just outside a pane edge keep the half of their stroke that overlaps the pane. The shared dash clipping bounds followed the centreline only, so a stroke whose centre lay outside the edge lost the half inside it, and a shallow crossing of a border was shortened. Both bounds are now widened by half the stroke width and square dots are reserved with the same bound, so overlapping strokes show on all four edges and fully hidden strokes still do not. (#1433)

  • The order ticket and the depth tab size and colour their controls consistently. Ticket fields and menus share one height, the quote box balances against the primary action, the header icons and exit switches are larger, and the order-type rail and its underline have the same thickness in both themes. Field outlines are softer at rest while keeping 3:1 contrast on the field background, stronger on hover and in the accent colour on focus, which is painted only for the field’s own layer so that a popup overlapping a field does not draw it; the time-in-force styling no longer reaches later controls, and disabled light fields are filled. Switches and the quote box take neutral surfaces derived from the theme, labels are muted, and text sizes, button text colours and hover fills come from the theme. The depth ladder uses a 20 point row pitch with body-size prices and sizes, shorter position boxes and footer actions, market buttons without outlines and a filled margin tag for the prospective order type, and reserves the actual height of the quantity field so that the footer controls stay reachable. (#1526, #1527, #1531)

  • The standalone indicator pane example takes a CustomIndicator, so it compiles with the widget feature alone, and documentation links to items behind a feature the build lacks point to the feature table or name the feature instead of failing to resolve. (#1314)

  • Price tags on a scale without instrument precision take the decimals of the nearest tick label, at least two, instead of always two: the last price and countdown, the previous close and extended-session price, High, Low, Bid and Ask, price lines, study values and the tags of added series. A close of 1.08692 on a scale from 1.0845 to 1.0873 read 1.09. (#1221)

  • Study value tags and the High, Low, Bid and Ask tags and badges on the price axis choose black or white text for their fill, as price line tags do, so labels on pale fills such as gold and yellow study colours are readable. (#1273)

  • A dashed or dotted study line is dashed only where it can be seen. Study lines were split into dashes or dots along their whole length, including the part far outside the pane, so zooming the price scale in close to its minimum span stalled the frame; every further dashed or dotted line, such as the three Bollinger Bands lines, added the same cost. The patterns inside the pane are unchanged. In a 1,000 point pane, a dashed line crossing it from the scale’s top bound to its bottom bound paints about 100 dashes instead of 2,000,000. (#1338)

  • Drawing properties show Fill, Extend and the Text tab only for tools whose renderers use those settings. Edits preview on the chart while the dialog is open; Ok commits them as one undo step, and Cancel, Escape or closing restores the original properties without changing undo or redo. A Template menu in the footer saves named styles and the tool’s default, resets to defaults, and applies or deletes the saved templates of the same tool. Template rows no longer appear in the Hide flyout. (#1367)

  • Cyclic lines start at the first anchor and repeat only towards the second, using the drawing’s line width and style, without alternating fills or labels. Time cycles use closed half circles that honour the fill colour, without a period label; placement and handle drags keep both anchors on the first anchor’s baseline, with the second anchor changing only the period. Sine lines no longer draw centre and amplitude guides or labels. Cyclic lines and sine lines no longer offer a fill setting, since they paint no filled area. (#1390)

  • Table drawings use a plain theme background, equal-height rows and one-pixel grid lines and borders in the theme’s border colour. Cell text is left-aligned with padding and vertically centred, including the first row. Existing saved tables keep their cells and use the same appearance. (#1399)

  • Volume Footprint and Session Volume Profile charts zoomed out until several bars share a physical pixel draw the bars without executions merged, about one candle per pixel column as Candles charts do, instead of every bar; bars from the first execution on are still drawn from their executions. In builds without studies, the volume beneath a footprint from Chart::show_footprint merges the same way. A Volume Footprint chart with 1,000,000 bars in view paints 3,013 shapes instead of 2,001,055; cargo bench --bench frame_time -- "volume footprint" measures its frame time. (#1269)

  • A frame visits only the markers and time scale events near the view: the lists given to Chart::set_markers, Chart::set_events and Chart::set_time_scale_events are indexed by time when set, so the markers drawn, hit and fitted to the price scale and the event badges are found by binary search instead of by reading every item, and manual markers are no longer copied each frame when a mark source supplies bar marks. Markers and badges are painted in the order supplied, as before. cargo bench --bench frame_time -- "200,000 bars" measures the frame time with a marker or a news event on every one of 200,000 bars. (#1271)

  • Forecast drawings label both anchors with their price and date, format prices and the signed change with the instrument precision, and express the time to target in calendar units. Cards fit their text and follow the active theme; a success or failure badge appears below the target card only when decided. The forecast line ends in an arrowhead. (#1402)

  • Fixed range and anchored volume profile drawings leave more candles visible: the widest row uses one third of the measured span, the range has a faint tint instead of an outline, and up/down and delta rows outside the value area are dimmed. Anchored rows grow left from the pane’s right edge, with their width capped to one third of the pane when the anchor is offscreen. The point of control is a stronger solid line without a badge; value-area guides remain optional. Volume profile studies keep their existing presentation. (#1407)

  • Ghost Feed accepts any number of anchors and finishes on double-click or Enter. It projects one candle per bar with repeatable noise seeded by the saved drawing identity, uses tick-based average range and noise inputs, and paints translucent rising and falling candles along a thin grey path without a tag, permanent dots or a projection stub. Instrument tick size sets the price increment; without it, one price unit is one tick. Saved spacing and wick settings load with the new defaults. Migration: replace GhostFeedConfig::spacing and wick with average_range_ticks and noise_ticks; calls to GhostFeedConfig::candles now also pass the tick size and persistent drawing id. (#1404)

  • Ray and extended-line rendering, endpoint markers and hit areas now follow Extend left and right; new rays start extended right and new extended lines start extended both ways. Rectangle borders, fills and hit areas extend to either pane edge as configured. (#1372)

  • Regression trend selection handles sit on the fitted centre line and change only the bar range when dragged; the Coordinates tab edits time or bar coordinates without price fields. The Style tab exposes Fill and Extend. With Fill on, the channel fills its upper half in the fill colour and its lower half in the line colour; it draws solid boundaries in the accent colour at the drawing width and a dashed centre line, and Extend carries all three lines and both fills to the pane edge. A plain correlation value near the lower boundary replaces the boxed statistics. Existing saved bar ranges are retained. (#1378)

  • Sector drawings take the short arc between their radii in either direction, with the hit area following the same wedge. Projection move and target labels size their backgrounds to the text, so long prices stay inside their boxes. (#1405)

  • Trend angles show a signed angle with one decimal and a degree sign as plain text in the drawing colour and font size. The short horizontal guide and arc are dotted and share a radius that meets even a short leg. The label box, the permanent anchor and arc-end dots, the change and bar statistics and the unused fill setting are removed; selected handles and the first-anchor preview remain. (#1373)

  • Pattern, Elliott wave, cycle and Gann main lines honour the configured width, including 2 px, while ratio connectors, guides, grids and label outlines keep their own widths. Pattern and wave fills use the chosen colour and disappear when Fill is disabled, without recolouring their label boxes. Their point, wave and ratio labels use the configured font size, with backgrounds growing with the text. New tinted patterns, waves and Gann boxes store their tint as an enabled fill; tools without a fillable body no longer offer a Fill control. Other drawing families retain their configured body fills. Opening properties preserves an unchanged translucent fill, and version-1 patterns retain their saved line colour in their default tint. (#1370)

  • Disjoint channels mirror the first line’s slope through the third anchor over the same bars. Flat top/bottom channels end on those bars without overhang. Both draw only their two boundaries and the configured fill, without price or height labels, respect Fill and left/right Extend, and share their visible geometry with hit testing, including fills across a crossing. Parallel, flat top/bottom and disjoint channels offer a handle at each line end; the flat handles change only price, parallel boundary handles change width, and disjoint boundary handles keep the opposite ends fixed while mirroring the reshape. Disjoint drawing alerts follow the mirrored boundary on linear and logarithmic scales. Existing saved anchors use the corrected geometry without a storage migration. (#1377)

  • Bundled stickers retain their outline and eye colours when the drawing colour changes, and font icons and emoji no longer carry an extra dot. (#1401)

  • Pressing and dragging any unlocked drawing selects and moves it in one gesture without panning, in the price pane and study panes. Locked drawings and empty chart space still pan. Completed drawings are selected immediately, and drawing bodies and handles show pointer, move and resize cursors. Selection handles stay on anchors; rectangles replace their centre handle with four edge handles that resize only the grabbed side, and a body move remains one undoable edit. Migration: exhaustive matches on HandlePos add Top, Bottom, Left and Right. (#1364)

  • Time-scale spacing has a 0.000001 pixel floor, including when the configured minimum is zero or a positive maximum is smaller than the floor, so large or repeated zoom-outs leave finite scroll offsets and visible ranges and zooming back in still works. TimeScale::set_min_bar_spacing and set_max_bar_spacing ignore non-finite values and retain their previous limits. (#1349)

  • Finished drawings show their lines, fills and labels without permanent anchor dots or rings. Selecting a drawing still shows its editing handles, and placement previews keep their anchor dots. (#1363)

  • Indicator::plot_style and Indicator::line_style accept any line on every built-in study. MACD, PSAR, ADX Breakout, Rising Wedge, Falling Wedge, Knoxville Divergence, PPO, PVO, Woodies CCI and Elder Ray panicked on a line past their last, and so did line_style of MACombination and its presets, MA Ribbon among them; such a line now gets a style, also through the ConfiguredStudy that a chart and StudyTemplate::create return. (#1326)

  • A study template, a copied study and a saved layout recreate CVD, CloseToCloseVol, HL2, HLC3, PriceChannel, EhlersFisher and MACombination, and Chart::snapshot no longer fails on a chart that holds one: IndicatorFactory::create and has resolve their names, while list, category and count leave them out of the catalogue as before. MACombination has inputs for its number of averages, two to fourteen, its crossing pair and its colouring by direction, ahead of the inputs of each average; the moving average presets keep their average count and crossing pair fixed; MA Ribbon also offers colouring by direction. (#1327)

  • StudyTemplate keeps the study’s value scale in scale and applies it, as the study clipboard does, so saved layouts keep it too; a template saved without it leaves the study’s own scale. Settings made through builder methods are inputs, so templates and layouts keep them: the session names and time zones of TradingSessions, the time zone and trading day start of VolumeWeightedAvgPrice, the Fibonacci levels, label settings and options of AutoDrawing, and the colouring by direction of MA Ribbon. VolumeWeightedAvgPrice::with_session keeps what the calculation reads, the earliest open of a window that spans midnight, to the minute; TradingSessions::with_session keeps a session name on one line; and AutoDrawing::with_fibonacci_config keeps up to 24 levels with finite ratios and one-line labels. A template that names an IANA time zone needs the timezones feature to load, as VWAP event zones already do; the zones of the default trading sessions also load without it, as the fixed offsets the study uses there. (#1328)

  • Double-clicking a non-text drawing opens its properties in the terminal and demo; annotations and supplied content keep their inline editor. (#1366)

  • Kinetic scrolling replaces non-finite damping coefficients and values outside 0.0..1.0 with the default of 0.997 when chart options are applied. Non-finite velocity or overflowing motion stops the animation before an invalid offset can reach the time scale, and stopped animations no longer request another repaint. (#1350)

  • Empty legend titles no longer reserve a gap or paint text with non-finite bounds. Floating tooltips omit empty cells, and tracking tooltips omit empty text when optional fields are disabled. (#1268)

  • Study values in floating tooltips and legends use the plot colour at full opacity, so translucent plots keep readable readouts, and a fully transparent one uses the theme’s text colour. Host-facing study colours retain their plot opacity. (#1275)

  • LocaleTimeFormatter::new defaults to a 24-hour clock for en-GB, and underscore locale identifiers use the same hour cycle as their hyphenated forms, including the 12-hour clock for en_US and en_CA. Explicit clock preferences are unchanged. (#1231)

  • Subsecond time-axis labels show milliseconds, including fractions within minute and midnight boundaries. At intervals of one second or more, clock marks retain their labels without fractions, including bars with sub-millisecond timestamp offsets. Subsecond crosshair labels place the fraction before the AM/PM marker in both built-in formatters and the TimeFormatter default. (#1227, #1228)

  • Intraday time axes with day or longer label intervals mark the first available bar of each Monday-anchored day bucket, including weeks whose opening day has no data. Missing Sunday bars no longer hide weekly labels. (#1219)

  • Daily time-axis labels use the first supplied bar at or after each calendar boundary, so weekends and holidays with no bar are not labelled. Candidates sharing a bar keep its strongest boundary, and candidates beyond the last bar are omitted. (#1234)

  • InMemoryToolsRepository::get_all_categories returns the toolbar’s CATEGORY_ORDER, so it includes Cursors, and unknown category names no longer select Trend Line. Migration: drawings::categories::get_category_default_tool returns Option<DrawingToolType>, None for an unknown name; DrawingToolType::by_category returns an empty vector for an unknown name. To keep the old fallbacks, map None to DrawingToolType::TrendLine and an empty vector to vec![DrawingToolType::TrendLine]. (#1334)

  • The demo gives SAMPLE and its US stocks (AAPL, MSFT, NVDA, TSLA) US equity hours in America/New_York on weekdays, regular 09:30 to 16:00 and extended 04:00 to 09:30 and 16:00 to 20:00, so post-market trades stream until 20:00 New York time with extended hours on and the hours follow daylight saving. Before, SAMPLE had fixed UTC hours that ended its extended session at the pre-market and the stocks streamed around the clock. The session and dividend adjustment controls show for every symbol with trading hours and a dividend, the stocks and the fund, and adjustment applies a synthetic dividend of the symbol’s own, with distinct ex-date instants inside the retained live history so ADJ changes earlier prices; crypto, forex, the index and the future keep their behaviour. Closed-market quote lookups skip nights and weekends without scanning the retained trades. Extended quotes keep the latest price and time inside the extended windows when the market is closed. The session menu’s note gives the hours in New York time. (#1295)

  • Drawing anchors in whitespace use the known timeframe duration or the most common positive spacing among the outermost 16 loaded bars, so a weekend, overnight gap or partial opening bar no longer changes their step or moves them when the next regular bar arrives. Steps that divide an hour keep whitespace slots on the grid of the regular bars, including after a partial opening bar. Known month and year intervals advance by calendar months in the display time zone when the bars are keyed at its midnight and in UTC otherwise, and axis labels use the same full-history mapping at every zoom. Migration: hosts that store whitespace times from Chart::index_to_time or Chart::visible_time_range get the new spacing; drawings saved past either end keep their stored instant and may need to be moved once. Their original placement cannot be recovered from the stored times. (#1254)

  • services::PaperAccount removes accumulated rounding dust when closing decimal quantities, so buying 0.1 and 0.2 then selling 0.3, or scaling out 1.0 in ten sells of 0.1, leaves no phantom position. (#1151)

  • combine_trades and Chart::combined_trades give fills at one price exactly that price as their volume-weighted price, instead of a value one rounding step away. (#1143)

  • MaturityScale::whitespace treats a non-finite last maturity as the configured minimum range and caps a finite last maturity at 12,000 months before comparing it with that minimum. A larger explicit minimum range is preserved, while an invalid or extreme data-derived maturity no longer requests unbounded whitespace. Migration: a host that needs whitespace past 12,000 months sets minimum_range to that span. (#1307)

  • TimeScale ignores non-finite widths, bar spacing, right offsets and scroll or zoom inputs, including options applied by chart construction, settings, synchronization and undo or redo. Invalid configured offsets retain the previous live-edge values, so returning to realtime remains safe. Chart::set_chart_options and Chart::with_chart_options retain the previous finite spacing and offsets before storing options, so reapplying an invalid offset preserves a scrolled view. New spacing bounds still clamp the retained spacing. Box zoom rejects non-finite corners or widths before changing either scale or zoom history. Migration: infinite offsets, scrolls and zooms that previously clamped to the scroll or zoom limit are now ignored; pass a finite limit to reach an edge. (#1306)

  • PriceScale::set_range ignores non-finite, equal or reversed bounds and overflowing spans before changing the range, manual scaling or a locked price-to-bar ratio. Automatic scaling can still fit the next frame after a rejected range. (#1233)

  • VolumeFormatter promotes a rounded mantissa of 1000 to the next available unit, so values just below the K, M and B boundaries show 1.00K, 1.00M and 1.00B at the default precision, including negative values. (#1230)

  • Normal and logarithmic price-axis ticks respect multiples of PriceMarkGeneratorConfig::min_price_step, including when label precision is set. Automatic labels retain the decimal places needed for fractional grid intervals, up to eight in fixed notation. Percentage and indexed intervals keep their own scale units. Floating-point noise in tiny tick sizes or precision units no longer increases an already round interval. (#1229)

  • Percentage axis ticks and price labels show a positive zero when the value rounds to zero at the displayed precision, including scientific tick labels. (#1226)

  • A drawing copied or saved in a study pane is pasted or loaded into the pane holding the same studies on the target chart, or into the price pane when the chart has no such pane, instead of the pane of whichever study has the same id there, where it sat on another study’s scale, was drawn at a study’s price in the price pane, or was listed and saved but never drawn. Study ids are local to each chart, so Chart::copy_selected_drawings and Chart::save_drawings store the pane’s identity in StoredDrawing::pane (a StoredPane: the names and inputs of the pane’s studies and its rank among the panes holding the same ones), and Chart::paste_drawings and Chart::load_drawings resolve it as Chart::linked_pane matches panes for linked charts. Records written before keep their study id and load as before. A study that takes another study’s output as its source names it by its local id, so its pane matches only on charts where that id names the same study, as with linked charts. Chart::linked_pane no longer answers the price pane when its overlays are the same studies, as documented. Migration: StoredDrawing literals add pane: None, or use StoredDrawing::new. (#1252)

  • Undoing a bulk drawing command reverts only the drawings it changed. DrawingManager::edit_selected (the properties dialog), delete_selected (the Delete key), clear_all, set_group, set_visibility_all, toggle_lock_all and the end of a multi-selection drag recorded every drawing, so their undo also reverted changes made since to other drawings outside chart history, such as a linked chart’s edits or a host’s edit_drawing, and queued saves for all of them. They now record only the drawings they change or remove, with their list indices, which also keeps history from growing with the number of drawings. (#1251)

  • Undo and redo put drawings back at their place in the drawing list, which decides which of two drawings with the same z-order is painted and hit on top. Undoing the deletion of a drawing no longer brings it above the drawings it was under, and redoing a paste no longer puts the copies beneath every other drawing. History records the list index of each drawing it takes out of the list and reinserts the drawing there. Migration: DrawingCommand::Delete is a struct variant with drawing and index, DrawingCommand::Snapshot::drawings pairs each drawing with its list index, HistoryService::push_delete takes the index the drawing was removed from, and HistoryService::push_snapshot takes (index, drawing) pairs in list order. (#1250)

  • Saved drawings, pasted drawings, host drawing edits, the drawing properties dialog and drawing templates, including the settings document’s drawing defaults, refuse a font size outside 1 to 256 points, a stroke width that is not above 0 and at most 100, and a pitchfork level beyond 100 times the tine distance; DrawingStorage::to_json refuses them as well, and loading skips such a drawing and reports it. The text, icon and inline editor renderers draw sizes outside the range at its nearest end, as do the tooltip, the watermark and the axis labels, and Chart::restore refuses a tooltip, watermark or axis font size outside it. Pitchfork levels beyond the bound are not drawn, and pane heights are shared from stretch fractions, so a stretch factor near f32::MAX no longer overflows, and Chart::restore refuses stretch factors whose sum is not finite. A large font size in a saved document had panicked the glyph rasterizer, and huge or negative sizes had produced NaN geometry. (#1238, #1241)

  • The vertical grid of a time-independent chart and of indicator panes keeps its lines at least 80 points apart at any bar spacing, so a tiny maximum bar spacing no longer makes a frame draw millions of lines. The two grids share one interval rounding. Chart::restore refuses minimum and maximum bar spacings that are not 0 or at least 0.01. (#1239)

  • A layout that Chart::restore accepts now saves a layout that loads again. Chart::restore refuses a snapshot holding a number that is not finite, which the next save would write as null and the next load refuse (for example an f32 field of config or options given 1e39), a crosshair width of zero or less and a scale font size of 0 in its settings, before changing the chart. Chart::snapshot returns an error instead of a layout that restore would refuse, and a price scale whose fit to the data overflows keeps its previous range, so a study with an extreme input no longer makes the chart’s layout unsaveable. (#1240)

  • Editing an alert whose saved expiry has no local time in the dialog’s time zone, such as the last representable instant in a zone east of UTC, no longer panics: the dialog treats that expiry as changed, so a newly entered date and time replace it. (#1242)

  • Session dividers and the watermark follow the active theme: ChartConfig::with_theme, and so Chart::set_theme and set_theme_override, set session_break_color from the theme’s major grid colour and watermark_color from its grid colour, and a restored layout that still holds the previous palette’s values follows the theme too, while an edited colour is kept. They stayed at the dark preset’s colours, which made the dividers invisible on the light theme and the watermark a heavy dark mark. (#1272)

  • Marker::new has the colour Color32::PLACEHOLDER, which the markers and the time scale marks paint in the active theme’s text colour, shapes and text alike, so a marker without with_color reads on the light theme instead of painting white on white; a marker with a colour is unchanged, and layouts saved with white markers keep them white. (#1274)

  • widget::ValueFormatters is publicly exported so hosts can name, store and pass the formatters used by Legend, and styles::LayoutContext, which ResponsiveToolbar passes to its content, is exported with the ui feature. Public signatures are checked by the unnameable_types lint. (#1310)

  • PaperAccount::new documents its panic when balance is NaN or infinite under a Panics heading. (#1318)

  • Migration for standalone renderers: pass ticks_visible before slot to render_time_labels; false preserves the previous tick-free axis.

  • Depth history pages keep held columns at their existing resolution: empty and fully overlapping pages leave every tier unchanged, older columns merge pairwise to the oldest held tier’s resolution, and columns inside gaps are placed by span and age. Adjacent pages complete a short oldest column so default paging retains at least 42 hours; accepted counts exclude discarded input columns. Live corrections replace overlapping columns without merging unrelated history again; full columns merge only in overflowing tiers. (#1247)

  • Replayed trades with order ids find their retained fills by id in constant time, including individual pushes, drained bursts and overlapping history pages, so reconnects no longer scan the trade store for every fill. Missing order ids are still completed without counting the fill again. A 100,000-fill replay is checked for instruction growth in CI, with annotation correctness checked independently of elapsed time. (#1245)

  • Depth deltas sort their changes and merge only the touched suffix of each side into reused buffers, so small updates near the touch do not copy the whole book or allocate once warm, and best-first batches no longer shift a growing side once per new level while holding the inbox lock. The last entry for a price still wins, and a resulting side beyond 10,000 levels is rejected before replacing either side. Larger batches of updates and removals remain accepted when their resulting sides fit. Change buffers with capacity beyond 10,000 entries are released after the delta. (#1246)

  • Heartbeats after a pushed whitespace bar keep the last real close for their zero-volume candles instead of creating invalid bars. Whitespace alone does not seed a heartbeat candle. (#1248)

  • History pages extend only their newest bar with trades already streamed in its slot, keeping the page open, the combined range and volume, and the latest trade close, for both chart and study series. Completed page bars and bars over heartbeat candles with no trades replace the tick bars; bars at or after the request’s before are dropped, with a warning naming the feed on scroll-back. A scroll-back page with no valid older bar ends history with a warning. A heartbeat leaves an existing non-whitespace bar unchanged. The first trade after a heartbeat replaces only the carried candle and extends any page bar already in that slot, keeping its volume. Zero-size trades keep the forming candle’s open and range across drains and extend the newest page bar with their range and latest close when history arrives. Repeated pages do not count the trades again; an overflowing page bar is rejected and counted without discarding the trades. Migration: a feed that streams trades before answering history leaves them out of the page’s newest bar, or holds them until the page is answered. (#1243)

  • WeeklySessionProvider breaks at midnight UTC after its configured break_day and distinguishes weeks across years. Its default still starts weeks on Monday. Migration: the default break_day is now Sun, and explicit weekdays now take effect instead of being ignored. CompositeSessionProvider::standard() gives monthly breaks priority over weekly and daily breaks; custom composites keep insertion-order priority. (#1224, #1319)

  • Daily and longer session dividers use the trading date each bar carries, its UTC date or, for a bar opening at midnight in the session zone or at the first instant of a date in its clock’s calendar or session zone, its local date, including when midnight is skipped or repeated, so week boundaries and their labels agree with session closes across exchange zones. Monthly and multi-month bars shorter than a year show calendar-year dividers through SessionBreakType::Yearly, with stronger yearly lines, while weekly and multi-day bars retain month dividers. Bars of a year or longer have no dividers. Custom intervals of exactly 24 hours receive daily week dividers and session closes, including for the countdown. Migration: exhaustive matches on SessionBreakType add Yearly. (#1222, #1225, #1232)

  • BarClock keeps intraday opens in chronological order across repeated hours for intervals longer than one hour, including a boundary inside the repeated hour. Session closes start a separate off-session bucket, so an after-close execution cannot change the final regular bar; shortened buckets and subsequent opens agree, including across adjacent trading windows. (#1220, #1223)

  • A dashed or dotted drawing is dashed only where it can be seen. Rectangles, triangles, polylines, arrows, arcs, circles, ellipses, patterns and the other drawings restyled by their line style generated one shape per dash along their whole length, so a drawing reaching far beyond the view, after switching to a shorter interval, pasting into one or loading saved drawings, stalled the frame and could exhaust memory; the point of control line of volume profile drawings and studies did the same. The pattern stays anchored at the start of each stroke, so it does not shift as the view moves. In an 800 x 600 pane, a dashed rectangle reaching a million points beyond it paints fewer than 1,000 dashes instead of 333,000, and a frame with an anchored volume profile anchored 200,000 bars back paints about 500 shapes instead of 100,000. (#1237)

  • Body, centre-handle and multi-selection drags translate every drawing anchor in the price scale’s own units. Logarithmic drags preserve the shape and positive prices in either direction. Horizontal drags leave every valid price exactly unchanged, including anchors far outside a tightly zoomed range. Single handles retain their existing pointer clamping and magnet behavior. Migration: DrawingManager::{update_drag_handle, update_drag_handle_with_coords} and HandleService::update_handle callers pass a price-translation closure after the existing Y-to-price closure; it takes (price, from_y, to_y) and shifts the original price in scale units, as PriceMap::translate_price does. (#1255)

  • Selected drawing handles and bodies near a pane edge can be dragged outward from the first movement. The press origin starts the drag, and every update keeps the pointer on the pane, including a release outside it. (#1253)

  • Studies sourced from another study’s plot refresh from the first output value it changed, including earlier bars repainted by a new swing, fractal or pivot. Live appends and last-bar updates keep dependent histories in step with their source. (#1256)

  • Estimated volume profiles resolve tied points of control to the lower price row, as executed profiles do. Equal two-row volume sums expand the value area by one row on each side. Both tie rules are documented; a single bar spread over 24 equal rows has POC row 0 and a 70% value area of rows 0 through 16. (#1288)

  • Volume profiles built from executions centre each row on its price, so a trade at 100 with a tick of 1 spans 99.5 to 100.5, level with the footprint cells and trade, book and depth profile rows. Migration: VolumeProfile::from_executions(bar, step, complete) becomes VolumeProfile::from_executions(bar, step, flow.tick_size(), complete), with the new Footprint::tick_size. (#1289)

  • Footprint delta-percentage markers, level imbalances and bar bid/ask-ratio markers include exact threshold equality despite floating-point rounding, including fractional execution sizes summed trade by trade. All three comparisons use the same relative tolerance of one part in a billion; a value one lot below the threshold remains below it. (#1287)

  • Equal-row volume profiles that start flat rebuild as soon as a later bar changes the traded range, even inside the first row’s padding. Studies and drawings then use the requested rows and actual price boundaries, including a one-row configuration; repeated bars at the original flat price still extend without a rebuild. (#1283)

  • Footprint cells and annotations, trade profiles and their POC, value-area and node guides, live book profiles and liquidity heatmap rows extend half an instrument tick below their first tick and above their last tick. Grouped rows shift by half a tick rather than half a grouped row. Footprint::tick_size exposes the original tick size. Migration: render_trade_profiles callers pass the instrument tick size after the grouped step, for example flow.price_step(), flow.tick_size(), &config. (#1289)

  • HeatmapStrip keeps cells aligned with the host’s bar positions at narrow zooms, widens a cell to the minimum width only up to the next cell so translucent cells never stack, clips their paint to the strip, appends cells in amortized constant time and finds visible cells by binary search. Delta and volume normalization use cached maxima over the complete history. Migration: call render(ui, rect, (first, last), bar_spacing, |i| mapping.idx_to_x(i)), where the range is inclusive and i is an absolute bar index. The cells field is private; read normalized copies with cells(), construct with new or with_config, replace history with set_data and add cells with add_cell; both keep the cells ordered by bar index, and appending in that order is amortized constant time. (#1286, #1290)

  • Volume bubbles follow each bar’s clock slot even when the feed stamps bars inside their intervals. Automatic and price-step groups stay on the bar centre; execution and time-window groups measure elapsed time from the slot open, and the first visible bar retains trades before its stamp. (#1285)

  • The layout menu’s Autosave toggle, the trading lines’ order types, take profit and stop loss labels, tick results, tooltips and Buy and Sell button, and the legend’s series and study controls, quote boxes, delayed and end-of-day marks and hints and copied values go through the context’s translator, so one that changes every key reaches them without recreating the chart. The volume tag on the price scale takes the applied theme’s rising or falling candle colour for the last bar instead of a fixed pink, marker outlines take the theme’s crosshair label text colour, and event break lines its info colour, so a custom palette reaches them; a marker’s own colour is unchanged. (#1059)

  • TPO charts and studies index cached profiles by session once per frame, so zoomed-out daily views no longer search and shift the entire cache for every session. Context-menu hit testing shares the same cache; profile reuse, session splits, composites and retention limits are unchanged. The frame benchmark and instruction regression check cover 400 and 1,600 daily sessions. (#1270)

  • A footprint built from the feed’s trades drops the contribution of each trade the bounded store evicts, summing the bar that lost trades again from those held so its delta high and low agree with them, and keeps at most 5,000 bars and 50,000 price rows, the oldest bars first. Footprint::complete_from gives the open of the oldest bar whose executions are all held; bars before it, cut by eviction or the budget, are drawn as candles instead of as complete footprint bars. (#1114)

  • ADX shows +DI and -DI as soon as their period is full, and Stochastic and Stochastic RSI show %K while %D is still warming up. Each line starts where its own definition first gives a value; the slower line’s start is unchanged. Technical Ratings includes its default Stochastic vote two bars earlier. Reference rows, including short histories, follow independent rational calculations of those definitions. Migration: on those warm-up bars ADX rows are Multiple([NaN, +DI, -DI]) and Stochastic and Stochastic RSI rows are Multiple([%K, NaN]) where they had no value; value(line, bar) still returns None for the missing line. (#1259)

  • Stochastic, Williams %R, Ultimate Oscillator, CCI, ADX, Stochastic RSI, ROC, Bollinger BandWidth and 52 Week High/Low keep their ratios when prices are rescaled below the former absolute zero thresholds. DMI, ADX Breakout, the Commodity Selection Index and Technical Ratings inherit the corrected values. ROC has no value when its previous close is exactly zero. VWAP, Anchored VWAP and VWAP Auto Anchored use every nonzero volume sum, including tiny volumes. (#1257)

  • Money Flow Index returns the neutral 50 when a window has no flow, including flat prices and zero volume, and keeps its ratios at small price scales. Flow magnitude uses the absolute typical price so negative prices retain the direction of their change. Elder Impulse reports bearish only when both its EMA and MACD histogram fall; unchanged inputs are neutral. (#1258)

  • Fixed range and anchored volume profile drawings use the executions of ChartView::executions when they hold any in the selected bars: Footprint::profile sums the bars from the first anchor to the last, each price row shows its buy, sell and unclassified volume as executed, and the POC and value area follow FootprintBar, so they equal the public exact profile and follow the anchors and any new trades. VolumeProfile::source (ProfileSource) tells an estimate from bars, labelled “Estimated from bars” on the chart, from executions, labelled “Partial executions” when none are held from the span’s first bar, and Drawing::volume_profile_of returns the profile a drawing shows. Executed profiles use the footprint’s price rows, so the drawing’s row count and row size apply to estimates only; its value area and display settings apply to both. The split display paints unclassified volume apart instead of as sell volume. The chart supplies the executions it holds while its chart type is the volume footprint or the session volume profile. Migration: ChartView literals add executions: None. (#1070)

  • TPO charts highlight the rows touched by a single period behind their letters when TPOConfig::show_single_prints is on, as ChartTypeParams::tpo_single_prints (the series settings Symbol tab’s Single prints and the Time Price Opportunity study’s Single prints input) sets it, and hovering one names its price. The highlight colour is TpoRenderConfig::single_print_color. Turning it off leaves the letters, POC, value area and initial balance as they were. Migration: ChartTypeParams literals add tpo_single_prints: true. (#1113)

  • Price scale labels that sit closer than a label is high, such as price lines, order and position lines, the previous close and the values of one study, stack in the order of their prices instead of in the order they were added, centred on where they wanted to be. The last price, extended session and volume labels keep their place, and labels further apart keep their exact positions. (#1172)

  • Long and short position tools keep their target and stop labels inside the plot: a label that would pass the right edge flips to the inner side of the line’s end, and placement elsewhere is unchanged. (#1171)

  • The upside and downside Tasuki gap patterns need the third candle to open strictly inside the second candle’s body and close strictly inside the gap, so an open outside the body, a close on either gap edge or a closed gap is no longer marked. (#1083)

  • A deselected rectangle draws its border, fill and label only. Its centre guides and size labels appear while it is selected or being drawn, and its corner dots, which duplicated the selection handles, are gone. (#1169)

  • Footprint cells and statistics columns at the edges of the plot show complete numbers or none; a number the plot edge would cut is left out. (#1170)

  • The magnet crosshair also snaps to the visible outputs of studies on shared, independent and unlabelled scales and to the values of visible comparison series, each converted through its own scale. Hidden, missing and non-finite values are skipped, and an equal distance keeps the bar’s own price first, then studies, then series. (#1107)

  • ChartLayout crosshair sync forwards the source chart’s main-pane price with its time, so synchronized charts show the horizontal line and price label at the same price. Over volume or an indicator pane only the time is shared, and both clear when the pointer leaves. (#1108)

  • Chart undo covers a user’s symbol navigation and comparison edits. Chart::set_symbol called inside Chart::user_action no longer clears history: undo and redo restore the symbol, interval and viewport and reload the feed for it, dropping answers still owed for the other symbol, and earlier steps stay with their own symbol’s drawings. Adding, removing, restyling, hiding, reordering and rescaling an added series or comparison are undo steps that keep its SeriesId, scale assignment and removed bars. The demo records its symbol switches this way, so they keep earlier edits, and after undo and redo its symbol, synthetic feed, watchlist and session controls follow the chart: the restored bars reload and replay stops without recording another step. A symbol change outside user_action still clears history. Comparison data stays with the host: after Chart::take_history_changed, compare Chart::series with the host’s own subscriptions by SeriesId to restart or stop them. (#1053, #1352)

  • Linked drawings in ChartLayout include study panes: Chart::linked_pane maps a study pane to the pane of another chart holding the same studies (equal names and inputs, then by order among identical panes), and drawings follow their timestamps into the mapped pane. Linked edits, unlocks and deletions now reach locked copies, so unlocking or deleting a drawing no longer leaves a locked copy in the other charts; direct edits of a locked drawing still meet its lock. (#1067)

  • A typed comma opens interval entry, empty and under the same focus and text-field rules as a leading digit, instead of symbol search. In a multi-chart ChartLayout, Alt+Enter shows the focused tile alone and a second press restores the preset with every slot, viewport and synchronization group unchanged, and a lone chart still hands the shortcut to the host. Double-clicking a study pane maximizes or restores it like its button; study settings stay on the legend button and the context menu. (#1066)

  • The saved scale font size, axis line colour and pane button visibility apply: ChartConfig::axis_font_size sizes the price and time axis labels, the line colour draws the border of the main, added-series and study-pane price axes and the time axis, and ChartConfig::pane_buttons shows the pane maximize and menu buttons always, on hover or never, in maximized panes too. The settings dialog gains Lines, Font size and Pane buttons controls, and all three read back from the chart and survive snapshots and undo. ChartConfig::left_axis_scale_mode sets the main scale when the left axis carries it, as right_axis_scale_mode does on the right. Study pane menu buttons now show on hover by default, like the setting says. Migration: ChartConfig literals add axis_font_size: None and pane_buttons: NavigationButtons::OnHover or use defaults. (#1060)

  • During replay, studies that request another symbol or interval read only the bars their history completed by the replay cursor, so the chart’s unfinished bar no longer shows the closing value of the other history’s bar in the same slot; that slot has no value until its bar closes. Moving the cursor in either direction recalculates those studies, and leaving replay restores the full histories. Studies that read the bars alone, such as ATR and ADX, offer the Interval and Wait for interval close inputs as single-source studies do, with their own inputs unchanged; studies that request data of their own or read trades do not. (#1049)

  • The study Style tab lists every plot type, step line, histogram, columns, area, circles, crosses, triangles, bar colour and background colour, instead of line, histogram and circles. A type that cannot be drawn for the study stays visible but disabled with the reason in its tooltip: bar colour for a study outside the price chart, and the zero-based histogram, columns and area on the price scale; a saved choice is never removed. PlotType::ALL, PlotType::name and PlotType::incompatibility expose the list, the labels and the rule. New Net Volume studies draw columns, and new PPO and PVO studies draw their oscillator and signal as lines and their difference as columns; styles already saved keep their plot types. (#1082)

  • Chart::restore keeps the colours the user edited and lets the others follow the active theme, so a layout saved under a light theme no longer opens with a light chart under a dark one. ChartSnapshot::palette records the colours the configuration followed; layouts saved without it are compared with the built-in light and dark themes. Migration: ChartSnapshot literals add palette: None. (#1163)

  • The triangle pattern draws both boundaries through its zigzag anchors, runs them on to the apex where they meet and fills between them up to it, instead of closing the anchors as one polygon. Boundaries that are parallel, diverge or meet before the first anchor stop at the last anchor, and a far apex is cut at the chart’s edge. (#1111)

  • Kagi lines change thickness where a continuing line crosses the prior shoulder or waist and are painted in two parts there, instead of only at reversals. ChartTypeStyles::kagi sets the thick and thin stroke widths, 2.5 and 1.5 points by default, which the series settings Symbol tab edits and which serialize with the chart type settings. Migration: KagiLine literals add crossing: None; ChartTypeStyles literals add kagi or use defaults. (#1061)

  • RSI divergence pivots and divergences treat RSI values within 1e-9 as equal, so a flat bar, which leaves the RSI unchanged, no longer makes a tie between neighbouring pivots depend on floating-point rounding. (#1089)

  • RSI, Connors RSI and the RSI divergence study compute 100 * gain / (gain + loss) from Wilder’s averages, with no absolute loss floor, so rescaling the prices leaves the values unchanged. A window with no loss is 100, one with no gain is 0, and a fully flat window is 50, for the price and streak components of Connors RSI alike. (#1089)

  • Value tags and legend values of added series use their own price scale’s decimals instead of a fixed two, while a host formatter set for the series still writes them. (#1064)

  • Volume candle bodies are as wide as the bar’s volume over the largest visible volume, with no hidden minimum: a zero or missing volume draws a body as thin as the wick, and without any visible volume every body keeps the full width. (#1104)

  • The demo page declares the project icon, so the tab shows it and no favicon request fails. The module preload no longer carries an integrity attribute, which browsers ignore for that destination and warn about. (#1044)

  • Range charts build their bars from the executions the feed supplied, in order with their timestamps and volume and with the incomplete last bar, so two execution paths with the same open, high, low and close show their own bars. History pages, corrections, live trades and the replay cursor rebuild them. Charts without executions keep the approximation from the bars’ open, high, low and close, and Chart::range_bar_source reports which one is shown as model::RangeBarSource. (#1105)

  • Drawing::alert_levels resolves a sloping line as the drawing is painted: straight on the price axis, so it follows the geometric mean on a logarithmic scale, and gives no price for a vertical line or a non-positive price there. Parallel and disjoint channels return their base line and second line, and a flat top/bottom its trend line and flat line, as levels 0 and 1 under stable alert sources. Migration: Drawing::alert_levels takes the chart’s PriceScaleMode as a second argument. (#1048)

  • The Elliott impulse projects its 1.618 wave 3 target from the wave 2 end by the wave 1 price leg, rising or falling with wave 1 and unchanged by zoom; fib_config.logarithmic projects the leg’s log return instead. The Elliott triangle collects an origin and waves A to E, labelled 0 and A to E, with the fill, trendlines and handles on A to E. Migration: DrawingToolType::ElliottTriangle needs and requires 6 anchors, and a triangle saved with 5 loads as a skipped drawing (Elliott Triangle needs 6 anchors, has 5) in DrawingStorage::from_json’s result rather than gaining an invented origin; redraw it. (#1068)

  • Three drives labels each correction’s retracement of the drive before it and each drive’s extension of the correction before it, measured in price, and omits a ratio over a zero-length leg. The reversal zone is the price interval 1.272 to 1.618 second-correction lengths beyond the correction’s end, painted through the active price scale, in place of a fixed-size badge. (#1071)

  • Fibonacci retracement and extension fills span the same horizontal bounds as their level lines and hit regions. Channel levels extended left or right run on to the visible pane edge on that side and keep the anchor on a side that is not extended. (#1069)

  • Returning demo visitors follow the system appearance, including live changes, until they pick a theme. Palettes saved automatically by earlier releases are ignored without discarding other settings; new choices persist in the app and on the loading page. (#1043)

  • The interval toolbar starts without favourites and shows one button for the current interval. Starred intervals appear in menu order, followed by the last selected non-favourite and an icon-only menu trigger, without repeating an interval. Selecting a favourite retains the non-favourite button. Toolbar buttons abbreviate one day, week and month to D, W and M. (#1041)

  • Box zoom uses a faint fill and visible border from the active theme’s info colour, with unmultiplied alpha. Its handles and dimension labels follow the theme. (#608)

  • CurrencyFormatter::eur() writes 1.234,56 € for 1234.56. Matching thousands and decimal separators omit grouping. Migration: CurrencyFormatter literals add decimal_sep (',' for EUR, '.' for USD, BTC and custom currencies), or use a constructor. (#676)

  • The price axis menu offers Scale price chart only, and the quick setting applies ChartConfig::scale_price_chart_only. It excludes overlay studies and their primitives from the main price range without hiding them; turning it off restores their individual autoscale participation. Other scales keep their own ranges. Saved configurations without the option default to including studies. (#964)

  • Changing symbols returns the main price scale to autoscaling, clears its price-to-bar ratio lock and discards the previous symbol’s zoom history, so prices outside a manually fixed range remain visible. Repeating the symbol or replacing or reloading its data keeps manual scaling. Initial ratio-lock settings are preserved. (#955)

  • Maximized indicator panes keep plot dragging, wheel and pinch zoom, axis scaling and reset, clicks and drawing placement. Crosshair positions reach host readouts in either pane order. Restoring the layout retains the shared time position and zoom without moving the hidden price pane’s manual range. (#1030)

  • The demo follows the system light or dark appearance at startup and live until a theme is explicitly selected. Explicit choices remain saved between sessions, and the web loading screen uses the same saved choice or system appearance before the app starts. (#1032)

  • Drawing sync notifications coalesce repeated saves and updates per drawing, and automatic storage disables them, so the queue no longer grows with every edit. Migration: hosts consuming both paths call chart.drawings_mut().set_sync_enabled(true) after Chart::set_storage. (#948)

  • Saving an alert with unchanged expiry fields preserves its exact saved instant, including seconds and the later occurrence of a repeated local time when clocks go back. Edited date/time fields still resolve in the explicit entry zone and validate before saving. (#981)

  • Session volume profiles keep their histogram visible when the session opens before the viewport, retaining the whole session’s executed volumes and their proportions. (#967)

  • Broker comparisons keep long names on one line and values inside their columns, with full text available on hover, so host-supplied descriptions cannot overlap other brokers or misalign their Connect buttons. (#1003)

  • Financial views keep their return button visible and their tabs, chart and table scrollable in narrow or short windows. Long row names, period labels and figures stay inside their columns. Charts retain period labels for zero-only and unavailable rows, treat non-finite host values as unavailable and scale finite gains and losses without overflowing their range. (#1002)

  • Symbol search opens at 840 by 680 points, centred and constrained to the window, with 32-point rows and wrapping categories. Instrument::logo and exchange_logo supply marks with text fallbacks. Search and Compare share 20-point corners and a light backdrop near #F1F1F1 over white; dark themes retain their overlay. Modal::backdrop allows a host override. (#998, #1012)

  • Quick search opens with an empty, focused query and an instruction to type. Commands are listed, and the best match highlighted, only once the query matches them; Enter still runs the highlighted match. (#1000)

  • Study appearance and input edits keep settings snapshots in chart undo history instead of copying calculated columns. Undo and redo restore the saved inputs and presentation and recompute against current data; removed studies retain their original implementation. (#944)

  • Drawing sync notifications coalesce per drawing and overflow after 1,024 actions into DrawingSyncAction::ResyncRequired. Hosts replace their stored set with the manager’s saveable drawings, deleting absent records. Automatic storage disables notifications. Migration: hosts consuming both paths call chart.drawings_mut().set_sync_enabled(true) after Chart::set_storage; enabling requests a full replacement. (#948)

  • Drawing autosave retains failed documents until storage acknowledges them, retries after one second of input time, and keeps the latest edits through delayed writes and symbol changes. Chart::flush_stored_drawings retries immediately and reports whether captured edits are acknowledged; storage remains host-owned. (#942)

  • Starred intervals appear in the top toolbar as one-click buttons after the interval menu, in the menu’s order, with the current interval’s button pressed. Unstarring an interval removes its button, and intervals the source cannot serve are left out. (#973)

  • Table, post and idea drawings follow the active surface and text colours in both themes. Ghost feed labels keep readable text while the path fades. Image states, empty content prompts and ghost labels use the host translation lookup. (#984, #985, #986)

  • Table editors keep their cells and wrapping row and column controls within narrow panes by scrolling them together. (#984)

  • Drawing alert sources escape % and # in stored drawing identities, keeping a drawing such as a#1 distinct from level 1 of drawing a. Migration: regenerate saved alert sources containing those identity characters with Drawing::alert_source; numeric identities are unchanged. (#980)

  • The demo loads image drawing addresses over HTTP and HTTPS as well as native files, so image input works in browser builds. The host still supplies image storage and access. (#985)

  • Drawing-menu alerts start on the first visible Fibonacci level even when level zero is hidden; drawings with no visible levels offer no alert. (#980)

  • The demo plays selected local execution and alert sounds with independent volume and mute controls. Test sound previews the selected tone and enables browser audio; playback failures are reported. TradingSettings literals add execution_sound_volume; AlertsSettings literals add play_sound, sound and sound_volume, or use ..Default::default(). Saved settings default the new fields. Native demo builds require a C++ compiler and CMake for the audio backend. External notification delivery remains host-owned. (#982)

  • Demo alerts retain independent live symbol sources and their creation interval across symbol changes and replay. Watchlist members have separate occurrence state and log their actual triggering symbol through AlertEvent::TriggeredForSymbol. Editing source references refreshes the retained study definitions without changing the alert’s clock or session; expiry also works with an empty watchlist. Monitoring lasts while the demo runs; durable evaluation, market feeds and remote delivery remain host-owned. (#961)

  • The demo saves comparison symbols and arithmetic spreads, including styles, visibility, pane positions and price scales, beside each layout’s chart snapshots, and recreates their synthetic feed bindings on restore. Save As, rename and autosave retain these definitions; older layouts open without comparisons. (#960)

  • Chart settings use the active representation’s Symbol controls for line styles, area and baseline fills, and price-based construction inputs. The demo’s top gear, price-axis gear, main-series menu and main-series double-click open the same seven-tab dialog with current values. ChartSettingsState literals add chart_type, chart_type_params and price_source, or use ..Default::default(); older saved settings retain the chart’s existing parameters. SettingsAction::Apply carries Box<ChartSettingsState>; dereference it when passing settings to an owned setter. (#965, #966)

  • The demo selects Range bars with a range interval and sizes them in instrument ticks. Copy price writes the selected price to the clipboard at instrument precision. Fresh sessions start with both crosshair strokes; saved cursor choices are retained. (#968, #969, #970)

  • Built-in studies, including KST, Ichimoku and Parabolic SAR, update changed bars and appends without recalculating unaffected history. Retrospective studies refresh affected pivots, legs and calendar periods. Migration: direct callers of Indicator::update_data must pass from = 0 when a requested history changes; nonzero from reuses requested histories. The chart supplies this invalidation. (#946)

  • Point and Figure columns retain their price endpoints and saturate inclusive box counts at usize::MAX rather than overflowing, including on 32-bit targets. PnfColumn::boxes rejects invalid geometry or expansion above two million boxes and reports allocation failures. Migration: boxes() now returns Result<Vec<f64>, String>; handle the error before using the prices, or use the column endpoints without expanding. (#943)

  • Cached Renko and range chart updates apply the same two-million-size work bound as fresh builds, reseeding after an excessive price move and resuming from that price on later bars. Whitespace does not bypass the bound. (#941)

  • Custom intervals retain positive week and calendar-month counts, with 3, 6 and 12 month presets. Bar boundaries follow the configured calendar timezone, so April 15 belongs to the quarter opening on April 1; session closes and strategy comparisons also retain calendar months. Month durations remain approximate for sizing, and previously saved Custom(seconds) intervals keep their fixed-duration meaning. (#963)

  • The drawing rail optically sizes its trend, Fibonacci and ruler glyphs within their existing button slots. Default light ink is black; dark and custom theme colours, disabled contrast and selected utility fills are retained. (#1001)

  • The magnet menu independently includes or excludes visible study targets through Snap to indicators, preserving OHLC, drawing anchors and the chosen magnet strength. DrawingToolbarAction::SetSnapToIndicators carries the host preference; toolbar snapshots retain it and the demo applies it. Migration: DrawingManagerOptions, ToolbarState and DrawingToolbarDomainState literals add snap_to_indicators: true (or use defaults where available); MagnetButton::show_submenu takes that preference as its fourth argument. (#979)

  • Position drawings size risk in lots using point value and lot size, round down to a configured quantity step, display its precision, convert profit and loss, and report required capital using leverage. Both position Inputs tabs expose the economics; saved drawings and defaults retain them, and older drawings keep unit sizing. Summaries wrap inside the chart, retain compact quantities at extreme magnitudes and disappear when panned out of view. Migration: Drawing literals add position_sizing: PositionSizing::default() or use Drawing::new; hosts supply point values and lot conventions in the account currency. (#959)

  • Two-point drawings accept successive primary clicks with a live preview as well as dragging; secondary drags leave the preview unfinished. Drag and freehand anchors retain the original press, including its snapping, and freehand strokes include the first movement and release. Holding Shift constrains rectangle previews and completed drawings to a square in screen points. Escape cancels unfinished placement. Existing interaction-mode queries and placement cursor feedback are retained. (#956, #957, #958)

  • Notifications default to the bottom-left corner with a 16-point inset. The demo fits notices beside the order ticket and hides them while no room remains; trading notices respect the configured width. Hosts can still select any corner with NotificationPanel::position. (#1009)

  • Held values show six base rows: time, open, high, low, close and total volume. Change remains in hover readouts. Volume study plots are opt-in through TooltipOptions::show_volume_details; other study values and host data windows retain their existing rows. Older saved tooltip options default to hiding volume details. (#1008)

  • Selecting a report trade in the demo restores the session used by its backtest after switching symbols, so the selected trade remains visible without changing the report scope.

  • The registry documentation guards its built-in study example with the studies feature, so the documented headless configuration compiles every example. CI also runs doctests with no default features. (#951)

  • Restoring a layout rejects main or pane scales requesting more than 1,000 tick marks before changing the chart. Direct tick generation caps the limit at 1,000, and built-in numeric formatters cap precision at 324 places even when fields are set directly, preventing overflow and formatting panics. Migration: lower saved tick_marks.max_marks values above 1,000 before restoring; formatter precisions above 324 now produce at most 324 decimal places. (#947)

  • Bar CSV/JSON imports and exports and Chart::export_csv return errors with Send + Sync bounds, allowing results and original error values to cross worker-thread boundaries. Migration: update explicitly typed results, function pointers and error adapters from Box<dyn std::error::Error> to Box<dyn std::error::Error + Send + Sync>. (#950)

  • Session range lookup clips its final one-minute check to the requested end and uses checked timestamp addition, so sub-minute ranges do not report a later break and ranges at the maximum UTC timestamp do not panic. Empty and reversed ranges remain empty. (#953)

  • The example dependency locks replace yanked clipboard-win 5.4.1 with 5.4.3. CI checks advisories as well as licences and duplicate versions, rejecting yanked packages. Three unmaintained standalone D-Bus packages required by the egui 0.37 accessibility backend have explicit maintenance exceptions pending its migration to zbus 6; these are development/example dependencies and have no patched standalone releases. (#952)

  • Numeric formatters omit the minus sign for negative zero and values that round to zero at their displayed precision. Currency amounts such as -0.001 dollars read $0.00; price, volume and study labels follow the same rule, while percentage changes retain their positive-zero convention. (#938)

  • CurrencyFormatter puts the minus sign of a negative amount before a leading currency symbol and no longer groups it: -123.45 in dollars reads -$123.45 and -123456 reads -$123,456.00, where they read $-,123.45 and $-,123,456.00. (#607)

  • Selecting a drawing in the object tree reveals offscreen anchors by panning while keeping zoom and the price scale’s auto/manual state. Double-click and Zoom to object use the same navigation instead of fitting a manual range to one drawing. Chart::reset_chart_view restores configured bar spacing and right margin, scrolls to the latest bar, cancels pending view motion and returns every price scale in every pane to auto-scaling. Chart-menu, keyboard, navigation-button and demo resets use this method. (#935)

  • The command palette consumes Enter in search and Enter or Space on a focused row before returning a command, so a host can open an export dialog without also submitting its empty save path. (#834)

  • The scroll-to-latest button is a theme-aware 28-point double chevron at the bottom right of the main pane, clear of the legend and navigation, with matching paint and hit rectangles, a pointer cursor and “Scroll to the most recent bar” tooltip. Clicking or using the return shortcut animates to the configured right margin without changing zoom. The button is hidden at the live edge and available in history or future whitespace. Custom position, size, text and colours remain supported; realtime_button_text: None selects the icon and Color32::PLACEHOLDER colours follow the active theme. (#930)

  • The study rotation regression checks that every study gets a refresh with both fast and slow recomputes, without assuming an exact count tied to the runner’s speed. (#927)

  • Replay resets clear remote-symbol, alternate-interval and metric study histories, tick-origin bookkeeping, errors and paging state before merging the new position, and invalidate dependent calculations. (#900)

  • Study sources retry recoverable resolve and history failures with exponential backoff capped at 60 seconds, honoring longer rate-limit delays. Retries retain the original page boundary and count, success clears the error, and paused or replaced sources cancel pending recovery. Replies from superseded requests are ignored. (#908)

  • Live subscriptions retain at most 100,000 undrained bar slots independently of raw trade capacity. Overflow evicts the oldest slots, increments FeedState::rejected_bars and reports InvalidData through last_error, asking the host to reload history. Explicit historical execution batches retain their complete output. (#901)

  • Time-based streams reject executions older than the last accepted execution, including inside the forming candle and across frame drains, so delayed trades cannot overwrite the chronological close. aggregate_trades enforces the same ordering contract. Equal timestamps remain valid and replay seeks reset the watermark. (#903)

  • Drawing saves retain the nanosecond remainder after each millisecond, preserving distinct execution-bar anchors when restored immediately, before history loads, through drawing paste or when older placements gain editable controls. Millisecond-only documents remain readable. Migration: StoredCoord literals add subms_ns: 0, or use StoredCoord::new for millisecond coordinates. (#899)

  • Watchlist service pushes and set_quote reject older timestamps and non-finite required or supplied numeric fields, retaining the last usable quote for the watchlist and host consumers. Equal timestamps can still correct prices. (#904)

  • Depth snapshots resolve duplicate tick prices before removing zero sizes, so the last supplied level removes earlier liquidity on either side. (#909)

  • SettingsStore::flush retries unchanged settings after a failed save and confirms them only after a successful acknowledgement. Edits made during a pending save keep the latest choice; repeated failures are reported once until a write succeeds. (#907)

  • The account panel keeps the newest 1,000 entries per completed-history category and releases expired order metadata. Active orders, cumulative partial fills and the latest fill per symbol survive eviction; older history remains host-owned. (#902)

  • PaperAccount checks placement, modification and gap fills against account-wide equity, position margin, working orders and commissions. Refused modifications leave the order intact; reductions and position exits remain available with insufficient funds. Account summaries use the current marks and reserve working-order costs. (#905)

  • PaperAccount accepts only good-till-cancelled orders until session boundaries are available. Migration: direct callers set OrderRequest::time_in_force to TimeInForce::GoodTillCancelled. The ticket and confirmed position actions use the broker’s symbol rules, including for positions outside the chart’s symbol. (#906)

  • Studies sourced from another study continue refreshing during continuous ticks, within the existing full-recompute budget. (#911)

  • Native trackpad pinches zoom around the pointer and stop tracking and kinetic scrolling. Contact input takes precedence when both are reported, and wheel zoom remains applied once. (#918)

  • Touch panning respects its horizontal and vertical permissions independently of mouse dragging and pinch scaling, including two-finger translation and the transition back to one finger. Price and time axis drags use their own scaling permissions even when plot panning is disabled and retain the gesture after leaving the axis; disabled axis gestures do not pan the plot. (#919, #920)

  • Small pans and anchored zooms retain fractional movement on large histories. Synchronized UTC ranges, added series and pointer actions keep sub-bar precision. Fitting and reading UTC ranges retain double-precision fractional bar spacing and indices at plot edges, avoiding magnified UTC rounding errors inside session gaps after long histories; the synchronization reference table covers one-day ranges inside three-day and 65.5-hour gaps at multiple widths. Scroll offsets retain double precision even far into history. Migration: ChartMapping::right_offset, IndicatorCoordParams::right_offset and ZoomState::right_offset are now f64; convert stored f32 values with .into() in struct literals. Existing constructors accept both types, and TimeScale::right_offset_precise returns the retained offset alongside the legacy f32 getter. (#916)

  • Main and comparison series use the same ordinary-price fallback when their percentage or indexed reference is zero or unavailable, keeping drawable comparison coordinates finite. (#913)

  • Logarithmic autoscaling filters drawable positive OHLC prices before reducing their extrema, including opens and closes of bars whose lows cross zero, on the main and added series. (#914)

  • Each chart and added series retains its own Heikin Ashi history, so nine or more active histories reuse their transforms on unchanged frames and release them with their owners. Price fitting and painting share those transformed bars, including recursive opens carried across price gaps. Migration for low-level renderer callers: add heikin_ashi: &cache to CandleDataContext literals, retaining one chart::rendering::candles::HeikinAshiCache::default() per series. The widget manages its caches automatically. (#912, #915)

  • Automatic price tick labels derive precision from their spacing and use scientific notation beyond eight decimals, so sub-nano prices remain nonzero and distinct on normal and logarithmic axes. Explicit instrument precision is preserved. (#917)

  • A zero right margin keeps the newest candle and its streaming updates in the visible data and price fit, including when the right edge is fixed. Logical ranges include their rightmost bar slot when converted to end-exclusive slices. (#910)

  • Chart panning includes the first movement after a pointer press, so a drag completed in one movement frame moves by its full distance. Headless widget tests check the complete pan, pointer-anchored wheel zoom and finite, bounded frames for empty, single-bar and flat histories. (#245)

  • The indicator list and configuration panel share the dialog’s available width, keeping the Add button visible in narrow windows when selecting a metric or another study. (#547)

  • Scalar rolling sums recover small values after a much larger value leaves the window. (#545)

  • Force Index waits for a complete seed of price changes, including when the whole history is shorter than its period. It shares the SMA-seeded scalar EMA with the other studies. Envelopes, Guppy averages and the percentage oscillators also use the public scalar helpers while retaining their reference values. (#545)

  • Starting or rewinding replay in the demo resets the paper account and reconnects its trading view; forward playback keeps the account. PaperAccount::set_replay_time timestamps trading history at each traversed source bar, including skipped bars; None restores the live clock on exit. Resetting the account retains its host-supplied prices and replay clock. Execution marks stay on revealed candles, including partial candles built from finer updates, and hide fills before history or at and beyond the exclusive cutoff. Replay holds no account of its own. (#215)

  • Waiting for a higher study interval to close treats the latest chart bar as forming. Its scheduled end no longer confirms a source bar early; historical chart bars retain their close-time alignment. (#175)

  • VWAP uses the chart interval to distinguish intraday exchange sessions from UTC-labelled daily bars, retaining timestamp inference only without an interval. Changing the interval recalculates existing studies. The inferred Daily flag is hidden from inputs; saved legacy values remain accepted and are ignored. Hosts should supply the interval through Indicator::set_timeframe or Chart::set_timeframe. (#672)

  • Custom toolbar buttons, drawing controls, tabs, menus, object rows and symbol lists report their accessible names, roles and selected, checked, expanded and disabled states. Dialogs expose their titles, and form rows, drawing and series settings, study inputs and alert fields associate their labels with their controls. The chart exposes a text summary of its symbol, interval, displayed history and latest or hovered OHLCV and study values, including gaps and empty history. Native examples with ui and the demo enable the screen-reader bridge; widget-only examples opt in with --features widget,eframe/accesskit. Applications using eframe enable its accesskit feature. (#250, #280)

  • Object tree rows use themed chevrons, drawing glyphs, settings and trash icons in place of letter and punctuation placeholders. (#279)

  • The right bar’s screener, hotlists, calendars, news, chats, alerts and object tree use flat dropdowns with thin chevrons and hover-filled text actions. Long dropdown menus scroll to keep every choice reachable in short windows. News and highlights keep the market scope reachable beside long symbols in narrow panels. Screener filters use the shared input style; market rows share the watchlist’s height and hover fill, with right-aligned tabular values. Calendars keep event metadata on one line and actual, forecast and prior in fixed columns, including missing figures. The screener, hotlists and news entries use fresh radar, mountain and feed glyphs. The demo’s Time and sales and Session notes entries appear only with Toggle API samples; hiding them closes an open sample panel and preserves session notes. (#863)

  • Marker text sits on a background in the chart’s colour, so it reads in full over the candles, bars and lines behind it. (#859)

  • A toast’s message wraps short of its close button, so the end of a long message, such as a broker’s reason for rejecting an order, is no longer drawn under the button.

  • A chart with a feed or server time repaints once a second only while its bar countdown is drawn, so a hidden price axis or a last price outside the visible range no longer keeps an idle chart repainting. (#852)

  • The Baseline chart fills both sides of its base without faint lines between neighbouring parts of the path, which a curved line made obvious. (#832)

  • The top toolbar’s layout button shows the cells of the current preset, one cell for a single chart, the matching grid otherwise and a tab strip for tabs, instead of a four-cell grid whatever the layout; each preset’s glyph is an icons::LAYOUT_* constant. Quick Search has its own magnifier with a lightning bolt (icons::COMMAND_SEARCH), so it no longer repeats the symbol search glyph, and Settings uses a hex nut (icons::SETTINGS_NUT). (#844)

  • The series legend’s values follow the title after one regular gap, and its flag and series actions appear after the values only while the pointer is over the row. The plot’s chart layout and overlay study menus appear only while the pointer is over the chart or a menu is open, and no longer draw a button frame at the edge of the plot. (#817)

  • The top toolbar labels Alert and Replay beside their icons, as it does Indicators, and places the chart layout selector at the right, directly before the layout name and Save. The demo lists its host actions in the main menu, so its default strip shows the built-in controls only. (#817)

  • Watchlist text rejects ambiguous symbols, row drags stay within their unsorted list, and long panel titles and values leave controls and neighbouring columns readable. Size filters scroll before they hide the trade tape. The demo keeps active-symbol quotes on the chart session and price basis, clears the tape when changing chart slots or layouts, and exports watchlists to a fixed filename. (#223, #237)

  • Continuous exchange sessions close their final intraday bucket at local midnight, so custom intervals retain their short final bar when resampled. (#97)

  • Higher-interval candles retain their full body and wick range and can be selected by that geometry after moving to a separate pane. (#546)

  • The main menu button of the top toolbar stays at the left edge while the narrow strip scrolls; only the controls after it move. (#810)

  • Icons draw their strokes one logical pixel wide at every icon size, two physical pixels at 2x, with horizontal and vertical segments on the pixel grid, so toolbar, rail and menu icons match the weight of separators and text instead of blurring across two or three pixels. Filled shapes keep their look. The chart installs the icon loader beside egui_extras’ loaders; an app that shows icons without a chart keeps rasterising them with egui_extras’ SVG loader as before. (#816)

  • The top toolbar keeps every control in its original group and order at narrow widths, scrolling horizontally with touch drags and horizontal wheel or trackpad input. The scroll bar and overflow dropdown are removed. A drag beginning on a button scrolls without activating it; taps and keyboard focus keep working, and focused controls scroll into view. (#806)

  • The web demo follows the dynamic viewport with a legacy height fallback, hides its right rail below 600 points with panels reachable from the main menu, and shows layout tabs only when there is more than one layout. Narrow legends show close and change instead of four OHLC fields, reserve space for pane actions, and keep title controls clear of values during hover. Study controls appear on pointer hover, keyboard focus or a touch row selection and dismiss on an outside tap. (#806)

  • Replay reapplies its cutoff on interval changes, includes newly added layout slots while paused, and restores checkpoints from their saved source interval. (#213)

  • Starting a feed reload no longer reports DataLoaded before history arrives. Successful pages and explicit data replacements still notify the host. (#201)

  • The basic chart example reserves its click readout above the plot and requests repaint after a host click event, keeping the feedback visible. (#201)

  • Switching between a local chart theme and the host theme retains the chart’s widget ids, keyboard focus and retained UI state. (#202)

  • Host pointer events use every visible magnet target in a merged study pane and retain the volume overlay mapping when a secondary click opens a menu. Volume magnet events report the bar volume rather than the raw pointer value. (#201)

  • Command palette labels and descriptions stay clear of categories and shortcuts in narrow windows. Long text is shortened to fit its column. (#308)

  • Shared comparison scales retain manual bounds when members are hidden, removed or reassigned. Comparison lines remain visible beyond the main history, relative axes retain their units in whitespace, and hidden study axes no longer consume comparison gutters. Removing the main series keeps its feed stopped when playback resumes. Copied layouts remap drawing pane ownership to the copied studies. (#87)

  • Applying drawing templates preserves the target study pane, and saved defaults omit pane ownership. Standalone drawing managers release cached geometry after drawings are deleted. Chart layouts keep study-owned drawings local rather than copying their chart-local study ids into another chart. (#151)

  • The study refresh regression checks one full recompute per frame without assuming measured update costs preserve registration order. Unequal refresh deadlines exercise that order independently of timer precision. (#747)

  • Drawing timestamps survive history replacement, interval changes and streaming inserts, including fractional indices and whitespace outside loaded bars. Undo/redo snapshots and linked charts use the same displayed-bar mapping. Drawings and markers are retained per symbol; switching symbols ends active drags and preserves drawing controls; markers between bars interpolate, with the nearest bar supplying their height. Migration: construct ChartPoint with new instead of struct literals; its editable bar_idx and price fields remain public. Handle SaveError::UnmappedAnchor in exhaustive matches. Switching symbols or replacing drawings through load_drawings clears chart undo history. (#81)

  • Recoverable resolve and history failures retry the same request after 1, 2, 4, 8, 16, 32 and then at most every 60 seconds, respecting a longer RateLimited.retry_after. Permanent failures remain exposed in FeedState::last_error and stop paging until reload. Chart::reload_feed explicitly reloads without changing the symbol; Sink::symbols_changed advances FeedState::symbol_catalog_revision for host search refreshes. Hosts still provide the feed and symbol catalog. (#71)

  • Configured right-axis price modes reach Chart::with_config, update_config and changes through config_mut. A mode change resets manual scale ranges and zoom history; unchanged settings preserve them. Undo restores manual ranges after a mode edit through config_mut. (#86)

  • CI builds the separate native demo on Linux, macOS and Windows, tests its controller and starts its Linux window under X11 with a software Vulkan backend. Startup must leave a visible window and survive the first rendered frames. (#282)

  • The demo restores its selected light or dark theme before building the chart and saves the selection through application storage. The existing full theme switch continues to update active and saved chart layouts. (#283)

  • Series settings Reset to defaults uses the active theme’s candle colours, clears custom borders and wicks and retains the selected chart type. Opening and accepting settings continues to preserve the chart’s current colours. (#578)

  • Pane legends identify each visible output with its plot colour. Values below 4.5:1 contrast use a coloured swatch and normal text, retaining the study name and legend controls. (#580)

  • RSI defaults to a two-pixel blue line, a 20% fill between its two grey 4/4 dashed guides and a 138 px pane when space permits. Other pane presets retain their zone fills. Migration: IndicatorPaneConfig literals add fill_between_zones or use ..Default::default(). (#726)

  • The top toolbar uses a 38 px strip followed by a 4 px gap, measured menu, settings and screenshot glyphs and a leading symbol-search icon. Its dark strip and separators use #0f0f0f and #4a4a4a. Save, quick search, settings, fullscreen and screenshot form the right group; alerts, replay and layouts remain reachable through overflow. Overflow preserves disabled Undo and Redo and the selected Replay state, including when playback stops outside the menu. The demo feed toggle moves into its menu and unsupported Publish and Trade buttons are hidden. (#287)

  • Save and the layout menu create independent session layout copies; export remains an explicit command. Drawing templates and account-dependent orders and positions controls are hidden until the host supplies them. Persistent layouts and trading accounts remain host-owned. (#118)

  • The widget bar centres Help on the adjacent 38 px bottom row in every preset, keeping the section rule above it. (#583)

  • Opening a chart, series or drawing context menu suppresses the crosshair, axis tags and data tooltip on the opening frame as well as while the menu stays open. (#291)

  • Removed the unused ContextMenuSizingTokens::char_width: context menus measure their laid-out labels and shortcuts, and elide labels to keep the shortcut column clear when a narrow window reduces their width. Migration: remove char_width from token struct literals. (#457)

  • Replay transport keys reach the visible replay bar before chart navigation, while dialogs retain keyboard priority. Hosts can call FloatingReplayControl::shortcut before dispatching chart input. The demo checks quick search through full application frames, including text arriving with its opening command. (#113, #523)

  • Shortcut dispatch preserves text queued after an opening command, and quick search focuses its input before processing that text. Drawing toolbars defer to the chart’s bindings even when keys are disabled or removed. Binding precedence also applies while a field has focus. Shortcut help wraps within narrow windows, and interval entry uses the shared dialog footer. (#113, #120)

  • A bound character key also consumes its text event, so a restored F binding fits the chart without opening symbol search. Typing ? in a text field edits the field; command search and F1 help remain available there. Opening a host dialog hands subsequent input to it, and typed symbol and interval entry focus their fields before processing queued editing keys. (#113)

  • Drawing tool shortcuts use the shared exact-modifier matcher, including when the toolbar is used without a chart. An extra Shift no longer selects a tool bound only with Alt. (#113)

  • Disabling chart keyboard shortcuts retains native arrow-key focus navigation and does not emit chart-focus commands for Tab. Enabled charts continue to keep repeated arrow pans on the chart. (#113)

  • Keyboard defaults now pan one bar, use Ctrl/Cmd+Left/Right for a page and Ctrl/Cmd+Up/Down for zoom, dispatch drawing undo/redo, quick search, study search, drawing tools and scale toggles, and route date, snapshot, clipboard and chart focus commands to the host. Typing opens symbol search or interval entry instead of selecting fixed intervals; 15 enters fifteen minutes. Help shows the supplied map’s bound actions. Migration: exhaustive KeyboardAction matches need the new command and DrawingTool arms, and labels/descriptions borrow the action. Reset is Alt+R, date entry Alt+G, snapshot Alt+S, inversion Alt+I, logarithmic Alt+L, percentage Alt+P and help Ctrl/Cmd+/. Unmodified F now starts symbol entry; bind FitContent explicitly to retain the former F shortcut. Drawing rectangle, text and pitchfork shortcuts no longer overlap these commands; assign custom bindings through the map. (#113)

  • The demo drawing toolbar zoom controls arm box zoom and restore its previous view through Chart::zoom_back, without consuming drawing undo or redo or editing drawing geometry. (#118)

  • Drawing bulk removal, hide/show and lock-all are single undo steps. Ordering changes and new cloned drawings also enter the existing drawing history, and bulk undo restores every drawing and its list order while queuing host synchronization for the affected records. Property edits were already recorded. Migration: exhaustive DrawingCommand matches need the Snapshot arm. (#108)

  • Quick Search finds and executes drawing tools, built-in studies, chart settings and chart actions. The demo builds its entries from the existing tool and study catalogues; Ctrl/Cmd+K, the search button and menu open the same palette. Migration: handle TopToolbarAction::OpenQuickSearch by opening the command palette; symbol and compare entries still emit their own requests. (#120)

  • The demo gives dialogs keyboard input before the chart and replay controls. Escape closes the shortcuts help without changing the drawing selection, armed tool or replay; an open popup keeps the key even when opened during the same frame. (#523)

  • Drawing Delete, Backspace, Escape and completion keys respect keyboard focus and open popups. Editing a text field leaves the selected drawing and armed tool intact; chart Delete still removes the selection and chart Escape cancels it. (#640)

  • Chart and series settings use the same modal, sidebar and action chrome, with object-specific titles, measured label columns, 8 px swatch gaps and readable section headings. Series colours use the shared picker; unavailable visibility and overlay controls are omitted. Shared dialog titles are 14 px, modal surfaces dim the app, and frame headers and footers handle Escape and primary Enter without taking keys from focused controls or popups. (#294, #278)

  • ChartSettingsState::from_chart and apply_to_chart read and apply the dialog’s display controls in the library, including background gradients, crosshair styling, precision, watermark, navigation, status, scale and margin settings. Invalid timezone, margins or crosshair width leave the chart unchanged. The demo uses this adapter and reads back current values; trading and events remain host-managed; alert visibility, labels and colour control the demo overlay and survive reopening settings. Main-series line settings now apply and read back. (#114)

  • Vertical grid lines retain their own colour through ChartConfig::vertical_grid_color; None follows grid_color. show_grid now gates both grid directions. Migration: ChartConfig literals add vertical_grid_color: None or use ..Default::default(); set show_grid = true before selecting individual horizontal and vertical visibility flags.

  • Symbol search opens near the top third with 32 px result rows, 13/11 px symbol and description text, trailing exchange/type columns and spaced keyboard hints. Comparison searches the same host catalogue. The demo adds timestamp-aligned close-price overlays from independent synthetic feeds, removes and hides them, and keeps their membership with each chart and saved layout. Add, remove and visibility actions leave the public compared_symbols list untouched until the host accepts them. Migration: update compared_symbols after handling an accepted intent. (#296, #117)

  • Vertical-only grid settings edit the visible grid colour. Fractional margins retain their text when settings reopen, and an edited right margin survives live updates. Settings controls inherit the shared checkbox, combo and sidebar styling; series candle colours are paired. Remove the ineffective panel-layout control and unused picker state. Migration: use SettingsDialog::open instead of the removed open_with_layout, set_layout_style and layout_style methods. (#114, #293, #294)

  • Series settings remove the placeholder Alerts, Trading and Events tabs. General settings remove inactive Trading and Events controls; the Alerts controls remain because the demo now applies their visibility, labels and colour to its alert overlay. Migration: remove SeriesSettingsTab::{Alerts,Trading,Events} and SettingsTab::{Trading,Events} from exhaustive matches. Host-owned trading and event settings data remain available for hosts that implement those surfaces. (#212)

  • Active price alerts, including channel boundaries and compound price conditions, have labelled draggable levels through chart::render_alert_levels; a drag returns a replacement for host submission. The demo applies alert visibility, labels and colour, opens the shared dialog at the latest price and saves hovered-price alerts with Alt+A when the chart owns the hovered point. The existing crosshair add menu remains available. The demo host evaluates its displayed synthetic feed, including consecutive crossings and changed drawing or study outputs while prices are idle, and reports triggers and expiry through Alerts, so the existing popup and log show them. Evaluation, sound, background watchlists and durable storage remain host-owned. (#210, #211)

  • PnlLabel::currency uses a host-supplied CurrencyFormatter, retaining sign placement and zero rounding with the instrument currency and decimals. Migration: pass the formatter as the second argument, for example PnlLabel::currency(value, &CurrencyFormatter::eur()). (#209)

  • Crosshairs honour independent line visibility, colours, widths and label visibility, align x with the selected bar, and snap to visible OHLC and study values in magnet mode. The demo magnet menu sets the crosshair mode too. Hovering price, volume or any study pane shares one bar index across all legends and readouts; horizontal cursors use the hovered pane’s scale and precision. Empty-space and synchronized cursors extend through the study panes. Crosshair tags stay inside their axis, including pane edges, with 4 px text padding; clicking the price tag retains the add-at-price intent without a permanent glyph. Pane guides use the theme grid colour, and study legends highlight on hover with visibility, settings and remove controls. Hidden overlay rows retain their show control. Long pane captions leave room for their controls, and floating study readouts fit narrow plots away from the hovered bar. Migration: Legend::show_with_study_actions returns StudyAction instead of a settings index; PaneInteraction literals include visibility_response and settings_response. (#107, #90, #286, #288)

  • Button::text_color changes a label without tinting its fill or icon. Floating replay uses the shared speed combo, a danger-coloured Exit label on the secondary button and a 28 px hide button. The 32 px bar stays inside an 8 px dock inset and scrolls horizontally when the window is too narrow for its controls. (#302)

  • The bottom-bar clock requests a repaint at the next whole second while visible, so it keeps advancing without pointer or feed activity. Hidden clocks schedule no wake-up. (#536)

  • Bottom-bar session and dividend controls show their selected state and describe the current mode. The calendar stays selected while the date picker is open, and range tips use singular interval units in both layouts. Narrow strips shorten the clock to its time, retain the zone in its tooltip and compact the range trigger so session and dividend controls stay visible. (#303)

  • DrawingToolbarDomainState snapshots and restores magnet strength, cursor type and eraser state alongside the active drawing tool. The demo synchronises from the chart before every toolbar frame, clearing finished tools and reflecting externally changed modes without retaining a conflicting zoom highlight. Cursor, eraser and drawing picks leave the previous mode immediately. Migration: snapshot literals supply magnet_type, current_cursor_type and eraser_mode_enabled; hosts call sync_from_domain_state before showing the toolbar. (#519)

  • The magnet flyout gives Off, Weak, Strong and OHLC modes action icons alongside their existing current-mode checks. (#290)

  • The floating selection toolbar uses shared icon buttons with accessible action names and the kit’s hover, pressed and focus states. Its frame follows popup fill, border and shadow, and group separators use the full theme stroke. (#468, #587)

  • Synchronized ranges interpolate repeated element timestamps without jumping forward; nearest crosshairs select the first element at a repeated time. (#116)

  • Layout synchronization retains hidden slots, clears stale tab hovers, retries drawings after receiver history loads and repaints mirrored edits. Drawing Delete shortcuts affect only the focused chart. Layout and group inputs stay open while editing, including toolbar overflow, and overlapping popups do not activate the chart underneath. New and copied layouts keep one linked copy of each shared drawing and retain main-series visibility. Layout theme changes use Chart::set_theme for active and saved charts. The demo preserves custom chart colours when changing slots and applies both endpoints of custom date ranges. (#115)

  • Chart::hover_time, set_synced_crosshair_time, visible_time_range and apply_synced_time_range exchange UTC timestamps instead of local bar indices. Receivers resolve their own bars, sessions, intervals and plot widths; missing crosshair times clear the cursor, and fractional range edges interpolate across gaps. Existing index and spacing methods remain available for local view restoration. (#116)

  • Series settings reserve room for their footer and scroll within narrow and short windows. Price-based types omit unsupported border and wick colour controls, and the inactive Template menu is removed. (#562, #633)

  • Baseline dashes keep their spacing across short segments and base crossings. (#562)

  • Renko wicks retain unfinished price moves beyond the last completed brick when the next brick reverses direction. (#633)

  • Resetting series settings keeps the active chart type in the dialog, so its style controls remain visible.

  • Dashed and dotted series retain their pattern when zooming out makes individual segments shorter than one point.

  • The Area chart uses a blue 2 pt line and a vertical fill fading from 45% opacity at the highest visible point to transparent at the plot bottom, behind the volume overlay. Panning and zooming move the gradient with the visible range. (#735)

  • The shared plot insets from #759 now grow the axis column for wide prices, quotes and study tags, retaining an 8 px outer clearance. Pane plots keep the same left and right edges, with no unused left-axis gutter. Width comes from the rendered tags and ticks, including custom price lines, currency headers and panes with hidden value tags, and updates in the same frame. (#579)

  • Price ticks, tags, crosshairs, legends and tooltip readouts derive precision from explicit instrument decimals or its minimum tick, including integer ticks, five-decimal quotes and prices quoted beyond sixteen decimal places. Sub-unit ranges retain their coordinates and axis marks. instrument_price_precision exposes the same rule to host readouts. Instrument::with_volume_decimals applies volume precision to legends, quote tags and tooltips; DataWindowInfo::with_instrument applies both precisions and zero is a price. Prices and absolute change share DataWindowInfo::price_decimals. Cloned custom formatters retain their closure. Migration: Instrument literals need volume_decimals, or ..Instrument::new(symbol); DataWindowInfo literals need price_decimals and volume_precision, or ..Default::default(). (#78)

  • Indicator pane ticks use the price axis text colour in every preset, retaining the shared axis font. Their shared tick generator avoids repeated labels at integer precision. (#584)

  • The demo alerts panel shares the panel header and New alert icon button, with a centred empty state and Create alert action. Demo notices use the shared opaque, padded toast component; screenshot completion keeps its saved-path feedback. (#304)

  • Object tree headers use shared icon buttons, the search field and type selector share a 28 px row, and the 11 px footer stays at the panel bottom. The Data Window separates Time and Interval; instrument precision and migration are covered in #78. The demo passes instrument metadata alongside its existing chart-formatted time and previous close. (#301)

  • Object tree rows open native context menus with menu rows, sentence case labels and ellipses. Menus stay within the window and close on Escape or any outside click. Migration: ObjectTreeState no longer exposes context_menu_open, context_menu_pos, context_menu_target, open_context_menu or close_context_menu; egui owns popup state. (#530)

  • Object tree selections use the active theme’s selection fill and text; hover state clears when the pointer leaves a row. Long names end with an ellipsis 4 px before the row buttons, with the full name in the row tooltip. (#529, #532)

  • Object tree shortcuts leave focused widgets and open popups alone, and consume handled keys so a chart cannot also act on them. (#527)

  • The grouped object tree shows data sources above its groups and honours the Data Source filter, so the main series agrees with the flat view and object count. (#526)

  • The demo keeps the right rail selection in step with the open panel, including panels opened from menus and the shortcuts dialog closing. WidgetBar::active_icon documents the host synchronisation contract. (#528)

  • Chart::set_theme(ctx, theme) updates chart colours and the context theme while retaining data and viewport. Crosshair labels and their add controls use the active theme’s colour pair, rectangle measurements use its axis colour pair, connection and alert statuses follow its semantic colours, and TPO letters retain at least 4.5:1 contrast on both the plot and value-area shading. The settings dialog resolves default background swatches from the theme instead of a fixed dark fill. Explicit crosshair and background colours remain overrides; alert statuses read the active theme directly. Default settings swatches follow runtime theme changes without changing saved values on Cancel. Migration: standalone crosshair_price_action calls pass the resolved label text colour as the final argument. (#275)

  • Custom controls draw keyboard focus rings, including object-tree actions, floating controls, layout menus and the Save arrow. Contiguous list rows keep their ring inside the row so neighbouring fills cannot cover it. Toolbars, custom intervals and dialog footers follow visual order under Tab; search and template fields release focus, and Enter activates the focused control. (#277)

  • The colour picker measures its popup bounds after layout, so clicking Hex reaches the custom editor. Custom editing starts from the current colour, Escape is consumed, and closing restores the swatch view. Only selection and hover draw a 2 px ring; swatches close to the popup fill get an inside hairline. Wells, swatches and the custom row show keyboard focus. Migration: ColorPicker::show returns egui::InnerResponse<Option<Color32>>; read .inner for a picked colour and .response for the well. The unused color_picker_btn helper is removed; use ColorPicker with persistent ColorPickerState. (#576, #650, part of #277)

  • Autocomplete keeps its popup alive while open and moves selection to the hovered suggestion before drawing any row. Only that row is highlighted, inset with rounded corners, and Enter confirms it. (#592)

  • Auto-height dialogs and modals offer scrolling bodies the current window cap each frame, so they grow with content, shrink again and retain their on-screen header when resized. Dialogs also retain their horizontal margins in narrow windows. The shortcuts dialog uses that cap without its own height workaround. (#641, #652)

  • Egui controls and kit buttons share the 4 px small radius. Focus rings follow each control’s corners and end 2 px outside it; the text cursor uses the theme text colour. Split buttons, sections and UiExt combos use the small chevron icons. Migration: styles::focus::draw_focus_ring takes the control’s radius as its third argument. (#586, #593, #594, #595)

  • Command palette highlights are inset from the row edges and use the kit small radius for selected and hovered rows. (#591)

  • Subdued list text and property labels use the weak text colour while values retain the row text colour. Dark weak text reads at 4.5:1 or better on panels and floating windows. (#589)

  • Action list rows are transparent at rest, including disabled rows, with disabled text and icons in the theme colour. Primary and danger rows use the shared opaque hover and pressed shades. (#596)

  • FormRow starts its controls after the label column with the same horizontal gap and row pitch as FormGrid. (#590)

  • Kit filter fields clear on Escape only while focused and consume that key, including immediately after focus moves elsewhere. Autocomplete handles confirmation only from its own field and reports a closed popup after a pick. The clear control uses the kit icon button with hover, pressed and keyboard states. (#588, #592)

  • Selected indicator rows take both their fill and text from IndicatorDialogConfig, including when the configuration was frozen from another theme. The default follows the active selection pair. Migration: add sel_text_color to configuration literals or use ..Default::default(). (#437)

  • Modal dialogs, modal handlers and the command palette read UiColors::modal_overlay from the active theme. Light dialogs dim white panels to 159 rather than 75; high contrast uses its window outline without dimming. Migration: add modal_overlay to colour literals and saved palettes, or construct colours from a preset. (#585)

  • Active widget rail entries use the selection colour pair and show the pressed step when held. Alert counts use danger_bg with danger_text instead of mixing a status foreground with the badge text. (#387, #531)

  • List action buttons and UiExt primary, secondary and danger helpers share the kit variants, including opaque themed state shades and their matching text. The dark primary blue now meets 4.5:1 with white. Ghost and Outlined controls use egui’s hover and pressed fills, and neutral button glyphs use the same foreground states across button types. (#435, #582)

  • Deserialising incomplete theme colour palettes reports a missing-field error instead of silently filling a light theme with dark colours. Text, spacing and radius scales still default independently. Migration: save the complete Theme value; hand-written theme files must include dark, ui and chart with all colour fields. (#434)

  • Links and clickable labels derive a readable colour from the accent on panels and windows. Theme::with_accent gives black, white and near-endpoint accents distinct opaque hover and pressed shades, a visible selection and a matching light focus ring while retaining text contrast. (#432, #433)

  • egui buttons, headers and open combo boxes use the theme’s fills and strokes in every state. Pressed neutral fills differ from hover by at least 1.2:1. Settings controls use control outlines, active settings icons and timeframe labels use readable text, and secondary surfaces retain readable muted and status colours. (#431, #276, #436, #581)

  • The drawing properties dialog in the demo opens with the drawing’s saved style and interval settings, and applies fill, font size and interval visibility through the existing undo and host-update path. The lock-all button derives its state from the current drawings, including locks changed through context menus. Locked drawings reject property and colour edits until unlocked, as well as movement, handle edits, erasing and deletion. (#138, #140, #141)

  • Drawing renderers apply common dash styles, non-default widths and configured fills to their paint primitives, while preserving custom fork levels and position profit/loss colours. Annotation text, tables and icons use the configured font size before sizing their surrounding geometry; the fixed note marker keeps its icon size. Bold adds synthetic weight using the host’s existing font family and fallback glyphs. Line endpoints render all stored marker styles in anchor order, including reversed lines and path tangents. Info lines, angle lines and arrows also honour left/right extensions. Migration: new non-arrow tools default to no endpoint marker; saved endpoint settings now render as stored. Icons use their saved font size instead of a size derived from stroke width. (#141)

  • Drawing selection also follows the clipped shapes emitted by the renderer, including text extents, position zones, data-driven tools, rings and cycle lines. The manager retains the last paint alongside the existing geometric hit tests; standalone interaction hosts can pass paint commands to DrawingInteraction::hit_test_painted. Moved anchors and edited properties discard stale painted hits. Geometric hits also respect the last paint clip. (#137)

  • Strong drawing magnet snaps to the nearest open, high, low or close of the bar under the pointer even outside the weak magnet’s pixel threshold. Weak magnet retains nearby bar, overlay and drawing targets. Both apply during placement and handle drags, and the drawing toolbar passes the selected strength to the chart. Migration: DrawingManagerOptions literals need strong_magnet, or ..Default::default(); set it with magnet_mode for strong snapping. (#139)

  • Drawing bodies, previews, selected handles and eraser highlights are clipped to the price pane and the caller’s clip rectangle. Patterns projected past the pane edge no longer paint across the time axis or other panes. The chart’s separate axis labels keep their own painters. (#653)

  • Selection handles follow the drawing’s visibility on the current interval, so a selected drawing hidden by its interval settings leaves no visible or hittable handles behind. Chart interval synchronization, drawing rendering and hit filtering were already applied. (#140)

  • Selected drawings move from a body grab while retaining the pointer offset. Every anchor follows the same bar and screen-height offset through the price scale, with one undo step and one host update per gesture. Rectangles also have a centre handle, and body grabs suppress chart panning. (#741)

  • The live demo varies execution arrival intensity in clustered bursts and quieter stretches over a daily activity profile, so minute volume varies several-fold. Price steps, tick sizes and trade-size generation retain their seeded sequence; history and streaming use the same timing. (#782)

  • The demo opens at its configured bar spacing even when the first canvas is narrow. Charts defer initial visible-bar and resize calculations while the plot is collapsed, preserving zoom and the right edge when a hidden or tiny canvas becomes visible. Pixel right offsets use the first usable bar spacing, locked resizes retain fractional visible ranges, and explicit visible-bar requests take precedence over a simultaneous resize. (#781)

  • Study selection follows histogram and circle geometry in overlays and panes. The applied-study editor keeps its controls and footer inside narrow and short windows in both themes. (#169)

  • Study output uses IndicatorValues, one contiguous Vec<f64> per output line, with NaN for missing values. Rendering, hit testing, snapping and autoscaling read the columns directly. Migration: Indicator::values implementations return &IndicatorValues; read line(index), columns() or value(line, bar) instead of indexing rows. to_rows() explicitly allocates the former owned row format for exports. Custom calculation closures still accept owned rows and their stored results are converted to columns. Numeric definitions and streaming update results are unchanged. (#180)

  • KST and RVI use running means of complete windows, STC shares the linear rolling extrema, and RankCorr reuses its sorting buffers and computes Pearson correlation of average ranks for ties. Migration: KST first appears at max(roc_period + sma_period - 1), with its signal signal_period - 1 bars later; RVI starts at bar period + 2, its signal at period + 5. These indices are zero-based; at default lengths KST starts at 44 and its signal at 52, RVI at 12 and its signal at 15. Incomplete windows no longer produce averages. Callers must handle IndicatorValue::None before the main line and NaN for a pending signal, and load enough history before consuming either line. RankCorr values on tied prices follow the rank correlation definition; flat windows have no value. (#179)

  • KAMA keeps a running sum of its last period absolute price changes and resumes last-bar updates and appends through the shared study driver. Full calculations are linear in history length and no longer allocate a price window for every bar. Its SMA seed, efficiency ratio, smoothing and handling of non-finite closes are unchanged. (#179)

  • Stochastic RSI returns its first value as soon as RSI, stochastic, %K and %D have warmed up, including histories of 32 and 33 bars at the default lengths. (#714)

  • DEMA and TEMA seed each inner exponential average with its own first full window, so constant input stays constant and the warm-up remains 2 * period - 2 and 3 * period - 3 bars. (#713)

  • Measurement boxes stay inside the pane when their anchors approach an edge. Gann and trend-time labels omit collisions in small drawings, and harmonic ratio labels move along their comparison chords to avoid anchors.

  • Parallel channel extensions follow chart left and right even when the anchors were placed right to left. Rays retain their direction when panned beyond the pane, and leftward Fibonacci time zones keep their fills. Drawing rail menus use the same available entries as drawing categories.

  • Pitchforks without custom level settings retain the drawing colour and the existing tine width. Fixed Gann grids without custom divisions retain their quarter grid.

  • Three-anchor projections add the first price and bar leg at the third anchor before mapping to screen coordinates, so logarithmic charts preserve the measured move. The target label shows the projected price.

  • Gann grid percentages suppress floating-point tails, the fixed-ratio label sizes to its text, and pitchfan labels sit at the visible ray ends where they have room.

  • Drawing placement collects the construction anchors: three for extensions, trend-based time, wedges, pitchfans, arcs, rotated rectangles, projections and channels; four for triangle patterns; seven for three drives; three and five for double and triple Elliott combinations. Price notes and arrow markers take two points. Positions place entry, target and stop in one click, with independent editable anchors. Extensions project the price leg from the third anchor and trend-based time projects its bar interval there.

  • Rotated rectangles use a sloping base and perpendicular width, Curve has a placed quadratic control, Double curve has two placed cubic controls, arcs pass through a third control, and pitchfan rays pass through Fibonacci fractions of the second-to-third anchor span. Table, Image, X post, Idea and Ghost feed stay loadable but are removed from tool menus until their content is implemented. Migration: new Curve and Double curve placements collect three and four anchors. Older saved placements still load: rotated rectangles gain their axis-aligned corner, double curves gain endpoint controls, wedges and pitchfans gain a boundary at the second time and first price, and one-point notes and markers gain a coincident second anchor. The added controls can be dragged after loading.

  • Fibonacci speed resistance fans include the time fan, ratio grid and quarter arcs in the anchor direction, and selection follows them. A three-anchor Fib wedge draws circular ratio arcs between its two trend rays, using the first trend radius and the signed shorter sweep.

  • Measuring tools count signed ticks and pips from Instrument::tick_size and the new optional pip_size (with_pip_size). Unknown, non-positive and non-finite sizes are omitted. Chart passes its host or feed instrument to drawings. Migration: ChartView literals set instrument (None when unknown); Instrument literals set pip_size: None or use Instrument::new.

  • Gann fans follow the signed anchor direction and retain their steep rays when they leave through the pane’s top or bottom. Fixed Gann squares keep their anchor-defined price-per-bar ratio through zoom. Drawing::gann (GannConfig) sets independent price and time grid fractions on boxes and squares; levels count from the first anchor. Migration: Drawing struct literals set gann, or use Drawing::new. Saved grid and pitchfork settings reject non-finite values.

  • Inside pitchforks use the first leg midpoint and second anchor as their tines, with the first tine passing through the third anchor and the median halfway between the tines. All fork rays follow their direction, including leftward and vertical forks.

  • ABCD, XABCD and Cypher label every price ratio on its comparison chord, including C’s retracement and D’s placement. Undefined ratios on flat legs are omitted.

  • Session breaks and previous-session closes follow exchange windows and holidays, with chart-zone calendar boundaries when no exchange is supplied. DailySessionProvider now honors its configured break time, and its exchange preset follows daylight-saving changes. Migration: DailySessionProvider struct literals need time_zone or ..Default::default(); new still takes UTC hours.

  • Time-scale clock, seconds and tick visibility flags now reach axis and crosshair rendering, and ChartBuilder::options_chart hides its time axis. Migration: time_visible defaults to true to preserve existing labels; false shows dates alone.

  • Floating and tracking tooltip times use the same chart-zone formatter as the crosshair, including daylight-saving changes. Exchange display mode reads the instrument zone when supplied. Chart::format_time gives host readouts the same format and source-bar precision on every chart type, and the demo Data Window uses it. Floating readouts paint above the legend so their time row remains visible.

  • Migration for standalone renderers: pass the chart-zone TimeFormatter and the bar duration in seconds as the final two arguments to render_tooltip_with_options. Pass ticks_visible before slot to render_time_labels; false preserves the previous tick-free axis.

  • Applying the demo’s time-zone setting updates chart readouts and the bottom clock without resetting pan or zoom. Reopening settings retains the zone selected from either control.

  • Daily axis marks use fixed calendar anchors for two-day and weekly intervals, keeping their dates stable while panning. Month boundaries remain visible between day strides and on the first of the displayed month at medium widths and wide time ranges, including across daylight-saving changes.

  • Horizontal arrow keys keep keyboard focus on the chart and pan on every press. Tab still moves to the next control.

  • Chart::visible_bars now applies the requested initial bar spacing on the first frame, matching set_visible_bars.

  • Chart settings read back current status and scale controls before opening. Choosing log or percentage scale clears the other mode; legend volume remains independent of the histogram. Custom price-line tags and axis gestures follow left placement, and long session tags stay inside the chart.

  • Enlarged modals fit narrow windows, with scrollable settings content and tabs. Indicator results use a 32 px row pitch.

  • Symbol search gives its category strip and results separate scroll identities, keeps keyboard selection under a stationary pointer and scrolls the selected result into view. (#597)

  • Opening chart settings now reads the chart’s current candle, background and grid colours, so applying display controls preserves its appearance in every preset. (#577)

  • The host Trade and Publish controls now explain their trading-account and chart-export actions on hover, using the shared toolbar tooltip.

  • The interval menu reserves a compact 200 px outer width until the custom form is expanded; the form retains its full input and unit controls.

  • Chart settings opens on Symbol in the shared modal, with a 752 px surface, tab-specific heights, neutral sidebar selection and aligned value columns. Existing tabs retain their controls and template actions; dropdown selection remains readable.

  • The indicator dialog uses an 840 px surface, a 40 px search field, a wider category column and single-line study names. Categories with no provider are omitted from the sidebar; favourite and study configuration actions are retained. Filter fields respect the host interaction height.

  • Quick search uses the shared 480 px modal with a search header and close button. The demo connects its quick-search button and Ctrl/Cmd+K to the existing command palette for symbol search, indicators, settings and export. Shared dialog titles use 20 px text.

  • The compare dialog uses the shared modal frame, a wide search header, a close control and a single list of 56 px symbol rows. Its configured fill remains supported through Modal::fill.

  • Symbol search uses the shared modal frame, a full-width search row with a close button and 56 px result rows. Escape and backdrop dismissal follow the modal; symbol filtering and keyboard selection are preserved. Empty modal titles allow a search row to serve as the header.

  • The Save arrow opens a compact export menu while the label keeps its existing action. Entries requiring hosted layout storage are omitted.

  • Snapshot offers image download in a compact menu beneath its trigger. Opening the menu leaves capture to an explicit download choice.

  • Chart-type menu rows use a single 14 px name beside each icon, neutral selection and separators between type families.

  • The interval menu groups full interval names in 32 px rows with trailing favourite marks and neutral selection, retaining custom interval entry and model selection.

  • Top toolbar tooltips use compact dark surfaces below their controls, with platform-specific shortcut chips for alerts. Symbol, interval and chart-type triggers now identify their actions on hover.

  • The demo opens at one minute in Arrow mode with axis readouts. Synthetic sessions stay continuous, with shorter wicks, varying low ordinary volumes and occasional peaks. Volume peaks use a quarter of the plot height with a flush baseline, and candle bodies use 75% of the bar pitch. Hourly data remains available; session timestamps and adjustment inputs are unchanged.

  • The in-pane legend and held values keep the chart’s configured candle colours. The legend title exposes a flag and copy actions on hover. The Data Window computes change from the preceding displayed element, matching the legend on both time-based and price-based charts. ChartState::shown exposes the series indexed by hover and selection.

  • Time axes use denser calendar marks shared with the vertical grid and semibold day, month and year labels. Round price levels use semibold labels. Minute intervals retain their unit in the toolbar, and interval picks update the trigger and selected row.

  • Dark plot and panels are black, with neutral hover fills quieter than pressed fills. Volume uses muted teal and salmon at the configured theme opacity, and both themes use dotted grids. The demo preserves its rounded chart container.

  • Cursor choices use 40 px rows, larger glyphs, a neutral selected row and a labelled values switch, with visible keyboard focus. Held values use a compact six-row panel. Eraser suppresses the previous cursor’s trail and crosshair strokes.

  • Toolbar controls, including replay, undo and redo, move into overflow before overlapping host actions at narrow widths. Demo Search, Trade and Publish keep their intended order and sizes.

  • Price ticks stay on the supplied decimal precision when zoomed in. Intraday marks survive bars that start between clock boundaries, and daily charts at multi-month zoom use calendar month names and year boundaries. Hover tags remain within narrow viewports.

  • Crosshair price and time tags default to black with white text, use 21 px and 25 px rows, and clamp at both horizontal edges. The price row reserves a 21 px add-action cell for the host to route with chart::crosshair_price_action. The default crosshair stroke is dotted; explicit colours and line styles remain supported. chart::render_crosshair_full and RenderContext let hosts draw the same readout over a combined price and volume viewport.

  • Price lines use 4 px dashes with 4 px gaps, and dotted price lines use 1 px dots with 3 px gaps. Drawing line patterns keep their existing lengths. Price tags are about 17 px high at the default axis font size.

  • Intraday time marks use actual session bars and the formatter’s timezone for calendar boundaries, so closed hours and missing weekends take no slots and month labels name the new month. Day labels show the day number. TimeFormatter::wall_time supplies calendar fields and format_crosshair supplies a hover readout; both have defaults for existing custom formatters. Intraday hover dates include weekday, day, month, short year and time, with fractional seconds preserved through timezone conversion.

  • Price ticks, price lines and crosshair price labels use the feed instrument’s price_decimals, which clears when the feed reloads. Hosts without a feed can set PriceScale::set_price_precision; an unspecified precision keeps at least two decimals on price ticks. Default price marks stay at least 40 px apart. Price tags have square left corners and white text on financial colours, while pale custom fills retain dark text.

  • The series legend wraps between whole OHLC fields within its supplied plot bounds, truncates long titles and paints the chart background behind text. The title uses 16 px text and the readout 13 px, with financial colours and 8 px field gaps; wide readouts stay inline.

  • Price and study panes share the available height at a 3 to 1 weight per study, with one 28 point time axis below the lowest pane. A study that would be under 40 points collapses to a 24 point legend row; clicking its title expands or collapses it. Pane plots and selection handles use the main plot’s horizontal bounds and clip to the allocated pane, including after a resize. (#736)

  • The bottom clock converts UTC instants to the named time zone, including daylight-saving offsets, and falls back to UTC digits and a UTC label for unknown names.

  • The bottom bar uses 14 px primary text, measures its labels to align the clock and session controls at the right edge, and keeps range buttons unfilled at rest. Clicking the remembered range requests it again after panning; narrow bars keep all ranges in a menu. The date button has a 24 px icon grid beside a 22 px rule.

  • The top toolbar is 38 px high with larger icons, a filled symbol pill with a semibold ticker, a plain interval and an icon-only chart type trigger. Group rules are 22 px high with compact gaps, and theme and search actions open from the menu. TopToolbar::show_with_slots reserves space for a host menu and right-side actions before compacting the built-in controls; alert, indicator and settings actions also move into overflow when a long symbol leaves too little room.

  • The demo opens in light with labelled synthetic one-minute candles, volume and one in-pane header; studies remain available on demand. The shell uses 38 px top and 39 px bottom strips, 52 px left and 45 px right rails, 4 px gutters, a 6.1 px opening pitch and a 65 px right margin. Regular and extended sessions and dividend adjustment derive from retained history. Ranges fit displayed timestamps, including replay and narrow windows; date navigation selects an available session. Chart timezone choices update both axis formatting and the bottom clock.

  • The export dialog stays open to show success with the file path or an error, and prevents duplicate requests while an export is pending. The demo reports file write results and offers PNG and CSV downloads in the browser. Image exports capture a frame after closing the dialog and report the result in a notice.

  • Drawing magnet mode snaps placed anchors and dragged handles to nearby OHLC and visible overlay-study values, keeping each value paired with its bar. Targets follow the current pan, zoom and price scale within DrawingManagerOptions::magnet_distance (15 logical points by default). Hidden overlays and the drawing being dragged are excluded; undo and redo retain the snapped data coordinates.

  • Drawing rail icons render on their 24 px grid with simpler Fibonacci, pattern, brush, magnet and keep-drawing details. The cursor family gains a pointer-and-halo icon for demonstration mode.

  • Drawing rail selection uses a neutral fill, distinct from the magnet’s contrasting latched fill. It keeps a 24 px icon grid on a 38 px pitch, with 35 px state fills and primary text ink. Its rules are 36 px wide and light-theme rules use a neutral grey. Drawing templates remain available in the Hide flyout instead of taking a utility row. Keep Drawing shows a pencil and lock, and the visibility menu uses an open eye. The right widget bar defaults to 45 px with 28 px icon grids; hosts should size its outer panel from WidgetBarConfig::width. Migration: TemplatesButton::show is removed; use the visibility flyout, or render TemplatesButton::show_submenu in a host menu.

  • UiExt::error_label, warning_label, success_label and info_label use the active theme’s error, warning, success and info colours instead of fixed colours, so the export dialog’s error message reads at 4.5:1 or better in every preset.

  • The interval and chart type menus close on Escape and on a click anywhere outside them, take the theme’s menu frame, and end on a whole row above the window’s edge with a scroll bar shown at rest when they scroll, so every interval and chart type can be reached. Interval codes no longer run into their descriptions, favourite intervals show a star icon instead of an asterisk and the current chart type a check icon instead of a “v”, and every row reports its name, role and selected state to accessibility tools, shows a focus ring and scrolls into view when the arrow keys reach it. (#289)

  • The crosshair of Renko, Kagi, Line Break, Point and Figure and range bar charts writes times to the precision of the bars they are built from, instead of milliseconds for the bricks of one bar or the date alone for elements days apart, and the tooltip and the OHLC header leave out volume on chart types without it. A view of a single bar takes the precision from the bar before it instead of writing seconds.

  • Renko, Kagi, Line Break, Point and Figure and range bar charts are drawn on a time scale of their own. Each brick, line, column or range bar takes one slot at the bar spacing and carries the time of the last bar that built it, so the time axis, the crosshair, the tooltip and the legend describe the element under the pointer. Panning, zooming, following the live edge and fitting the price scale work on the elements, and a few elements sit at the right of the pane as bars do instead of packed against its left edge. A change of chart type keeps the time at the right edge of the view, and a view at the live edge stays there. The time scale starts at the oldest kept element, and a chart with a feed stops asking for older history once older bars would not be drawn.

  • Intraday time axis marks fall on multiples of their interval from midnight UTC, so each midnight shows its date, clock times appear between dates and panning keeps each remaining mark’s time.

  • Cypher labels C as an extension of XA and D as a retracement of XC, both from anchor prices, instead of reusing the XABCD ratios and omitting C. B keeps its retracement of XA.

  • A multi-line study emits IndicatorValue::Multiple with one value per line, NaN for a line without a value, on every bar where any line has one, and never Single, as IndicatorValue now documents. TRIX, KST, SMI, RVI, PPO and PVO emitted Single with their main line while the signal warmed up, which every renderer drew on all lines, and Fisher Transform, Ehlers Fisher and Center of Gravity did so whenever the trigger or signal was exactly 0, as on a flat series. Their first value has no trigger or signal, since there is no previous value; a later trigger or signal of 0 is drawn. Migration: code matching Single on these studies reads the first value of Multiple; values do not change except the first trigger or signal, which is NaN instead of 0.

  • Multi-line studies draw every line they compute. Indicator::line_cnt defaults to the number of line_names instead of 1, so TRIX, KST, SMI, RVI, Center of Gravity, Fisher Transform and Ehlers Fisher draw their signal or trigger line, Elder Ray its Bear Power, Vortex its VI-, Price Channel its lower and middle lines, Pivot Points its six support and resistance levels and Squeeze Momentum its squeeze flag (1 or 0) in its squeeze-on gray, which becomes its second colour ahead of the negative-momentum red. DMI adds the ADX line of the same length, equal to the ADX study’s, after +DI and -DI. SuperTrend and Parabolic SAR are drawn as an up and a down trend line in their bullish and bearish colours. The main chart breaks a line at a NaN value as at a bar without one, and draws a run of one point as a dot; pane renderers skip a NaN value. Migration: an Indicator implementation that returns more line_names than lines overrides line_cnt. SuperTrend and ParabolicSAR output Multiple(vec![up, down]), with NaN on the line of the other trend, instead of Multiple(vec![value, direction]), and name their lines Up Trend and Down Trend, without the parameters; DirectionalMovement outputs Multiple(vec![plus_di, minus_di, adx]), NaN for a line without a value, and reports three lines and colours.

  • FloatingSelectionToolbar::show no longer panics when the window is narrower or shorter than the toolbar. On an axis where it does not fit, the toolbar is placed at the window’s left or top edge.

  • The indicator dialog starts each study from its own default parameters instead of one length of 14 shared by all, so Bollinger Bands open at 20 and EMA at 12, and it edits the Keltner Channels ATR length and multiplier and the Stochastic %K smoothing, which it fixed at 10, 2.0 and 3. IndicatorParams gains keltner_atr, keltner_multiplier and stoch_smooth; struct literals must set them.

  • Price auto-scale fits the visible values of visible overlay studies, every line they draw, together with the visible bars and through the same price transform, and skips values that are not finite. It fitted the bars alone, so a moving average or band outside their range ran off the pane. Chart::set_indicator_autoscale(id, false) leaves a study out of the fit without hiding it. VolProfileVisible and VolProfileFixed, whose values are volumes, draw no line. Migration: leave a study out to keep the bars-only range; ChartState::fit_price_scale takes the studies to fit, std::iter::empty() for the bars alone.

  • The time axis does a bounded amount of work for very long time spans and large right offsets, and formats only the labels it shows. Spans of a few hundred years and more show evenly spaced years.

  • TPO profiles add each bar in constant time instead of per row it spans, and a steady frame reuses the profiles of sessions whose bars did not change.

  • A Heikin-Ashi chart no longer recomputes its whole history when the forming bar ticks or a new bar opens: it updates the last bars of the cached transform, and draws the visible bars without copying them.

  • TimeScaleOptions::fix_left_edge works: when set, panning, zooming and scrolling stop with the first bar at the left edge of the chart, and when every bar fits the empty space is on the right. It had no effect, so its default is now false, matching how charts already behaved: the view can move up to 100 bars past the first bar.

  • Dragging the chart pans the price axis vertically while auto-scale is off, so a range zoomed by hand can be moved to other prices. Dragging used to pan in time only.

  • Price zoom stops at a span of a millionth of the price level on every price scale mode, also for views that cross zero: a percentage view, a logarithmic view of prices near 1, or a spread. It used to take a millionth of the visible bounds, which shrinks with each step across zero, until every price landed on the middle of the pane. Box zoom stops at the same span, and flat data on a logarithmic scale is fitted like flat prices, with margins taken from 1% of the price instead of 1% of its logarithm.

  • Box zoom zooms in time: the bars inside the box fill the chart width, up to TimeScaleOptions::max_bar_spacing, centred on the box, and a box inside one bar shows that bar across the width. It used to re-centre the view on the box and keep the bar spacing.

  • DrawingPropertiesDialog sizes its default frame to its tallest tab and uses the kit footer, with Apply as the only filled button and Delete and Clone as icon buttons, the kit colour picker, and line width swatches with a 1 to 10 px stepper; labels are in sentence case. Escape cancels the dialog and Enter applies it unless an open popup, colour picker or focused field takes the key.

  • Percent changes have the sign of the price change when the reference price is negative, as in spreads and some futures: the data window, the symbol header, the floating and tracking tooltips, the OHLC header, the position tools, the forecast tool, the measure tools, the percentage price axis labels and Bar::change_percent divide by the magnitude of the reference price, so a rise from -10 to -5 reads +50%. A zero or non-finite reference gives 0%, so the tooltips no longer show an infinite or undefined percentage for an open of 0. Migration: Bar::change_percent, OhlcData::change_percent and DataWindowInfo::change_percent change sign for a negative reference price.

  • Renko, Kagi, Line Break, Point and Figure and range bar charts are built once over the whole history and updated with each new bar, so their bricks, lines and columns no longer change while panning or zooming, and a steady frame no longer recomputes them. Only the newest 10,000 bricks or lines, or 5,000 columns or range bars, are kept.

  • Hollow candles are coloured by the close versus the previous close and filled by the close versus the open; the baseline chart uses a configurable level (a price or a share of the pane height, 50% by default) and splits segments where they cross it; the HLC area fills above the close in the up colour and below it in the down colour; volume candles scale by the largest visible volume whether or not the volume pane is shown.

  • Renko, Kagi, Point and Figure, range bars and Line Break use their own configured size, reversal and line count exactly, at any price level; a size the chart cannot use is reported on the chart instead of being replaced. Point and Figure columns draw each box at its own price instead of a running sum that drifted and stopped after 500 boxes, and a column whose boxes are under 2 px tall is drawn as a line.

  • The time axis no longer panics when a bar is stamped near the end of the representable date range, such as a millisecond timestamp read as seconds or DateTime::<Utc>::MAX_UTC: times it would extrapolate past the range are left out, and TickMarkGenerator::generate_marks stops at the last mark that fits.

  • The alert dialog and the alerts panel accept only a finite price or threshold, a multiplier above 0 and a lookback of at least one bar, keep Create disabled until the form is valid, and the dialog names the field to fix; an indicator alert set to compare with a threshold no longer loses an unreadable one.

  • A magnifier tooltip with a zoom of 0, a NaN or infinite zoom, or a lens larger than the plot no longer freezes or garbles the chart on hover: the zoom is drawn within 0.1 to 100 (NaN as 0.1), the lens is at most as large as the plot’s smaller side, and only the bars on screen are drawn in it.

  • model::to_range_bars_from_ticks and model::to_range_bars_from_ohlc leave out a volume that would make a range bar’s volume overflow, so two volumes near f64::MAX no longer give a range bar an infinite volume that breaks the volume scale.

  • The keyboard shortcuts dialog draws each key over its badge instead of under it, sizes itself to its content up to the window height with a scroll bar shown at rest once the list scrolls, lists only the shortcuts the crate handles, adds that the chart keys need the chart focused, and closes on an Escape only when no popup is open and no text field has focus, consuming the key.

  • The go to date picker no longer ignores a date it cannot parse: the field is outlined in the error colour, the line under it gives the expected format, and Go is disabled. In custom range mode Go is disabled until both ends are picked, the line under the field says which end to pick and then shows the range, a range no longer survives switching the mode or reopening the picker, and a typed date and the Today button pick a range end as a click on a day does. (#525)

  • The go to date picker closes when Go or Cancel is pressed. Go moved the chart and left the picker open over it, and Cancel did nothing; only the close button closed it. (#524)

  • IndicatorDialog::with_config keeps the configuration a caller sets: show no longer replaces it with the theme’s on every frame. Each colour left Color32::TRANSPARENT, as in IndicatorDialogConfig::default(), follows the theme passed to show. IndicatorDialogConfig::from_theme sets every colour, so a configuration built from it no longer follows a theme change, and it now takes muted_color from text_secondary instead of text_muted and sel_color from selection_bg instead of accent.

  • The indicator dialog’s Community category and its Profiles and Patterns tabs list nothing instead of the built-in indicators, since no source supplies those entries yet. Community also hides indicators a host passes to with_indicators, as IndicatorInfo has no community flag.

  • Returning to the live edge (a new bar while following it, tracking mode, the jump-to-latest button and TimeScale::jump_to_latest) restores the configured TimeScaleOptions::right_offset, or right_offset_pixels at the current bar spacing when set, instead of a fixed 2.5 bars; a time axis double-click restores the configured bar spacing before the offset, and a fixed right edge clamps it.

  • Overlay study lines walk only the values of the visible bars each frame instead of every value from the first bar, so their drawing cost follows the visible bars, not the length of the history (about 26.3M to 4.3M instructions per frame for SMA and EMA on 1,000,000 bars).

  • Volume bubbles draw as one mesh, each circle with as many sides as its radius needs to stay within a quarter of a pixel of round, instead of a filled circle and an outline shape per bubble, and the mesh reuses its memory from frame to frame. With 100,000 trades over 1,667 one-minute bars at 40 price levels a bar and 200 bars in view on a 1440 by 900 window, a frame tessellates 0.49 million vertices instead of 1.85 million and takes 13 ms instead of 33 ms, tessellation included; cargo bench --bench frame_time -- bubbles measures it. (#694)

  • Drawings that paint within a known reach of their anchors, such as shapes, patterns, Elliott waves and lines that are not extended, are skipped when that reach lies outside the pane’s time range, and the manager tracks last frame’s paints in time linear in the drawings instead of quadratic. The sine line draws its wave as one path instead of 200 line segments, and the circles of every drawing, such as anchor dots, wave labels and Fibonacci circles, become polygons with as many sides as their radius needs to stay within a quarter of a pixel of round instead of 32 to 128. With 500 drawings, every tool in turn, on a chart of 10,000 bars, a frame takes 15 to 17 ms instead of 17 to 21 ms when all are in view, at 364,000 vertices instead of 463,000, and 3.6 to 4.2 ms instead of 5.2 to 8.7 ms when they are spread across the history; cargo bench --bench frame_time -- "500 drawings" measures it. (#155)

  • A drawing that paints the same geometry as on the frame before reuses that frame’s tessellation: each run of lines, paths and fills becomes one mesh, tessellated once and kept until the drawing, the view, the scale or the tessellation options change, while its text and small discs are painted as before. Drawings are now also skipped when their reach lies above or below the pane, except tools that paint at prices from the bars or run a leg on past an anchor. Line segments that continue one another become one path for every line style, not only dashed ones, which halves the vertices of arcs drawn as chained segments, and the half circles of time cycles and speed resistance arcs get as many sides as their radius needs to stay within a quarter of a pixel of round instead of 32. A Fibonacci wedge tessellates 2,088 vertices instead of 3,600 and speed resistance arcs 424 instead of 1,652. With 500 drawings, every tool in turn, all in view on a chart of 10,000 bars, a frame tessellates 327,000 vertices instead of 362,000 and takes about 20 ms instead of 26 ms on a loaded machine, tessellation 12 ms instead of 19 ms; cargo bench --bench frame_time -- "500 drawings" measures it. (#155)

  • to_renko_bricks, to_kagi_lines, to_pnf_columns and to_range_bars_from_ohlc build with the size they are given, at any price level, instead of raising it to a share of the price range of the bars (a 200th, a 500th for Kagi and Point and Figure) or to 0.0001, and range bars no longer stop splitting a bar after 100 steps. A size that is not a positive finite number, or a Point and Figure reversal of 0 boxes, gives no elements. Renko and range bars start from a later bar when the bars move by more than two million sizes. Migration: pass the size to draw; the former behaviour was size.max((max_high - min_low) / 200.0) for Renko and range bars and / 500.0 for Kagi and Point and Figure.

  • A Line Break reversal line now starts at the open of the line it reverses, as the construction defines, instead of at its close.

  • ui_kit::Card is visible: it fills with the theme’s secondary surface, has a 1 px border and pads its content by 8 px. It filled with the panel colour and had no edge.

  • ui_kit::section::Section draws its icon 8 px before the title, inside the header row, instead of left of the header where it was clipped. Section titles are 11 px.

  • ui_kit::tab_bar::TabBar draws 12 px tabs 16 px apart from the content edge, each on a 28 px hit row, over a full-width rule that carries the active tab’s underline, and leaves 8 px before the content. A hovered tab brightens, tabs report their selected state to accessibility tools and show a focus ring. The alert and drawing properties dialogs no longer draw a second rule under their tabs.

  • ui_kit::toolbar::ButtonGroup lays out its content along the parent’s direction, side by side in a horizontal toolbar and stacked in a vertical one, and draws its separators across the group, not down the rest of the parent.

  • ui_kit::sidebar_layout::SidebarLayout insets its content 16 px from the divider and the top. Every SidebarTab reserves the icon slot, so labels line up whether or not a tab has an icon, and tabs report their selected state to accessibility tools and show a focus ring.

  • ui_kit::trading_labels::PnlLabel puts the sign before the currency symbol and groups thousands (”-$98.10”, ”+$1,234.56”), and shows no sign for zero, including -0.0. PnlLabel and SideLabel use the theme’s success and error colours, which are readable in every preset, instead of fixed chart tokens. Text that shows zero is in the normal text colour, not the gain or loss colour. The PnlLabel::percent example takes percent units, as the method does.

  • The command palette draws each command’s icon, description and shortcut, fills the selected and hovered rows with the theme’s selection and hover colours, reports rows as selectable buttons to accessibility tools, and takes the theme’s window corner radius and shadow.

  • ui_kit::PanelHeader uses one title style, the theme’s title size in the strong text colour, on a 36 px row with its actions 4 px apart. PanelHeader::strong has no effect and is kept for source compatibility.

  • CommandPalette::add_command and remove_command, and the same CommandPaletteHandler methods, rebuild the listed commands and keep the highlight on the same command, so changing the commands while the palette is open no longer panics or makes Enter run the command next to the highlighted one.

  • AutocompleteEdit no longer panics on Enter or Tab after a suggestion was picked from further down the list or the suggestions shrank: the highlighted row stays within the shown suggestions and returns to the first row after a pick.

  • Renko, Kagi, Line Break, Point and Figure and range bar charts keep their newest bricks, lines, columns and bars when they reach their element limit, and draw the newest ones, so the chart always ends at the last bar instead of losing the most recent data on a long or volatile history.

  • VWAP restarts at each trading day by default, counted in UTC, instead of accumulating over all loaded history. VolumeWeightedAvgPrice::with_time_zone and with_session count days in the instrument’s zone and trading hours, so a session that crosses midnight in the exchange zone or in UTC stays one period, and a window that spans midnight starts the next trading day at its open. A bar of a day or longer, which a feed stamps inside its UTC period, counts on its UTC date; bars count as a day or longer when no two consecutive bars share a UTC date. with_anchor restarts at each week or month instead (VwapAnchor), and with_std_dev_bands adds upper and lower bands at multiples of the volume-weighted standard deviation of the typical price. Migration: with_session_reset is removed, since restarting at each session is now the default; values of new() and the factory’s VWAP that were cumulative now restart each day, and those of with_session_reset restart in the exchange zone once a zone is set. To keep a cumulative VWAP over the whole series, use AnchoredVWAP::new(0).

  • The indicators, Go to, compare symbol, symbol search and export dialogs keep their content size under egui 0.37, which counts a window’s frame and title bar in its size, and their title bars span the dialog. The indicators, Go to and compare symbol dialogs keep their titles centred over the dialog, which egui 0.37 centres in the space left of the close button. The date picker centres its calendar in its configured width, which the calendar overflowed because it left out the spacing between days, and the indicator dialog keeps its width when the configuration panel opens.

  • An application that follows the system appearance, as egui does by default, keeps the theme applied with apply_to_egui when the system switches between light and dark. apply_to_egui wrote only the egui style in use, so egui switched to its own default style for the other appearance while the crate’s widgets kept the theme’s colours; it now styles both.

  • KDJ smooths K and D recursively from 50, weighting the new value by 1 / k_smooth and 1 / d_smooth (a third by default), as the formula is published, instead of with simple averages of those lengths, starts on bar period - 1, and draws its D and J lines. A bar with a non-finite close or window range has no value, and K and D carry over it unchanged. Migration: K, D and J differ on every bar, J most, so thresholds tuned on the old values need retuning.

  • Trend Intensity Index follows Pee’s definition: the share of the size of the last period deviations from the 2 * period bar simple moving average that lies above it, with the first value on bar 3 * period - 2. It counted the bars above the average of the same window, which reads 50 on any straight trend. Flat closes read 50 at any price level. Migration: values change, and bars period - 1 to 3 * period - 3 no longer have a value, so levels tuned on the old output need retuning.

  • VW-MACD is the 12-bar minus the 26-bar volume-weighted moving average of the close, with a 9-bar EMA signal, and starts on bar 25. It took exponential averages of one cumulative VWAP from the first bar, which shrank toward zero as history grew. Migration: values differ from those of the cumulative average, and bars before the slow period have no value instead of a line, so thresholds tuned on the old line need retuning.

  • SnapService::snap_point no longer panics when a snap target or the point is NaN: NaN targets are never chosen and a NaN coordinate is returned unchanged. BarData::min_price, max_price, price_range and max_volume skip NaN and infinite values, so the result no longer depends on bar order, and they return None when no finite value remains.

  • Logarithmic, percentage, indexed-to-100 and inverted price scales reach the screen. Candles and every other chart type, indicators, markers, drawings, the crosshair, the tooltip, the grid and the price axis render through the chart’s price scale; on an inverted scale High-Low bars are drawn, hollow candles keep their body clear of the wick, above-bar and below-bar markers sit outside the bar on screen, a click on a candle’s body or wick selects the series, and the volume profile drawings draw their rows and box with the VAH and VAL labels outside the value area. The series settings dialog’s scale mode and invert options apply to the main price scale (Chart::apply_series_settings), as does the mode given to ChartBuilder::with_right_price_scale. A new mode returns the scale to auto-scaling and clears the zoom history. Percentage and indexed modes are relative to the first visible close and keep the price order when that close is negative; the axis, the last-price label and the crosshair label show signed percentages or index values, and box zoom fills the pane with the selected prices in every mode. A range scaled by hand keeps its prices while the chart scrolls and when the zoom history restores it. A narrow logarithmic range is labelled in even price steps, and axis labels keep the same decimals at zero.

  • Logarithmic, percentage, indexed-to-100 and inverted price scales reach the screen. Candles and every other chart type, indicators, markers, drawings, the crosshair, the tooltip, the grid and the price axis render through the chart’s price scale, and the series settings dialog’s scale mode and invert options apply to the main price scale (Chart::apply_series_settings), as does the mode given to ChartBuilder::with_right_price_scale. A new mode returns the scale to auto-scaling and clears the zoom history. Percentage and indexed modes are relative to the first visible close and keep the price order when that close is negative; the axis, the last-price label and the crosshair label show signed percentages or index values, and box zoom fills the pane with the selected prices in every mode. A range scaled by hand keeps its prices while the chart scrolls and when the zoom history restores it. A narrow logarithmic range is labelled in even price steps, and axis labels keep the same decimals at zero.

  • The head and shoulders neckline runs through the two troughs instead of the two shoulders, and the target is projected from it at the last anchor: the head’s distance from the neckline, measured at the head, beyond the neckline on the side away from the head. No neckline or target is drawn while the troughs share a bar, where the neckline would be vertical.

  • XABCD, Cypher and ABCD ratio labels are measured in price, so they no longer change with zoom, pane size or scale mode. The XAB label is B’s retracement of XA (|B - A| / |A - X|), where it showed |B - X| / |A - X|, and the ABCD label is |D - C| / |B - A| in price, where it compared on-screen leg lengths mixing time and price. A ratio whose base leg is flat is not shown, where it showed 0.

  • Dragging the price axis zooms by each frame’s movement around the point where the drag began, so the zoom no longer depends on how many frames the drag spans.

  • The last-price line and label follow the newest bar instead of the last visible one, and are hidden while that price is off the scale.

  • KAMA’s efficiency ratio covers the last period bar-to-bar price changes, as Kaufman defines it, instead of the last period - 1, in both the net change and the sum of absolute changes. Migration: KAMA values from bar period onward differ on most series, so levels and signals tuned on the previous values need checking.

  • Chandelier Exit measures its distance from Wilder’s average true range, as the ATR study does, instead of a simple average of true range, and draws the short exit line as well as the long one. Migration: values after the first one change wherever the true range varies, so stops placed on the old values move.

  • On Balance Volume starts at 0 on the first bar instead of at that bar’s volume, which offset every value by that volume. Migration: every OBV value is lower by the first bar’s volume, so thresholds set on the OBV level need the same shift; changes between bars are unaffected.

  • Zig Zag draws its swings: each value between two consecutive pivots lies on the straight line joining them, instead of only the pivot bars having a value, which left nothing to draw. Bars before the first pivot and after the last stay empty, and a series without a reversal of at least the deviation has no values. Migration: pivots are the first and last bars with a value and the bars where the line changes direction, rather than the only bars with a value.

  • Built-in studies clamp float parameters into a documented range at construction, NaN to the bottom of it, as they raise a length of 0 to 1: multipliers, percentages and costs to 0 or more, the Accumulation Swing limit move and the Ease of Movement and Market Facilitation divisors to f64::EPSILON or more, the ALMA offset to 0 to 1 and sigma to 0.001 to 100, and the Parabolic SAR factors to at most 1, with the maximum no lower than the start. AccumulationSwingIndex::new(0.0), a NaN or negative band multiplier and an infinite ALMA sigma no longer turn every value into NaN or infinity.

  • FisherTransform follows Ehlers’ published construction: the normalised price is weighted by 0.33 instead of 0.66 before smoothing, the clamped value feeds the next bar, values beyond 0.99 are clamped to 0.999, and each Fisher value adds half of the previous one. Its output was off by up to several units in trends.

  • Ichimoku plots Senkou Span A and B displacement bars after the bar they are computed on and the Chikou Span displacement bars before its close, instead of all on the same bar, and each line starts once it has a value instead of every line starting at the Senkou B period with 0.0 in place of missing values. Values remain one per bar, so the leading spans computed on the last displacement bars are not drawn. Migration: the value at bar i now holds the spans computed on bar i - displacement and the close of bar i + displacement; a line without a value at a bar is NaN.

  • EaseOfMovement divides volume by 10,000 by default, as Arms defines the box ratio with volume in units of 10,000, instead of 1,000,000, which made every value 100 times too large. Migration: values with the default divisor are 100 times smaller; levels tuned on the old scale need dividing by 100, or with_divisor(1_000_000.0) keeps the previous scale.

  • Light theme text and control outlines are readable: secondary and muted text reach at least 4.5:1 on panels and windows, unchecked checkboxes and radios, text inputs and combo boxes have a 3:1 outline, and egui’s weak text uses the muted colour instead of fading by alpha. Dark theme secondary and muted text are raised to the same bar.

  • apply_to_egui sets error_fg_color and warn_fg_color from the theme, so error text no longer uses egui’s default pure red, and the status colours (success, warning, error, info) are defined per theme with at least 4.5:1 on its panels.

  • Hover and pressed fills in the light theme are visible against white (1.2:1 and 1.3:1, from 1.1:1), and the accent hover and pressed shades and the danger button reds keep white text at 4.5:1 or better.

  • The crate builds warning-free on current stable Rust: float literals that relied on the deprecated f32 inference fallback are now explicitly typed.

  • The documentation examples across the crate use the current crate name and module paths, and they compile as doctests with all features; those not marked no_run also run, and none is ignored. The icon_from_path! documentation now says its path is relative to the assets/icons/ directory of the crate that invokes the macro.

  • Cloning a CustomIndicator or CustomTimeFormatter now keeps its closure instead of replacing it with an empty or default one. Migration: CustomIndicator::new takes the closure directly (CustomIndicator::new(name, |bars| ...) instead of Box::new(...)), and the closure must be Sync.

  • The indicator dialog’s Momentum entry creates a new Momentum study (the close minus the close n bars earlier, in price units) instead of Rate of Change; Momentum is also registered in the indicator factory.

  • The export dialog no longer offers actions it cannot perform: the save path is typed into an editable field instead of a Browse button that set a fixed name, the data export text lists only the bar fields, and ExportDialog::with_formats limits the offered formats to those the host supports. Exportable::copy_to_clipboard, which discarded the image and reported success, is removed; copy a rendered egui::ColorImage with egui::Context::copy_image instead. The demo copies the chart image to the clipboard and saves PNG exports to the chosen path.

  • Dashed lines are clipped to the visible area before they are dashed, so a drawing anchored far off screen no longer hangs the UI thread or exhausts memory. Every dashed line in the crate (drawings, crosshair, price lines, session breaks, indicator pane zones) now shares this routine.

  • Auto-scaling flat price or indicator data now centres the series in a range proportional to the price level instead of collapsing to a near-zero range.

  • The anchored VWAP drawing computes the volume-weighted average of the typical price from its anchor bar, with bands one and two volume-weighted standard deviations away.

  • The fixed range and anchored volume profiles are built from bar volume, spreading each bar’s volume over its high-low range, with the point of control and a 70% value area. The anchored volume profile is placed with a single click and runs to the latest bar.

  • The regression trend fits the closes between its anchors by least squares and shows the resulting R² and the Pearson correlation of the closes.

  • The anchored VWAP, the volume profiles, the regression trend and Heikin-Ashi candles recompute when a bar inside their span is corrected, instead of showing values from the old bars until an anchor moved or the span grew. ChartState::set_data compares the new bars with the current ones to tell a correction from an append or a last-bar update, one pass over the bars per call.

  • A live volume profile or regression trend no longer recomputes its whole span when the forming bar ticks or a new bar opens, or after another drawing was dragged: it adds that bar to the cached result for the bars before it (a profile only while the bar trades inside the profile’s price range). At 1,000,000 bars a new bar costs about 0.002 ms instead of 20 ms for a profile, and a tick 0.001 ms instead of 5 ms for a regression trend. Heikin-Ashi candles no longer copy the whole transformed series on every frame.

  • Long and short position tools have a stop of their own that moves independently of the target, so risk/reward reflects the levels set; P&L replays the bars after the entry and shows the position as closed once the stop or the target trades. Both read n/a while the stop or the target is on the wrong side of the entry.

  • The forecast drawing shows the predicted change over its bar span and resolves to success once a bar reaches the target by the target bar, or to failure once the target bar has closed without that.

  • The bars pattern projection draws shifted copies of the selected bars.

  • The chart watermark falls back to the chart symbol and is hidden when there is none, instead of showing a placeholder.

  • The OHLC header of a chart without a symbol prints prices with the same magnitude-based decimals as the legend instead of 8 decimals, and labels the last bar’s volume as volume instead of 24h volume. The top toolbar’s symbol pill shows no symbol instead of AAPL when none is set, the chart and series context menus leave out their alert and order items until there is a symbol, and SymbolHeader leaves out empty info fields instead of drawing bare separators.

  • Zooming the price axis in by hand stops at a span of one millionth of the price level instead of narrowing to a few nanounits, and repeated zooming out can no longer overflow the price range to infinite or NaN bounds.

  • Timeframe::duration_ms saturates at i64::MAX for custom timeframes too large to represent instead of overflowing into a panic or a negative duration, and parsing a custom timeframe whose second count overflows is rejected.

  • Built-in studies raise a length of 0 to 1 and accept any longer length, alone or mixed with short ones, so a zero, huge or swapped period no longer panics, exhausts memory or yields only NaN (for example KAMA::new(0), SmoothedMA::new(0) and MACross::new(50, 20)).

  • SMA, VWMA, LSMA, Bollinger Bands, RSI, MACD and VW-MACD return one None per bar instead of no values when there are fewer bars than their period.

  • Stochastic no longer panics when all its periods are 1, Volume Profile Fixed Range no longer panics on a bar with a NaN price, and Rank Correlation no longer panics sorting NaN closes.

  • Rainbow Oscillator keeps a running sum instead of every SMA level, so a huge level count no longer exhausts memory.

  • Rainbow Oscillator divides the close’s distance from the mean of its averages by the close’s range over the last levels bars, as published, instead of by the mean itself. A bar whose range is zero has no value. Migration: every value changes scale, from a percentage of the price level to a percentage of the recent range of the close, so levels set on the previous values need to be set again.

  • Volume profiles refuse a row count above 10,000 and yield None for every bar instead of allocating that many rows for each bar.

  • to_tpo_profiles widens the tick size to a whole number of ticks when the bars span more than 1,000 ticks and skips bars with a non-finite or inverted range, so one wide or infinite bar no longer hangs the chart or exhausts memory. Migration: TPOProfile has a tick_size field holding the row height used, which TPOProfile::new takes as a second argument and which tpo_count_at, price_levels, letters_at and classify_shape use.

  • The CVD documentation states that it is estimated from bars and uses no trade or order book data.

  • The keyboard focus ring uses the applied theme’s ui.focus colour (egui’s selection stroke when no theme has been applied) instead of the selection fill at reduced alpha, so it reaches 3:1 on panels and windows in every preset, and 4.5:1 in the high-contrast preset (it was 1.2:1 in light themes and 2.0 to 2.3:1 in dark ones).

  • Widgets that meant the accent read the theme accent instead of the selection fill, which is pale in light themes: tab underlines, the sync button and its checkboxes, the selected drawing colour swatch, the open colour picker, the layout name input, the date picker range and Primary list item buttons. Text on an accent fill uses the theme’s on-accent colour, and Danger list item buttons fill from the danger button token.

  • Selected sidebar items and active chart control toggles use the selection fill and text colour (the sidebar painted accent text on an accent tint, 2.4:1 in dark themes), active tab labels use the strong text colour, descriptions on selected timeframe, chart type and template rows are no longer faded to 3.7:1, and the success status message uses the theme’s success colour instead of the accent.

  • Selected rows, tabs, menu items and calendar days render readable text on the selection fill instead of an empty accent bar (the selection text colour equalled the fill): white on the accent in dark themes, accent text on a pale accent fill in light themes.

  • Tooltips, popups and menus have padding, a hairline border, an elevated fill, a small radius and a tight shadow; windows get padding and a border.

  • apply_to_egui sets item spacing, window padding and menu padding from the design tokens instead of zero, so labels no longer touch their controls; toolbars, dropdown rows and stacked chart panes keep their own explicit gaps.

  • Switching the theme repaints everything: the bottom toolbar, date picker, range switcher, timeframe bar, right panel tabs, symbol header, chart context menus, OHLC tooltip, replay bar and command palette resolve their colours from the active theme instead of keeping the dark theme they were built with. Fields a caller sets on the public config of TimeframeToolbar, TimeframeBar or RightPanelTabs are kept; only the fields left at their theme-derived value follow the theme.

  • Custom-painted buttons (top toolbar, drawing toolbar, widget bar and the ui_kit buttons) draw a focus ring when they have keyboard focus.

  • The dialog close button no longer draws an accent outline at rest; it looks like an icon button, so only keyboard focus draws a ring around it.

  • The command palette search icon follows the theme instead of staying white, so it is visible in the light theme.

  • The native demo starts on Linux: it enables wgpu’s default backends instead of none.

  • The web demo publishes, next to its page, the licences of the egui default fonts (Hack, Ubuntu Light and the egui icon subset of emoji-icon-font) and the Lucide icons that its WebAssembly module embeds; THIRD-PARTY-NOTICES.md lists the fonts.

  • The README, package description, crate docs and ROADMAP state what the code does: the number of drawing tool types (counting cursor modes) and of registered indicator names, with a unit test that keeps those counts in step with the code; no unproven icon count; and no claim of magnet snapping, drawings saved by the chart or templates saved to disk, none of which works yet. The crate and module docs describe the modules, presets and data contracts as they are: which builder sets what, where pan and zoom live, that fetch_historical needs supports_historical, and that nothing consumes Datafeed or the services yet.

  • ROADMAP ticks an item only when it works end to end: unwired widgets, scale modes the chart does not render, drawing tools with wrong geometry and indicator lines that are computed but not drawn are now unticked or carry their limits.

  • The README’s Rust snippets compile and run as doctests against the current API (including the Datafeed example), and the install lines use version 0.2.

  • The QuoteSource docs describe when it is actually called: nothing in the crate polls quote sources.

  • Bar replay no longer panics when a frame is due more bars than remain, and ReplayState::update returns the number of bars actually advanced.

  • ListItem allocates its row once: rows are 28 px apart with no gap, hover, pressed and selected fill the whole row, and every content type starts its icon and text 8 px inside the row. Custom ListItemContent implementations paint inside ContentContext::rect and return the row response instead of allocating space of their own. Row colours come from the active theme, with a pressed state distinct from hover and on-accent text on selected rows, and rows report their role, label and selection to accessibility tools.

  • The AutocompleteEdit popup is exactly as wide as its input, has the popup border, aligns its suggestions with the input text and draws them in the theme’s text colour.

  • FormRow takes the height of its content instead of the remaining height of the panel, so consecutive rows and a following FormGrid stay visible. The label is centred on the widget’s line, and the description sits below it in the theme’s muted text colour.

  • The FilterWidget search icon and clear button sit inside the field, 8 px from its edges, and the field no longer grows by a pixel when hovered or focused. Clicking the clear button now clears the query.

  • The ColorPicker swatch is 28 px with a border that stays visible on dark colours and brightens on hover. Its popup is as wide as the swatch grid and uses the popup border, and the row below the grid shows the hex value and opacity of the selected colour.

  • The compare symbols dialog draws its symbols, labels and background in the theme’s colours when CompareSymbolsConfig leaves them at the default instead of drawing them transparent.

  • The ui_kit buttons share one state model. Rest, hover and press are each a visible step: neutral fills move one step further from the surface, and Primary and Danger fills darken, so pressed no longer equals hover or looks paler than it; a selected Button, IconButton or SplitButton is drawn as Primary, filled with the accent; enabled(false) renders exactly like a button inside add_enabled_ui(false); and a disabled Primary or Danger button is drawn as Secondary, so its faded label stays as readable as other disabled buttons, with an accent outline on a disabled Primary Button so a selected one still reads as selected.

  • ButtonVariant colours follow the active theme: Primary is the theme accent with its hover and pressed shades and on-accent text, Secondary a neutral fill one step above the surface, Outlined a border in the secondary text colour, Ghost the primary text colour, and Danger the danger button reds with on-accent text.

  • Button is as wide as its laid-out label plus 12 px on each side, instead of an estimate from the byte length, so every label gets the same padding and labels with multi-byte characters fit.

  • SplitButton points its chevron down whether or not it is expanded.

  • The ui_kit buttons report their role, label (the tooltip for icon-only buttons), and enabled and selected state to accessibility tools, and show their tooltip while disabled.

  • The kit Modal, ConfirmDialog, PromptDialog and the command palette draw their dimming backdrop below their window instead of over it, so the dialog is shown at full contrast. Clicking the backdrop closes a closable modal.

  • PromptDialog keeps the text typed into it between frames instead of resetting it to the initial value, so Enter and the submit button return what was typed.

  • The data window prints a negative price with the decimals of the positive price of the same magnitude, so -37.63 reads -37.63 instead of -37.63000000.

  • Saved drawings round-trip: stored_to_drawing restores the anchors (chart_points), so a restored drawing no longer disappears on the next frame, every tool type loads back, and every setting (line style, fill, font, extend, arrows, lock, visibility, per-timeframe visibility, z-order, Fibonacci levels, volume profile, regression trend and position size) is kept.

  • Every drawing tool’s display name parses back to that tool with FromStr, ignoring case; the Fibonacci extension, time zone, speed resistance fan, trend-based time and speed resistance arcs tools and the five Elliott wave tools were not parsed.

  • A drawing whose tool type is unknown is skipped with the error unknown drawing tool "Name" instead of one listing all 95 tool types.

  • ColorType::from_hex returns an error for input that is not six or eight hexadecimal digits, instead of panicking on a multi-byte character such as "aÄÄb" or accepting a sign such as "+F+F+F".

  • ColorType::from_hex and ColorType::from_rgba read the alpha as unmultiplied, as CSS and Color32::from_hex do, so "#FF000000" is fully transparent and "#FF000080" is half transparent red. They stored the unmultiplied channels as premultiplied, which drew a transparent colour as additive red and a translucent one too bright. Migration: code that passed premultiplied channels to from_rgba builds ColorType::Solid(Color32::from_rgba_premultiplied(r, g, b, a)) instead. Colours saved by earlier versions keep the values they were saved with; build them again from their hex or RGBA source to get the corrected colour.

  • Ease of Movement leaves a bar with zero volume and a nonzero range out of its average instead of counting it as a bar that did not move. A bar with a NaN or infinite high, low or volume has no value, and a window without any bar with a raw value has no value.

  • Zig Zag confirms its first pivot from the first reversal instead of starting at an extreme of the first bars, extends the current leg on an outside bar instead of reading it as a reversal, and skips a bar whose prices are not finite or not positive. The rules are documented on ZigZag. Migration: values change on most series, since the line now starts at the first confirmed pivot, usually earlier than before, pivots around outside bars move, a series at or below zero, such as a spread, has no values, and a deviation of 0 gives no values instead of a pivot on almost every bar, so swing levels read from the previous values need checking.

  • Fibonacci retracement levels are measured back from the second anchor, the end of the move: level 0 is drawn on the second anchor and 100% on the first, with each level’s price label, background band and hit area at the same height, and the Reverse option, which had no effect, now swaps the two anchors. Migration: saved retracements draw with their levels flipped; set FibonacciConfig::reverse to keep the previous placement.

  • The Gann fan draws each angle at its labelled ratio: an NxM line has N/M times the slope of the 1x1 line, so 8x1 is the steepest and 1x8 the flattest. They were drawn the other way round, so the drawn lines did not match the lines a click selects, and 1x3 used 0.333 instead of one third.

  • The sine line passes through both anchors, a peak and a trough half a period apart, with the centre guide midway between them and the amplitude label at half their price distance. It crossed the centre line at the first anchor and returned to it at the second, so it missed the second anchor unless both had the same price. Migration: a saved sine line keeps its anchors, and its first anchor is now a peak or trough instead of a crossing of the centre line.

  • The parallel channel’s second line starts and ends on the bars of the first two anchors, straight above or below them, and passes through the third anchor. It was shifted along the base line by a construction at right angles to it, so its ends sat on other bars and the connecting lines were slanted; the hit test now uses the drawn line.

  • The Gann box draws its 2x1, 3x1 and 4x1 lines and their mirrors from the first anchor to 1/2, 1/3 and 1/4 of the far edges, and counts its 0%, 50% and 100% levels from the first anchor’s price. The lines started at the top-left corner whatever corner the box was drawn from, and ended at a pixel slope that matched the labels only for a square box.

  • Time cycles repeat the interval between their anchors forward in time: each cycle is a half circle as wide as that interval, standing on the first anchor’s price, from the earlier anchor to the right edge of the chart. They drew six concentric half circles around the first anchor, from 0.5 to 3 times the anchor distance.

  • Several Fibonacci tools are corrected: channel levels lie on the side of the base line where the third anchor is, where they were always drawn on one side; speed resistance arcs open towards the first anchor’s price, below the end of a rise and above the end of a fall, where they were always drawn below; the speed resistance fan extends towards the side of its second anchor, where a fan drawn right to left was mirrored to the right; time zones fall on 0, 1, 2, 3, 5, 8 and on along the Fibonacci sequence, where the line at 1 was drawn twice; and the spiral is a golden spiral through the second anchor whose radius grows by the golden ratio every quarter turn, where it grew by that ratio per full turn from a tenth of the anchor distance and ignored the second anchor’s direction.

  • to_renko_bricks reverses only after a two-brick move: a close must move one brick beyond the open of the last brick, and the reversal brick starts at that open. A one-brick move against the trend drew a reversal brick over the last brick. Renko charts now show fewer reversal bricks.

  • parse_date_range("MTD") starts at 00:00 UTC on the first day of the current month, as YTD starts on the first day of the year, instead of 30 days before now. 1M still covers the last 30 days.

  • parse_date_range rejects a relative count below 1, such as "last -5 days" or "last 0 days", with DateRangeParseError::InvalidNumber instead of returning a reversed or empty range, and returns the same error for a count too large to represent instead of panicking.

  • An absolute range from parse_date_range includes its end date: "2024-01-01 to 2024-12-31" ends at the start of 1 January 2025, and a range whose two dates are equal covers that day instead of being refused. An end date on the last day chrono can represent returns InvalidDateFormat. Migration: the end of an absolute range is one day later than before, so code that added a day to include the end date no longer needs to. The end is exclusive: keep a bar when its time is before the end. DateRangeParseError::InvalidDateOrder reads “End date must not be before start date”.

  • TPO profiles count each period once at each price row instead of once per bar, and a bar’s period follows the whole minutes elapsed since the session’s first bar instead of advancing by at most one period per bar, so a gap leaves its periods empty and a bar 95 minutes into a profile with 30-minute periods gets letter D instead of B. On bars shorter than the period, a row touched by several bars of one period holds one letter and one TPO, which changes the point of control, the value area, single prints and poor highs and lows. On bars longer than the period, each bar takes the letter of the period it opens in, so letters skip the periods it also spans, for example A, C, E on 1-hour bars with 30-minute periods. Building a profile walks each row once per period instead of once per bar. Migration: TPOLetter::ts is the open time of the first bar of the letter’s period instead of the bar that placed it; letters and counts differ from earlier versions on series whose bars are shorter than the period or have gaps, and letters differ on bars longer than the period.

  • to_tpo_profiles uses the default letters when TPOConfig::custom_letters is an empty string, instead of panicking with a remainder by zero.

  • Time scale options whose minimum bar spacing exceeds the maximum, or is NaN or infinite, no longer panic when the chart is built, zoomed or box zoomed: a minimum above the maximum counts as the maximum, a NaN or infinite minimum as the default 0.5, a negative minimum as 0, and a NaN or infinite maximum as unlimited.

  • The crosshair price label sits in the price axis, aligned with the tick labels and in their font, shows the price with the decimals of the axis ticks instead of eight, and no longer ends in a ”+”. The time label sits on the time axis instead of over the volume bars, in the axis date format with the year when it is not the current one, and the vertical line runs through the volume pane.

  • The crosshair’s time label and its magnet snap take the bar nearest the pointer, the one the OHLC readout shows; they took the bar to its left when the pointer was past the middle between two bars.

  • The last price tag is aligned with the tick labels and in their font, and its text is black or white, whichever reads better on the candle colour; it was light grey at 2:1 or less. An axis label under the last price tag or a crosshair label is left out instead of showing in part, and the crosshair price label covers the last price tag it overlaps.

  • The crosshair line and labels follow the theme (chart.crosshair_line, chart.crosshair_label_bg and chart.crosshair_label_text); the light and high contrast themes showed the dark theme’s. The CrosshairOptions colours, including the label colours that nothing read, default to Color32::PLACEHOLDER, the theme’s colour, and override it when set. The light theme’s crosshair line is darker, 3.2:1 on white.

  • The floating tooltip shows its labels and values in two aligned columns in the proportional font, prices with the legend’s decimals (at most price_precision), and a 1 px border in the theme’s border colour instead of a 2 px ring in the candle colour. It sits in the top corner of the price pane away from the pointer instead of next to it, so it no longer covers the hovered bar. TooltipOptions::border_color_bullish and border_color_bearish default to Color32::PLACEHOLDER, the theme’s border colour; the tracking bar and the magnifier take the candle, crosshair and text colours from the theme.

  • Price and time axis labels use one font size, so month and day labels share a baseline.

  • The selected drawing’s handles are round, an accent ring around the chart background like the selection dots of a series, instead of white squares with a dark outline; the handle being dragged is filled with the accent. HandleConfig::color and selected_color default to Color32::PLACEHOLDER.to_array(), the theme’s accent.

  • A new drawing is pink (DrawingManagerOptions::default_color), a colour no default study uses, instead of a blue close to the EMA’s.

  • The legend’s O, H, L and C labels and the bullet after the symbol use the theme’s secondary axis text colour instead of fixed greys (#459), and its values and change the theme’s success and error colours instead of the candle colours, which read at 3:1 on the light chart.

  • The chart, series and drawing context menus hide the crosshair, its labels and the tooltip while they are open, open 2 px from the pointer (the drawing menu 6 px, clear of the clicked handle) and flip to the other side of it to stay 8 px inside the window, size themselves from the laid-out text and elide labels wider than 300 px, and draw with the theme’s menu frame, hover fill and shadow. Rows show the bound shortcut, formatted for the platform (“Ctrl+R” on Linux and Windows), only for actions with a key binding; the crate handles only Delete, destructive rows (“Remove 5 indicators”, “Delete”) use the danger colour, both menus format the clicked price with thousands separators, and every row reports its label and role to accessibility tools.

  • NotificationPanel stacks its toasts 8 px apart, newest nearest the corner, 16 px from the window corner. Every toast was drawn at the same spot, flush to the corner, so only one was visible.

  • Toasts are opaque and follow the theme: the window fill, border and popup shadow, text in the theme’s text colour (a title in the strong text colour, its message in the secondary text colour), and the icon and progress bar in the theme’s colour for the kind. They were translucent fixed-colour slabs, the same in every theme, with error text below 4.5:1. The close button can be clicked, and a timed toast’s progress bar spans the toast’s content instead of stopping 16 px short.

  • Alert takes its colours from the theme: the icon in the theme’s colour for the kind, the fill and border in that colour at 10 % and 40 %, and the title in the strong text colour with the message under it in the secondary text colour. It used fixed tokens tuned for the dark theme, so several icons fell below 3:1 in the light theme and the high contrast theme showed the dark colours. Every alert fills the available width, the dismiss button can be clicked, and the text starts 8 px after the icon instead of 16 px.

  • status_message draws Info in the theme’s info colour instead of the plain text colour, starts at the left edge of the content around it instead of 8 px in, and leaves 4 px above instead of 6 px.

  • Acceleration Bands average each bar’s widened high and low, as Headley defines them, instead of widening the average high and low by the average range, and draw all three bands.

  • Klinger Oscillator weighs volume by Klinger’s volume force, built from each bar’s range and the cumulative range of the current trend, instead of by the trend sign alone, and draws its signal line. Equal sums of high, low and close keep the current trend, a series too short for the long average has no values instead of values from a partial average, and a bar with a non-finite price has no value without ending the study. Migration: values differ from the signed-volume averages computed before, and every value is Multiple([oscillator, signal]), the signal NaN until it exists, where it was Single(oscillator) until the signal existed.

  • BarData::to_csv, to_csv_string and to_csv_with_indicators write a bar’s fraction of a second, and BarData::from_csv reads it, so bars less than a second apart keep their times through a CSV file. Whole-second times are written as before.

  • A replay speed that is not finite plays at 1x and a custom speed is clamped to 0.1x to 100x, so ReplayAction::SetSpeed(f32::NAN) or a negative speed no longer freezes a replay that still reports playing.

  • to_range_bars_from_ticks closes one bar per full range a tick crosses, up to 100, and always returns the bar holding the last trade, so a tick that closes a bar no longer loses the rest of its move and the series ends at the last traded price. It keeps the newest 5,000 bars, like to_range_bars_from_ohlc.

  • Trend Detection Index follows Pee’s definition, the absolute n-bar sum of n-bar momentum minus the excess of the 2n-bar over the n-bar sum of absolute momentum, and starts on bar 3n - 1. It returned the net move minus the path length, which is never positive. Migration: levels tuned on the old values need resetting, and the first value now comes 2n - 1 bars later.

  • The True Strength Index starts its averages at the first price change instead of a made-up zero change on the first bar, which skewed the index for dozens of bars after its warm-up, and draws its signal line.

  • ADX starts from the mean of the first n DX values, as Wilder defines it, instead of n - 1 values divided by n, so it no longer reads low after its warm-up.

  • ATR with length 1 has a value on a single bar, its range, instead of none until a second bar exists.

  • The Commodity Selection Index computes Wilder’s formula, ADXR * ATR(n) * (V / sqrt(M)) * (1 / (150 + C)) * 100, from the ADX and ATR studies, and starts on bar 3n - 1; it used a simple mean of true ranges, an unsmoothed DX and a division by the close. Migration: CommoditySelectionIndex::new(period, cost) is now new(period); set the contract with with_point_value, with_margin and with_commission. The old cost parameter had no counterpart in Wilder’s formula.

  • The release workflow fails when cargo publish fails; it skips the publish only when crates.io already has the exact version.

  • Bars with a non-finite value, a high below the open or close, a low above them or negative volume are dropped and counted instead of drawn; bars out of time order are sorted, and of several bars with one open time, or in one slot of the timeframe for a chart built with a feed, the last is kept. This holds for Chart::new, set_data and update and for the bars a feed sends.

  • A live update no longer copies the history: the chart merges new bars in place and updates its studies once per frame from the first changed bar instead of recomputing them on every update.

  • Removing a study no longer moves the selection to another study, and removing the selected study clears the selection.

  • Loading older bars with Chart::set_data moves the drawings with their bars, and so does a bar that Chart::update or a feed inserts between stored bars.

  • The Schiff pitchfork’s median starts at the first anchor’s time, halfway between the first and second anchors, and runs through the midpoint of the second and third anchors with the tines parallel to it. It started at the first anchor and was aimed halfway between that anchor and the midpoint, so the median and both tines had the wrong slope.

  • An Image drawing draws its checkerboard only where it is visible, so a large frame, or a stored anchor far off screen, no longer stalls every frame.

  • Fibonacci retracement and extension levels are drawn, labelled and hit at the price they are labelled with on every price scale, where on a logarithmic scale the line sat at the interpolation of the anchors’ screen positions and its label named another price. The hit test of a retracement and of an extension follows the visible levels of their config, where the extension tested the retracement’s fixed levels. Drawing gains the field level_ys, the screen y of each visible level, rebuilt by update_screen_coords. Migration: construct a Drawing with Drawing::new instead of a struct literal, and call update_screen_coords after changing fib_config or chart_points before rendering or a hit test. A retracement or extension with fewer than two chart_points, as Drawing::add_point leaves it, now draws nothing, where it drew its levels from the screen points.

  • A bar with a non-finite price or volume no longer blanks every later value of KAMA, On Balance Volume, ATR, Fisher Transform, Ehlers Fisher, Chandelier Exit and the Commodity Selection Index: that bar has no value and the study continues past it, as the new Indicator section on non-finite bars states.

  • The floating replay bar’s shortcuts (Space, Home, End and the arrow keys) no longer act while a text field has focus, a popup is open or a control outside the background layer has focus, and take their key when they act, so a space typed in the symbol search no longer toggles playback and Space on a focused button presses that button. Escape no longer hides the bar: a close button on the bar does, FloatingReplayControl::show_control shows it again, and the demo’s Replay button shows a hidden bar instead of stopping replay. The bar is also drawn in the frame a shortcut acts in.

  • The floating replay bar draws Go to start and Previous bar disabled on the first bar, and Next bar and Go to end disabled on the last. FloatingReplayControl::sync_from divides the zero-based bar index by the last index instead of the bar count, so the last bar reads 100% instead of 99.7% for 300 bars.

  • A bar with a non-finite close no longer blanks every later value of EMA, DEMA, TEMA, SMMA, GMMA, McGinley Dynamic, VIDYA, ZLEMA, EMA Cross, MACD, VW-MACD, PPO, TRIX and Stochastic RSI (VW-MACD also needs a finite volume): that bar has no value and the study continues past it.

  • A bar with a non-finite input no longer blanks every later value of Elder Ray, Force Index, Mass Index, TSI, SMI, STC, DMI, Keltner Channels, Chaikin Volatility, VWAP, Anchored VWAP, A/D, CVD, VPT, PVT Enhanced, PVI, Williams AD, the Accumulation Swing Index, Volume Oscillator and both volume profiles (the high, low, close, open or volume the study reads): that bar has no value and the study continues past it.

  • A bar with a non-finite input no longer leaves finite but wrong values after it in RSI, Connors RSI, Stochastic, KDJ, Double Stochastic, Williams %R, Ultimate Oscillator, Pretty Good Oscillator, Relative Vigor Index, Know Sure Thing, Trend Intensity Index, Elder Impulse, MFI, VWMA, Ease of Movement, Historical, Close-to-Close, Garman-Klass and Parkinson Volatility, rank correlation, ADX, SuperTrend, Parabolic SAR, Aroon, Ichimoku, Donchian Channels, Price Channel, Pivot Points, 52 Week High/Low and Choppiness, True Range, Vortex, Squeeze Momentum, Majority Rule, Chaikin Money Flow and Klinger (the high, low, close, open or volume the study reads): that bar has no value and every later value equals the one for the series without it.

  • “52W HL%” measures its range over the bars within 364 days of the current bar’s timestamp on every interval instead of over 252 bars, so on a 1-minute chart it no longer covers 252 minutes, and has no value before 52 weeks of history. The new “52W High/Low” (Week52HighLowLevels) draws the highest high and lowest low of the same window as two lines on the price pane. Migration: replace Week52HighLow::new(period) with Week52HighLow::new(); intraday charts with less than a year of bars show no value. The factory category for both 52W studies changes from “Breadth and spread” to “Market structure”.

  • Net Volume signs each bar’s volume by its close against the previous close (positive up, negative down, zero when equal) instead of against its own open, so a gap no longer inverts the sign, and the first bar has no value. Migration: the first value is blank and signs differ on bars that open away from the previous close.

  • ZeroTrendVol computed the Parkinson high-low estimator; that calculation is now ParkinsonVol in parkinson_vol.rs, still registered as “Parkinson Vol” with unchanged values. “Zero-Trend Vol” (ZeroTrendVol) is the zero-mean close-to-close estimator: the square root of the mean squared log return, annualised by sqrt(252) * 100. Both assume daily bars (#672). Migration: Rust code that built ZeroTrendVol for the high-low estimator builds ParkinsonVol.

  • Balance of Power with smoothing of length n has no value on its first n - 1 bars, and none on any bar of a series shorter than n, instead of plotting the unsmoothed ratio there. A bar with a non-finite price has no value and the average is taken without it. Migration: the first 13 bars of the default Balance of Power are blank instead of raw ratios.

  • PPO seeds its signal line with the mean of the first signal values of the PPO, as MACD defines it, instead of an EMA over zeros before the PPO exists, and returns the histogram (PPO minus signal) as a third line, so line_cnt, line_names and colors report three lines. The new PercentageVolumeOscillator, registered as “PVO” with lengths 12, 26 and 9, returns the same three lines computed from volume. Migration: PPO values from bar 33 (for 12, 26 and 9) are Multiple([ppo, signal, histogram]) and the signal differs on every bar, since the zero start no longer pulls it down; PriceOscillator::with_colors and set_colors keep the colour of a line they are given none for.

  • Zig Zag pivots sit on the swing extremes: when a reversal is confirmed, the new leg starts at the lowest low or highest high since the pivot it reverses from, not at the confirming bar, and the bars after that extreme are judged against the new leg, so the line touches every swing extreme. depth is now the minimum number of bars from a pivot to the bar that confirms the next reversal, and two pivots can be fewer than depth bars apart. Migration: values change on any series with a swing extreme fewer than depth bars before its confirming bar, which with the default depth of 10 is most series, so swing levels read from the previous values need checking, and a depth chosen to keep pivots apart no longer does. A bar with a non-finite price has no value and is not counted in depth, as if it were not in the series, instead of being drawn across.

  • A replay’s playback state follows seeks and steps: ReplayState::jump_to_bar and step_forward mark the replay finished whenever they land on the last bar and paused when they leave it, as step_backward did, and reset, init and enter_replay_mode apply the same rule, so a reset after the end is paused and a one-bar replay starts finished. Playing after seeking back from the end continues from the bar sought to instead of the first bar, and toggling play (ReplayAction::TogglePlayPause, the play button and Space in ReplayControls) on a last bar reached by a seek or a step restarts the replay instead of doing nothing; ReplayAction::Play still does nothing on the last bar.

  • ReplayController::load_data during an active replay keeps the replay time: the position moves to the last bar that opens at or before it and a playing replay keeps playing, instead of restarting paused on the first bar. On a coarser interval the bar that contains the replay time is shown whole. The demo reloads its replay this way on an interval change, so the next step no longer brings back the old interval’s bars. Migration: to restart a replay on new data, stop it first or send ReplayAction::JumpToStart after load_data; a series that ends before the replay time resumes finished on its last bar.

  • An indicator alert needs an Indicator A and either an Indicator B or a threshold: the alert dialog keeps Create Alert disabled and names the missing field (“Choose Indicator A”, “Choose Indicator B”) until it has them, and AlertsPanel::get_indicator_alert_form returns None for a blank indicator, so the panel’s Create stays disabled. Both used to create an alert with nothing to compare against.

  • A drawing placed with clicks keeps exactly the anchors that were clicked: the pointer preview between clicks is no longer kept as an anchor, so a parallel channel, a pitchfork or a triangle needs three clicks rather than finishing on the second with its last anchor repeated, the pattern and Elliott tools take one click per anchor, and a trend line or a polyline no longer stores an extra point where the pointer last was.

  • Releasing a drag that has left the price pane, over an axis or outside the chart, finishes the drawing with its last anchor on the pane’s edge, and ends a handle drag, where the drawing stayed in progress until the next drag on the pane or Escape and the handle kept following the next drag.

  • A locked drawing can no longer be moved or reshaped by its handles, or removed by the eraser, the Delete key, DrawingManager::delete_drawing (which the drawing’s context menu, properties dialog and object tree row call) or DrawingManager::clear_all (Remove all drawings), until it is unlocked, and the eraser no longer highlights it.

  • Drawings are drawn in ascending Drawing::z_order and hit from the highest down, in list order where it is the same, so a layering set with ZOrderService takes effect and survives a save and load. DrawingManager::bring_to_front and send_to_back set z_order instead of moving the drawing in DrawingManager::drawings, a drawing created with the tools starts on the top layer, and a drawing restored through DrawingManager::add_synced_drawing keeps its stored z-order.

  • A drawing shown only on some intervals is no longer drawn on the others, and Chart::set_timeframe sets the interval its visibility is checked against, where the check always used 1D and applied only to selection. The Visibility tab of the drawing properties dialog names the minute intervals 1min to 30min, as the chart’s interval label does, where it offered 1m to 30m, which matched no interval.

  • The trend line, ray, extended line, horizontal and vertical lines, horizontal ray, cross line and trend angle are drawn in the drawing’s dashed or dotted line style, and a trend line set to extend left or right reaches that edge of the pane and is hit along the extension, where these lines were always solid and the trend line ended at its anchors.

  • A drawing restored with stored_to_drawing keeps the id, creation time and notes of its stored record in the new Drawing::stored_id, created_at and notes fields, and drawing_to_stored saves it back under them, where a load and save renamed every drawing to its session id, reset its creation time and dropped its notes. DrawingManager gives a new drawing an id above every id its drawings hold or are stored under, so a drawing created after a restore no longer replaces an older stored one. Deleting a restored drawing queues DrawingSyncAction::Delete with its stored id, and a copy of a drawing passed to DrawingManager::add_synced_drawing while the original is there is saved as a new drawing rather than over the original. Migration: construct drawings with Drawing::new, or set stored_id, created_at and notes in a struct literal of Drawing.

  • The measure, info line, price range, date range and date and price range drawings report durations from the bars’ times instead of counting a bar as one minute, the volume traded between their anchors, and the price change with its sign; the info line’s angle is positive for a line that rises on screen. The measure no longer prints a pips figure computed as the price change times 100, nor Vol --.

  • The flat top/bottom and disjoint channel drawings label the price distance between their two lines as drawn on the chart’s price scale, logarithmic included, with its percentage of the lower line, and the rectangle labels its width in bars and its height in price, all from the anchors’ bars and prices instead of screen pixels, so the labels no longer change with zoom and pan. The trend angle prints its price change, bars and duration in place of a pixel length and slope.

  • The Fibonacci channel moves its levels straight up or down from the base line, as the parallel channel moves its second line, so each level is as far in price from the base at every bar; on a sloped base they were moved at right angles to it and slid sideways.

  • Fibonacci retracements, extensions and channels are selected along the level lines they draw and nowhere else: over the extent the lines are drawn, including the part extended to the chart edge, and for the channel along its sloped levels instead of fixed horizontal ones. The undrawn diagonal between the anchors no longer selects them.

  • Rays, extended and cross lines, horizontal rays, price and date ranges, the measure, polylines, paths, brushes, arrows, trend angles, info lines, the harmonic, head and shoulders, triangle and Elliott wave patterns, triangles, circles, ellipses, arcs, curves, every pitchfork and the pitchfan, the Gann fan, box and squares, the flat top/bottom and disjoint channels, and the Fibonacci time zones and speed resistance fan are selected anywhere along the lines they draw, from the same geometry their renderers draw, where they could be selected only near an anchor. The measure, date range, date and price range, Gann box and squares, the two channels, and filled triangles, circles and ellipses are also selected inside the areas they fill; brushes and the highlighter are selected across the width they are drawn at. The Gann fan is hit along its nine lines to the chart edge instead of eight lines that stopped at the second anchor, and an unfilled circle is no longer selected at its centre.

  • A ray whose second anchor is left of its first is drawn, and selected, from its first anchor through its second to the left edge of the pane; it ran from its first anchor to the right edge, away from its second.

  • DrawingStorage::to_json refuses a drawing whose tool is a cursor, such as the eraser, with SaveError::Cursor, instead of saving a drawing that from_json skips on the next load.

  • DrawingManager::pending_sync receives one DrawingSyncAction per drawing for every change to a stored field: drawings finished by a drag, a double-click or Enter, clearing all drawings, hiding or locking them all, bringing to front, sending to back, undo, redo and a copy added with add_synced_drawing now queue theirs too. The new DrawingManager::edit_drawing applies an edit, records it for undo and queues it, and DrawingManager::drag_edit_drawing with end_drag_handle makes a continuous edit, such as a colour picker drag, one undo step and one update. The host drains the queue; the chart never does. Migration: clear_all now queues a Delete for each drawing it removes, so a host that saves from the queue deletes their stored records; to unload drawings without deleting them, clear drawings, then call cancel_curr_drawing and deselect.

  • Choosing the eraser in the drawing bar lets a click delete the drawing under the pointer. The chart erased only while a crate-private flag was on that nothing set; it now follows DrawingManager::eraser_mode, which the new DrawingManager::set_eraser_mode switches on (leaving the active tool) and off, and which choosing a tool with set_active_tool switches off.

  • In eraser mode a click deletes the drawing under the pointer while another drawing is selected too, instead of selecting it; a locked drawing is still not erased, and Escape switches the eraser off.

  • The drawing bar’s “Save as Template…” opens a template name dialog that stays open until the name is saved or the dialog is cancelled, instead of closing on its first frame because its empty name read as a cancel. The visibility flyout closes when the dialog opens. TemplatesButton::show_name_dialog returns Some(DrawingToolbarAction::None) on Cancel or Escape, where it returned None, so a caller can tell a cancel from a name still being typed.

  • The drawing bar’s Icons/Emojis button opens a menu of icons and emoji that emits DrawingToolbarAction::InsertEmoji, drawn with the app’s fonts (the demo enables egui’s monochrome_emoji_fonts and lists Noto Emoji and emoji-icon-font in its font licences), and the next click on the chart places the one picked, as does every later click in keep-drawing mode; the button opened nothing, and a click after DrawingManager::start_icon_insertion placed a default * instead of the picked icon.

  • The drawing bar scrolls when the window is shorter than its buttons, so Templates, Hide and Remove stay reachable, and its flyouts scroll when they are taller than the window. A flyout opens beside its button, closes on an outside click or Escape without also clearing the chart’s drawing state, and closes after a pick unless keep drawing is on.

  • The drawing bar’s buttons and flyout rows no longer overlap their neighbours by 3 and 5 px, so a click near the lower edge of a button no longer activates the next one. Tooltips open to the right of the bar instead of over the next button.

  • The drawing bar shows the state it was left in: the cursor button shows the chosen cursor or the eraser, the cursor menu checks the current one and the values tooltip option, the magnet menu has an Off row and checks the current mode, and the magnet button is filled while snapping is on. Zoom and the cursor are no longer highlighted at the same time.

  • The selected drawing bar button and flyout row use the accent fill with the accent text colour, readable in every theme; hovered and selected rows differ. Section headers and shortcut hints in the flyouts are 11 px and use the secondary text colour, and a flyout is as wide as its widest row, so “Elliott Triple Combo Wave (WXYXZ)” no longer meets the border.

  • The drawing bar’s menus share one look: rows 28 px high with a 16 px icon column, the theme’s menu fill, border and shadow. The Hide menu reads “Hide drawings”, “Hide indicators”, “Hide positions” and “Hide orders”, the Remove menu shows its two rows in the error colour, and the Text flyout’s sections read “TEXT & NOTES” and “CONTENT” in the order the bar uses.

  • Typing ”/” in a text field no longer opens the drawing bar’s tool search; with no field focused it opens a search field beside the bar, with a close button.

  • Drawing bar buttons and flyout rows have a role, a name and their selected state for assistive technology, and rows show a focus ring.

  • MAChannel::new takes the upper and lower lengths, and MA Channel draws the simple average of the highs and of the lows, where it drew a simple average of the closes with percentage bands; the LinReg Channel input multiplier is replaced by upper_multiplier and lower_multiplier. Saved templates and layouts keep loading. Migration: MAChannel::new(period, offset_percent) becomes MAChannel::new(upper_length, lower_length), with with_offsets(upper, lower) for bar offsets, and the former lines are Envelopes::new(period, offset_percent, EnvelopeAverage::Simple); MA Channel colour lists hold the upper line, the lower line and the fill. Code that sets the multiplier input of LinReg Channel sets upper_multiplier and lower_multiplier. Envelopes colour lists gain the fill as a fourth entry, and LinReg Channel lists gain the upper and lower band fills as a fourth and fifth. Code that relied on Envelopes::default() at 2.5% or LinearRegressionChannel::default() at 20 bars passes those values to new. (#1492)

  • Drawing gains the public fields position_target_color and position_stop_color, and DrawingProps gains tick_size. Migration: add position_target_color: None and position_stop_color: None to Drawing literals and tick_size: None to DrawingProps literals, or end them with ..Default::default(). DrawingProps::from_drawing reads the tick size of the chart’s instrument; properties assembled by hand supply a positive finite tick_size to enable the tick inputs. Saved drawing files stay compatible. (#1408)

  • DrawingProps::timeframe_visibility, a TimeframeVisibility, replaces visible_all_timeframes and visible_timeframes, TimeframeVisibility gains the public field ranges, and DrawingPropertiesAction::Apply carries its properties as a Box<DrawingProps>. Migration: read and set the dialog’s visibility through DrawingProps::timeframe_visibility, such as props.timeframe_visibility.show_on_all; add ranges: Default::default() to TimeframeVisibility literals; build Apply with Box::new(props), and read a matched payload as before, since its fields are reached through the box. TimeframeUnit moves from the interval menu to model, so the drawings code builds without the ui feature, and is now ordered; ui::top_toolbar::TimeframeUnit keeps working. (#1368)

  • FibonacciConfig gains the public fields level_width and level_style, and ChartView gains price_formatter. Migration: add level_width and level_style to FibonacciConfig literals, or end them with ..Default::default(); add price_formatter: None to ChartView literals, or Some(&formatter) with the host’s PriceFormatter to format the price labels of drawings as the chart does. New drawings use ratio labels and the updated construction defaults, and saved explicit settings stay intact. (#1380, #1381, #1382)

  • Trading::is_connected is false while the broker reports that it is connecting or disconnected, where it was true whenever a broker was set. Migration: code that used it to tell whether a broker is set, for example to show the account panel or to open the broker picker, calls the new Trading::has_broker. (#1484)

  • TPOProfile::tpo_count_at, price_levels, letters_at and classify_shape no longer take a tick size and key on the profile’s own tick_size, the row height to_tpo_profiles used. The configured tick they took gave wrong prices and counts once to_tpo_profiles widened the rows. Migration: drop the tick size argument, so that profile.tpo_count_at(price, tick_size) becomes profile.tpo_count_at(price). (#1308)

  • MagnetType::OHLC is removed; it snapped as MagnetType::Strong, which replaces it, so the magnet menu lists Off, Weak and Strong. Migration: use MagnetType::Strong, and read a stored OHLC choice as Strong. Hosts that handle drawing toolbar actions apply DrawingToolbarAction::HideAll by hiding every supported drawing, indicator, position and order group, and DrawingToolbarAction::RemoveDrawingsAndIndicators by removing both groups, each in one undo step; the new menu rows do nothing until the host handles them, and position and order handling stays with the host. Measure is no longer a saved drawing, so a host that needs a persistent measurement adds one with DrawingManager::add_drawing; loaded and explicitly added Measure drawings keep ordinary drawing behaviour. (#1409)

  • DrawingPropertiesDialog holds its named templates in DrawingPropertiesDialog::templates, kept in memory unless the host attaches its Storage service, and restores an unfinished preview when it closes. Migration: construct the dialog with new() or default() instead of a struct literal, retain the instance, and call show_and_apply each frame, including after closing it externally. (#1367)

  • The drawing storage format is version 3 (DrawingStorage::CURRENT_VERSION), which tells editable ray and extended-line extensions from flags earlier renderers ignored. DrawingStorage::from_json migrates versions 1 and 2 with those extensions set to their former reach, including the direction of reversed rays, and later saves keep explicit extension edits. Migration: hosts that read the storage JSON themselves must accept version 3; older releases cannot load it. (#1372)

  • Envelopes::new takes its average as an EnvelopeAverage, Simple or Exponential, instead of a string, for which any value but "EMA" computed a simple average under that name. Values, the middle line names SMA(20) and EMA(20) and saved inputs are unchanged; the Average input lists Simple and Exponential. Migration: pass EnvelopeAverage::Simple for "SMA" and EnvelopeAverage::Exponential for "EMA". (#1333)

  • IndicatorFactory::register and register_in return whether they registered the constructor, and refuse a name that is empty or only whitespace. A constructor already registered under the name, a built-in included, is replaced, as before. Migration: a call used as a value of type (), such as a match arm or the last expression of a closure, ends with a semicolon. (#1335)

  • Built-in studies have refined default colours, transparencies, widths and line styles that read on the light and dark themes. Averages and VWAP are blue, oscillators use individual hues with muted dotted or dashed guides, and Bollinger Bands have a red upper boundary, a blue basis, a teal lower boundary and a faint blue fill. Volume columns are teal and red at 50% opacity. MACD, PPO and PVO histograms shade rising and easing columns above and below zero. Study legend backdrops default to 60% opacity and fit their text. Volume profiles draw the point of control as a solid line in the text colour and hide the value area boundaries unless VolumeProfileConfig::show_value_area_lines is set; TPO profiles hide single prints by default. A pitchfork with edited levels fills each band in the colour of its outer level. Saved explicit study colours and palettes load unchanged. Migration: studies::palette constants keep their names with refined values; DEEP_GREEN, DEEP_ORANGE, GOLD and INDIGO are removed, so code that named them uses the values they held (Color32::from_rgb(27, 94, 32), (255, 87, 34), (255, 193, 7) and (63, 81, 181)). VolumeProfileConfig literals add value_area_colors and show_value_area_lines or use ..Default::default(). (#1298)

  • The long and short position tools draw their handles only while selected, from the shared handle painter, and stroke only the entry line. The target and stop labels are sized to their text and centred above and below the box, with the amount gained at the target and lost at the stop; the P&L, quantity, risk/reward and capital sit in one block on the entry line, on the stop side, coloured by the result; and a dashed line runs from the entry to the exit, over the part of the zone the trade covered. Compact labels, muted theme-aware fills, finer hollow handles and a thin light border around the selected stats block keep the chart readable in both themes. Migration: PositionToolSizingTokens loses label_info_width, label_info_height, label_target_width, label_offset_x and text_offset_x, which no layout uses any more. (#1266)

  • TickMarkType::TimeWithMilliseconds marks fractional-second ticks and subsecond crosshair clocks. Migration: exhaustive TickMarkType matches handle the new variant, and custom TimeFormatters format it, as the trait default now asks for it instead of appending the fraction to a seconds clock. (#1227, #1228)

  • Chart’s per-frame pan, zoom, tracking, focus, keyboard and drawing handlers, including handle_drawings and render_eraser_highlight, and calculate_bar_spacing are now crate-private; unused calculate_visible_bars is removed. Migration: input is handled by Chart::show; dispatch host shortcuts with Chart::dispatch_shortcuts, and zoom from code with set_visible_logical_range or execute_box_zoom. execute_box_zoom remains public and zoom_back undoes it. (#1311)

  • TPO charts use a smooth period gradient, separated blocks, neutral POC rows and initial balance bars, compact value-area and midpoint labels, and a thin price path. Profiles have clearer session spacing and theme-aware contrast in dark and light views; when sessions are too narrow to hold the labels, as on zoomed-out daily charts, the labels are left out and the profiles keep their full session width. (#1296)

  • Session volume profiles use faint session boxes, blue and violet volume stacks, distinct value-area shading and thin red POC lines in dark and light themes. Default value-area guides, node labels and developing traces are hidden; shared trade-profile rows gain crisp gaps, theme-aware value-area opacity and a thinner POC stroke. (#1297)

  • UserSettings is #[non_exhaustive], so that fields can be added without a breaking change. Migration: build UserSettings with Default and assign fields. IndicatorDialogAction implements Clone and Debug, and SettingsAction implements Debug.

  • Migration for scale settings: ScalesAndLinesSettings, ChartConfig and PriceAxisOptions literals add the new display fields or use ..Default::default(). Older saved settings take their defaults. chart::render_axis_currency takes an optional unit before the currency choices; pass None for the previous header. PriceScale::set_bar_ratio accepts a positive finite number of scale units per bar, with None unlocking it; logarithmic axes measure natural logarithms of prices.

  • EventVisibility struct literals add show_earnings_breaks, show_news_notifications and show_ideas or end with ..Default::default(); saved visibility without them takes the defaults.

  • chart::render_alert_levels takes active_only after labels; pass true to keep drawing only active alerts. AlertsSettings literals add show_active_only and notification_seconds or use ..Default::default(); older saved settings take defaults. Hosts apply lifetime through AlertsPanel::set_notification_seconds; sound playback uses the existing host audio path.

  • ChartTypeStyles, CandleColorConfig, StatusLineOptions and ChartSettingsState gain the requested candle, status and dividend fields. Struct literals add the fields or use ..Default::default(); older saved settings take defaults. chart::render_candle takes the rising/falling direction after the bar and &CandlesStyle last; pass bar.is_bullish() and &CandlesStyle::default() for the previous drawing behaviour.

  • Chart settings use seven tab pictograms, a 206 point sidebar with 40 point rows, neutral selection and an undimmed backdrop. Shared dialog titles use semibold 20 point text, and footer actions are at least 44 by 34 points with a primary fill in the theme text colour. (#991)

  • The chart layout menu shows arrangement diagrams grouped by chart count from 1 through 16, including available alternatives, and highlights the active arrangement. Hover labels name each arrangement and explain synchronization effects. Short windows scroll the menu. (#997)

  • The indicator browser lists Profiles and Patterns and searches across built-in pages. IndicatorFactory::register_in accepts host categories, including PERSONAL for My scripts and COMMUNITY for shared studies. Destinations without compatible studies stay hidden, host-only catalogues open their populated page, and Favorites retains its explanatory empty state. Migration: exhaustive IndicatorCategory matches handle MyScripts; volume and time price profiles now use the Profiles factory category (IndicatorFactory::PROFILES) instead of Volume. (#972)

  • A click, or Enter or Space, on an indicator browser result adds the study at once with its default inputs, and the browser stays open for the next one; an added study’s inputs are edited through its settings with IndicatorSettingsDialog. A source the study rejects is reported above the results. Migration: the parameter panel is removed with IndicatorParams, IndicatorDialog::{selected, params, params_mut, input_summary} and IndicatorDialogConfig::{sel_color, sel_text_color}; caption an added study from its Indicator::inputs, and call IndicatorDialog::close on IndicatorDialogAction::AddIndicator to keep adding one study per visit. (#971)

  • Symbol details inset the title and price by 10 points inside the host panel and enlarge the main price to 26 points. The supplied SymbolDetails::category appears below the name, key statistics sit on a tinted card, and prices use the watchlist’s thousands grouping. (#990)

  • Watchlist rows are 30 points high with an 18 point symbol mark and aligned names. WatchlistPanel::set_mark supplies a mark; rows without one show an initial on a neutral disc. Prices and changes use thousands grouping, so 43237.45 reads 43,237.45, and changes omit the sign when they round to zero. (#989)

  • Chart layout uses the shared dark toolbar tooltip with consistent padding and no shortcut chip when no shortcut is bound. (#1011)

  • Sell and Buy quote buttons use outlines and matching text on the chart background, with a minimum width of 59 points. Bid and Ask axis tags default to hidden while saved choices remain intact; volume shows a compact last-value tag when study values are enabled. (#988)

  • The demo allocates 25% of the price pane to overlay volume, keeping the columns on the plot bottom and the height configurable through ChartConfig::volume_height_fraction. (#987)

  • Light crosshair tags use black fills and white text, with dashed crosshair ink at approximately #9C9C9C on the white plot. (#1007)

  • The light preset draws grid lines in #D1D1D1 instead of #DCDCDC, so the dotted grid stays visible on the white plot. Horizontal and vertical grid lines keep their separate visibility settings. (#1010)

  • Crate and public API documentation now describe host-supplied history and streaming data, current feature boundaries and a populated quick start. Stale capability claims, counts and implementation inventories are removed, and the README and package description use the same scope. (#933)

  • Charts follow active theme changes for inherited background, grid, text, candle, border and wick colours, retaining host edits and per-chart overrides. Chart titles, OHLC and pane legends, secondary series, trading labels and chart controls read the active text, spacing and radius scales. Clearing an override rejoins the current context palette. Migration: a default ChartBuilder now follows the active theme; call with_theme(Theme::dark()) to retain a fixed dark chart beside a differently themed UI. Settings dialogs read Theme directly; UI chrome, shared buttons, forms, lists and dialog padding use the applied text, spacing and radius scales. Applying a theme also updates egui’s built-in text sizes while retaining font families. Study defaults now use studies::palette, preserving their existing colours independently of UI status colours; unused study and extended colour tokens have been removed. Migration: replace the removed theme::components::{DialogStyle, SettingsDialogStyle, ContextMenuStyle} and their theme re-exports with Theme fields or egui visuals; replace DESIGN_TOKENS.typography and TypographyTokens with theme.text; pass &Ui instead of &Visuals to StyledPanelFrame constructors so separate frames also read the applied scales. Remove SemanticTokens::{buttons, alert, modal, command_palette} and their corresponding ButtonSemanticTokens, AlertSemanticTokens, ModalSemanticTokens and CommandPaletteSemanticTokens literals; UiSemanticTokens retains only the engine fallbacks text_muted_dark and border_dark. TextSizes literals add micro, marker and dialog_title or use ..Default::default(); saved themes default missing roles. See theme integration. (#356)

  • The next release is 0.3.0. Public implementation modules are private, extensible options and output records are non-exhaustive, and growing chart, interval, drawing, study and host-intent enums require fallback matches. The timezone formatter wrapper is crate-private; hosts keep using TimeFormatterBuilder::with_timezone. Main stateful types retain their private fields and accessors. Public configuration and data fields remain intentionally editable. CI compares the API with the latest published crate version and also gates release publication. Before 1.0, an incompatible API or exposed egui upgrade requires a new minor release; from 1.0 it requires a major release. The 0.3 line uses egui 0.37; compatible egui patch upgrades may ship in patch releases. (#253)

    Old path or constructionNew path or construction
    widget::builder::ChartBuilderwidget::ChartBuilder or the crate-root ChartBuilder
    widget::indicator_pane::ChartMappingchart::coords::ChartMapping
    widget::indicator_pane::{IndicatorCoordParams, IndicatorPane, IndicatorPaneConfig, PaneInteraction}widget::{IndicatorCoordParams, IndicatorPane, IndicatorPaneConfig, PaneInteraction}
    widget::keyboard::{ShortcutMap, ShortcutRequest}widget::{ShortcutMap, ShortcutRequest}
    widget::layout::{ChartLayout, ChartLayoutMode, ChartSyncOptions}widget::{ChartLayout, ChartLayoutMode, ChartSyncOptions}
    widget::export::{ChartImage, ImageExportOptions}widget::{ChartImage, ImageExportOptions}
    chart::selection::{SeriesId, ChartElementId}widget::{SeriesId, ChartElementId}; use Chart::{selected_element, selected_bar, clear_selection} instead of selection state helpers
    chart::selection::{SelectionState, SelectableId}Use Chart::{selected_element, selected_bar, clear_selection} for a chart, or a host-owned Option<Id> for standalone selection
    Complete literals of config::{ChartConfig, ChartOptions, CrosshairOptions, TooltipOptions}, widget::ImageExportOptionsStart from constructors or Default and assign fields; struct literals, including update syntax, are unavailable. Output geometry and image records are returned by the chart
    Complete literals of widget::{RenderedIndicatorPane, ChartLayoutRects, PaneInteraction, ChartImage}Obtain output geometry and image records from the chart and pane methods; PaneInteraction::default() remains available
    Exhaustive matches on growing chart, timeframe, drawing, keyboard, event, study and UI intent enumsAdd a fallback arm for future variants
    TimeframeSelectorConfig::{item_height, bg_color, hover_color, sel_color, text_color, muted_color, favorite_color}Removed unused options; rows use the menu layout and colours use the active theme. btn_width and dropdown_width remain supported
    TimeframeAction::AddCustomRemoved unused intent; custom intervals emit TimeframeAction::Select
  • Runtime module dependencies are acyclic. Shared bar interpolation, streaming study inputs, profile calculations and formatting live below rendering; study geometry and timestamp drawing methods live with their chart and widget consumers. Chart settings and study recipes no longer depend on UI modules, localization is shared at the crate root, and UI extension traits live beside the UI kit. CI rejects module cycles and inherent methods defined outside their type’s module. The crate remains one package. (#93)

    Old path or memberNew path or member
    model::{ChartState, ZoomState}studies::{ChartState, ZoomState}
    studies::{OrderFlowInput, OrderFlowKind, ProfileDisplay, StudyProfile, VolumeProfile, VolumeProfileConfig}data::{OrderFlowInput, OrderFlowKind, ProfileDisplay, StudyProfile, VolumeProfile, VolumeProfileConfig}
    drawings::{ProfileDisplay, VolumeProfileConfig}, drawings::domain::{ProfileDisplay, VolumeProfileConfig}, drawings::domain::options::{ProfileDisplay, VolumeProfileConfig}data::{ProfileDisplay, VolumeProfileConfig}
    studies::StudyFormatscales::StudyFormat
    services::PriceTargetsdata::PriceTargets
    ui::dialogs::templates::StudyTemplatestudies::StudyTemplate
    widget::localizationlocalization
    ext::{UiExt, ResponseExt, ButtonWidgetExt, TextEditWidgetExt, RoundingExt}ui_kit::ext::{UiExt, ResponseExt, ButtonWidgetExt, TextEditWidgetExt, RoundingExt}
    Theme::apply_to_config(config)config.with_theme(&theme)
    ChartSettingsState::{background_color, grid_color, sync_legacy_fields}Use chart_basic_styles.background_color and grid_lines.horizontal_color directly; the redundant mirrors and synchronization method are removed
    ui::top_toolbar::components::settings_menu::data::EventsSettings and its settings-menu re-exportmodel::EventVisibility
    ui::top_toolbar::{CandleColorConfig, StatusLineOptions, ChartSettingsState, PrecisionMode}widget::settings::{CandleColorConfig, StatusLineOptions, ChartSettingsState, PrecisionMode}
    ui::top_toolbar::components::{CandleColorConfig, StatusLineOptions, ChartSettingsState, PrecisionMode}widget::settings::{CandleColorConfig, StatusLineOptions, ChartSettingsState, PrecisionMode}
    ui::top_toolbar::components::settings_menu::{CandleColorConfig, StatusLineOptions, ChartBasicStylesSettings, GridLinesSettings, CrosshairSettings, WatermarkSettings, ScalesAppearanceSettings, ButtonsSettings, MarginsSettings, ScalesAndLinesSettings, TradingSettings, TradingNotifications, AlertsSettings, ChartSettingsState, BackgroundType, GridLinesMode, ButtonVisibility, WatermarkMode, PrecisionMode}widget::settings::{CandleColorConfig, StatusLineOptions, ChartBasicStylesSettings, GridLinesSettings, CrosshairSettings, WatermarkSettings, ScalesAppearanceSettings, ButtonsSettings, MarginsSettings, ScalesAndLinesSettings, TradingSettings, TradingNotifications, AlertsSettings, ChartSettingsState, BackgroundType, GridLinesMode, ButtonVisibility, WatermarkMode, PrecisionMode}
    ui::top_toolbar::components::settings_menu::data::{CandleColorConfig, StatusLineOptions, ChartBasicStylesSettings, GridLinesSettings, CrosshairSettings, WatermarkSettings, ScalesAppearanceSettings, ButtonsSettings, MarginsSettings, ScalesAndLinesSettings, TradingSettings, TradingNotifications, AlertsSettings, ChartSettingsState}widget::settings::{CandleColorConfig, StatusLineOptions, ChartBasicStylesSettings, GridLinesSettings, CrosshairSettings, WatermarkSettings, ScalesAppearanceSettings, ButtonsSettings, MarginsSettings, ScalesAndLinesSettings, TradingSettings, TradingNotifications, AlertsSettings, ChartSettingsState}
    ui::top_toolbar::components::settings_menu::types::{BackgroundType, GridLinesMode, ButtonVisibility, WatermarkMode, PrecisionMode}widget::settings::{BackgroundType, GridLinesMode, ButtonVisibility, WatermarkMode, PrecisionMode}
  • Breaking API cleanup: interval controls, settings, drawings, studies and trading share the domain types below. The small prelude exports common host types and traits, with widget exports following their feature. There are no compatibility aliases. Symbol search returns the host’s Instrument with its metadata intact. (#95)

    Old path or memberNew path or member
    ui::top_toolbar::Timeframe, ui::top_toolbar::components::Timeframe, ui::top_toolbar::components::timeframe_selector::Timeframemodel::Timeframe; use its variants or parse "7min", and pass it directly to the selector
    drawings::LineStyle, drawings::domain::LineStyle, drawings::domain::options::LineStylemodel::LineStyle
    config::CrosshairLineStyle, config::SessionBreakStylemodel::LineStyle; crosshair and session defaults remain dotted and dashed respectively
    studies::PlotPatternmodel::LineStyle
    ui::top_toolbar::components::settings_menu::LineStyle, ui::top_toolbar::components::settings_menu::data::LineStylemodel::LineStyle
    ui::widget_bar::LineStyle, ui::widget_bar::panels::LineStyle, ui::widget_bar::panels::object_tree::LineStyle, ui::widget_bar::panels::object_tree::types::LineStylemodel::LineStyle::name() replaces as_str()
    ui::dialogs::DrawingLineStyle, ui::dialogs::drawing_properties::DrawingLineStyle, ui::dialogs::drawing_properties::actions::DrawingLineStylemodel::LineStyle; name() replaces label(), all().iter().copied() yields values
    model::TradeSide, model::quote::TradeSidemodel::OrderSide; unknown aggressors remain None
    model::StrategySide::{Long, Short}model::OrderSide::{Buy, Sell}; migrate saved strategy sides from "Long"/"Short" to "Buy"/"Sell"
    model::Symbolmodel::Instrument; name becomes symbol, display_name becomes optional description, exchange becomes optional, and subscription state belongs to the host; use with_exchange and with_symbol_type instead of with_market
    ui::symbol_header::SymbolInfo, SymbolHeader::symbol_infomodel::Instrument, SymbolHeader::instrument; pass the interval label separately to SymbolHeader::new(instrument, timeframe)
    ui::top_toolbar::ScaleMode, ui::top_toolbar::components::ScaleMode, ui::top_toolbar::components::settings_menu::ScaleMode, ui::top_toolbar::components::settings_menu::types::ScaleModescales::PriceScaleMode; Auto becomes Normal
    ui::top_toolbar::components::settings_menu::types::{CandleColorConfig, StatusLineOptions}widget::settings::{CandleColorConfig, StatusLineOptions}; use ..Default::default() for additional status fields
    Indicator::line_cnt, CustomIndicator::with_line_cnt, LineBreakConfig::line_cntIndicator::line_count, CustomIndicator::with_line_count, LineBreakConfig::line_count
    ui::top_toolbar::components::settings_menu::TradingSettings::show_possTradingSettings::show_positions; migrate the saved JSON key too

    The selector accepts model intervals directly, including subsecond presets, and preserves full nonzero execution counts and custom seconds in its labels.

    Interval preferences now serialize model::Timeframe values instead of {value, unit} objects. Convert each old entry with its unit (Minute uses "min", Month uses "month"), parse it and serialize the resulting value. Presets and arbitrary intervals use the same nonzero model representation. Existing line-pattern JSON variant names are unchanged.

  • IANA time zones and daylight-saving rules are behind the timezones feature, enabled by default, so builds with default-features = false omit chrono-tz. UTC, system local time and signed fixed offsets remain available. All time zone APIs now use model::TimezoneId, including TimezoneMode::{Timezone, Exchange}, TimezoneMode::to_tz, BarClock::with_timezone, TimeAndSalesConfig::timezone and SymbolDetailsPanel::set_timezone. Migration: replace a chrono_tz constant with a parsed name such as "America/New_York".parse()?; add "timezones" to an explicit feature list to keep named exchange zones and presets. Without it, Trading Sessions uses fixed standard-time offsets (+09:00, +00:00 and -05:00), configurable through with_session. Use offsets such as "+05:45".parse()? or TimezoneId::fixed_offset(seconds); unknown or unavailable names are rejected instead of approximated. Persisted named-zone strings retain their format. Session presets and the settings time zone list also use fixed offsets without timezones. CI checks licences and duplicate versions in both the library and demo against deny.toml, with pinned exceptions for existing upstream version splits. (#256)

  • Ordinary solid study lines draw each uninterrupted run as one joined path instead of a separate shape for every pair of bars, reducing painting and tessellation work on charts with many studies while keeping gaps, colours and stroke widths. Directional colours and gradient fills retain their segment rendering. The README links performance notes with application-owned glibc allocator settings for large native charts. (#472)

  • Replay no longer holds a separate simulated balance or position. Migration: use services::PaperAccount through Broker instead of TradingSimulationState, ReplayState::trading_sim, the simulation actions on ReplayAction, or the trading fields on ReplayBehavior. (#221)

  • WatchlistPanel::set_quote and SymbolDetailsPanel::set_quote take a model::Quote, which carries the update time, extended-hours trade and session volume, and SymbolHeader::quote is an Option<Quote> whose bid and ask show when both are known. ExtendedHoursQuote and ExtendedSession moved from ui::widget_bar to model. The symbol details panel takes its price decimals from the instrument, or from the size of the price. Migration: build Quote::new(last, prev_close, time) in place of a WatchlistQuote and pass its decimals to WatchlistPanel::set_price_decimals; replace SymbolDetailsPanel::set_extended_hours with Quote::with_extended, and set_volume(volume, average) with Quote::with_volume and set_average_volume; set SymbolHeader::quote to Some(Quote::new(..).with_bid_ask(bid, ask)) in place of a QuoteData. (#222)

  • The chart’s order book keys levels by the nearest integer tick of the instrument’s tick size, so a feed that computes prices with rounding errors updates and removes the level it means instead of adding a neighbour. A crossed book is kept as the feed sends it, and Sink::push_quote now keeps a crossed quote, the top of such a book, instead of rejecting it. (#229)

  • Sink::push_depth_delta takes the delta by reference, so a feed can clear and refill one OrderBook for every update instead of allocating its levels per message, and the chart’s book keeps each side in a sorted array that reuses its capacity, so applying a delta allocates nothing once the sides reached their depth. Migration: pass &changes. (#228)

  • The web demo builds with the wasm-release profile, whole-program optimisation at opt-level = "s", which cuts its download by 15%; native builds keep release. The library defines the same profile for its own web builds, and scripts/web-size.sh builds the demo and the bare chart for the web and prints their raw, gzip and brotli sizes. examples/bare_chart.rs now also runs in the browser, where it applies the dark theme, so its web build carries Roboto alone instead of egui’s default fonts. The demo renders with eframe’s glow backend instead of wgpu, which takes another 17% off its download, and exports images through an offscreen framebuffer. The crate documentation lists these steps for an application’s web build, with chrono-tz’s filter-by-regex to keep only the time zones it needs. (#251)

  • Zoomed out until several bars share a physical pixel, a time-based chart draws them merged, about one bar per pixel column, instead of every bar. Candles, bars, columns, HLC area and high-low merge each group into its first open, highest high, lowest low and last close with its highest volume. Line, step, area and baseline charts keep the first, lowest, highest and last value of each group at their own bars, which draws the same line through the column. Groups with whitespace or per-bar colours retain their source bars for drawing, so gaps and individual styles stay visible. Volume, the time axis, sessions and hit testing read the merged groups, which are aligned to multiples of a power of two so panning keeps them, and are rebuilt only when the bars, the zoom step or the price source change. One chart of 1,000,000 bars all in view now paints 3,043 shapes in a 12 ms frame instead of 3,000,104 shapes in 1,864 ms, measured by the new scenario of benches/frame_time.rs. Heikin-Ashi, price-based and TPO charts, and study plots other than the volume on the main pane, still draw every bar. (#834)

  • Bars charts draw their bars and ticks with ChartConfig::wick_width, one point by default, instead of a fixed 1.5 point stroke, so they stay as crisp as candle wicks. Turn off BarsStyle::thin_bars for bars that widen with the zoom. (#832)

  • Panes keep their proportions when the chart is resized: dragging a separator and a study’s preferred pane height now set stretch factors instead of fixed pixel heights. A double click on a separator still restores the default shares. (#827)

  • PriceScaleMargins are shares of the pane height rather than of the data range, as the chart settings dialog already presented them: the default 10% above and below keeps the data in the middle 80% of the pane, and margins that leave no room for the data are ignored. PriceMarkGeneratorConfig defaults to a 20 pixel min_spacing and 100 max_marks, so target_density alone sets the spacing, which stays 40 pixels by default. (#833)

  • DetrendedPriceOscillator defaults to the conventional length 21 in its non-centred form, the close minus the 21-bar SMA of 11 bars earlier, aligned with the current bar. The new centered input, or with_centered(true), selects the centred form, the close 11 bars back minus the SMA, which is now stored at the bar that completes the average and drawn back through plot_offset, so it no longer reads later bars and fills the bars a previous rule left blank. Bars with a non-finite close are skipped and the pane draws a zero level. Migration: for the previous series use DetrendedPriceOscillator::new(20).with_centered(true) and read a centred value with plot_value, or at its source bar plus period / 2 + 1. (#176)

  • PivotPoints is the Pivot Points Standard study: levels for each day, week, month, quarter or year of exchange trading days come from the previous period’s open, high, low and close, counted in the instrument’s time zone and session as VWAP counts them, instead of a rolling window of bars. PivotTimeframe::Auto, the default, picks the period from the chart interval: daily up to 15 minutes, weekly below a day, monthly below a week and yearly above. The Traditional, Fibonacci, Woodie (with the current period’s open), Classic, DM and Camarilla types output P, R1, S1 through R5, S5, NaN where a type has no such level, for the last 15 periods by default (with_pivots_back). Lines are constant within a period and not drawn across the change to the next. AnchorPeriod names the calendar periods. Migration: PivotPoints::new(period) becomes PivotPoints::new() with with_method, with_timeframe and with_pivots_back; PivotMethod::Standard is Traditional and DeMark is DM, which now has P, R1 and S1 only; the catalogue name "Pivot Points" is "Pivot Points Standard"; values are eleven lines in the order above instead of [Pivot, S1, S2, S3, R1, R2, R3], and set_colors sets them line by line. Saved study templates of the previous study no longer load. (#176)

  • The widget bar’s bottom section keeps host entries at the foot of the bar above its line, with Help below the line, so a lower group of host panels stands apart from Help. Without host entries the bottom section is unchanged. The demo opens with its watchlist and the chart symbol’s details in a 300 point panel, lists the watchlist before Alerts and the Object Tree, and moves Data Window, Time and sales and Session notes to the lower group; compact windows still start with the chart alone.

  • The built-in Volume study starts with its moving average off and draws its columns in the theme’s rising and falling volume colours at reduced opacity; the chart’s volume switch applies the active theme’s volume_up and volume_down. Its legend row reads Vol and the bar’s volume in the study’s declared volume format (154, 64.55M), coloured like that bar’s column. The study no longer fixes three decimals. Migration: turn the average on with Volume::with_average(Some(VolumeAverage::Simple)) or the Moving average input, and set a precision override in the study settings to keep three decimals. (#817)

  • KineticScrollOptions::dumping_coeff is renamed to damping_coeff, the share of kinetic scroll velocity kept per frame; its default and effect are unchanged. Migration: replace dumping_coeff with damping_coeff in field access and struct literals. (#369)

  • Chart menu orders choose sides relative to the last price, use the quantity and capabilities from ChartMenus::set_order_entries, and open the ticket for confirmation. At the market price they may fill immediately. Migration: replace ContextMenuAction::SellLimit and BuyStop with Order(OrderRequest); ChartContextMenu literals add market_price, tick_size, order_quantity and order_types, or use new(). (#218)

  • Chart navigation buttons default to NavigationButtons::Never, leaving the plot clear on hover. Set OnHover or Always to show the existing controls; keyboard navigation stays available. The settings dialog starts with the same hidden choice, and the row hides if it cannot fit in the pane.

  • The plot uses the chart interior with a floating legend and the configured axis widths instead of fixed 40 point insets. ChartConfig::padding defaults to 0. ChartConfig::volume_baseline_inset makes the volume baseline configurable, retaining the 12 point default; set it to 0 and volume_height_fraction to 0.25 for a flush quarter-height overlay. Axis ticks that would cross the plot edge are omitted. Migration: struct literals of ChartConfig set volume_baseline_inset or use ..Default::default(). The unused styles::sizing::chart::{TOP_PADDING_WITH_OHLC, TOP_PADDING_NO_OHLC, BOTTOM_PADDING_NO_TIME, MIN_CHART_WIDTH, MIN_CHART_HEIGHT} constants are removed; use Chart::calculate_layout_rects for configured bounds.

  • Light chart grids use 1 point dots with 3 point gaps in #dcdcdc, for both price and time lines. Explicit grid colours are kept; dark chart grids use the same dotted strokes.

  • The light preset uses neutral text, separators, control states and panel gaps, white plot and axis surfaces, and #089981 up candles and #f23645 down candles. Semantic success and error colours stay separate from the candle palette.

  • theme::apply_to_egui installs the bundled Roboto Latin subset with tabular digits, at weight 400 with semibold symbols and time-axis years. Toolbar text is 14 px, legend values 13 px with 16 px titles, axes and price tags 12 px, and the bottom bar 14 px, with its right controls reserved at their actual width. TimeframeToolbarSizingTokens and SizingTokens::timeframe_toolbar are removed because the reservation follows the controls. Migration: remove those token fields from struct literals; to replace the bundled face, call egui::Context::set_fonts after applying the theme.

  • Volume bars take #26a69a up and #ef5350 down from the theme at 60% opacity in dark. The library defaults stand 12 points above the price pane bottom, reach 12% of the height above that baseline and span 80% of the bar pitch, with candle bodies defaulting to 60%. Reported layout bounds, hit testing and selection handles follow the overlaid bars.

  • Bollinger Bands default to #2962ff upper and lower bands and a #ffa726 basis, and overlay study lines default to 1 point instead of 2. Study colour overrides and oscillator pane widths stay the same.

  • The dark preset uses #000000 for panels, plot and axes, #2a2a2a separators, #dbdbdb text and toolbar icons, #b8b8b8 secondary text and time labels, #707070 muted text, #575757 disabled text, white price labels, #222222 grid lines, #089981 up candles, #f23645 down candles and #3179f5 active toggles. Light and high contrast preset values stay the same.

  • On Renko, Kagi, Line Break, Point and Figure and range bar charts, the indices the chart reports and accepts count elements instead of bars: the TimeScale and visible_range of ChartState, ChartState::visible_data (one bar per element), Chart::set_start_idx, get_start_idx, get_visible_bars, get_chart_mapping, selected_bar, get_hover_bar_idx, set_synced_crosshair_bar_idx and RightClickTarget::Element::bar_idx. Chart::set_chart_type, and set_chart_type_params on these types, clear the zoom history when the value changes. Migration: read the bars from Chart::bars, and find the bars of an element by its time.

  • Studies, drawings and markers are not drawn on Renko, Kagi, Line Break, Point and Figure and range bar charts, whose bricks, lines and columns do not map onto the bars they are anchored to. They cannot be selected, edited or hit there, and studies do not count in the price fit. They are kept, studies stay up to date, and they show again on the other chart types; a note in the price pane says what is hidden. These chart types draw no volume and no longer reserve a volume area. Chart::set_chart_type clears the selection when the type changes.

  • The indicator dialog lists every study of its IndicatorFactory instead of 24 hardcoded entries, each row showing the full name and the explanation from the study’s Indicator::desc (the registered name when the description has no “Full name - ” prefix), sorted by that name and searchable by its registered name and category, and creates the one added through the factory, so a study the host registers is offered too. IndicatorDialog::with_factory sets the factory and IndicatorDialogAction::AddIndicator carries the created study. Migration: replace with_indicators with with_factory, and handle AddIndicator(study) by adding study to the chart instead of calling create_indicator on AddConfiguredIndicator; IndicatorType, ConfiguredIndicator, IndicatorInfo::builtin_indicators and IndicatorInfo::indicator_type are removed, and IndicatorInfo::id is the factory name, so favourites and ToggleFavorite ids saved under the old ids (“sma”, “bb”, “stoch”) must be mapped to factory names (“SMA”, “BB”, “Stochastic”).

  • Volume bubbles are drawn by the chart from the trades its feed sends: Chart::set_volume_bubbles turns them on with a chart::overlays::VolumeBubblesConfig. Trades are summed per bar and price level (price_step, else the instrument’s tick size) as they arrive, and a frame reads only the bubbles of the visible bars, the levels of a bar that fall on one pixel row drawing as one bubble, so its cost follows the bubbles in view instead of growing with the square of the trades held: 16,000 trades that did not merge took 1.6 s per frame before; now 100,000 held trades over 1,667 one-minute bars, 40 levels a bar, draw 200 bars in 45 ms including tessellation, and 100,000 trades at 100,000 prices all in view in 15 ms. The bubbles hold no trade the chart’s bounded trade store has dropped, and Renko, Kagi, line break, point and figure and range charts draw none, since their x axis is not time. Sizes scale over the visible bubbles, a volume more than clamp_std_devs standard deviations (3 by default) above their mean draws at the maximum diameter so one large print does not shrink the rest, and color_by colours a bubble by its dominant aggressor side (BubbleColor::Side) or blends the sell and buy colours by its delta (BubbleColor::Delta). Migration: VolumeBubbles, TradeBubble, AggregatedBubble, VolumeBubblesConfig::aggregate_nearby and VolumeBubblesConfig::aggregate_threshold are removed: push trades into the feed’s Sink with push_tick and pass the configuration to Chart::set_volume_bubbles; struct literals of VolumeBubblesConfig set color_by, clamp_std_devs and price_step or use ..Default::default(). (#234)

  • The last-price line is drawn as a price line: the same width, with the standard dashed pattern (8 points on, 4 off) instead of its shorter dashes.

  • The export dialog uses the kit dialog chrome: a left-aligned title with a close button, one form grid with sentence-case labels, an instruction as the path hint, and a footer with Export as the primary action. Enter exports, and Escape closes it unless a field has the focus, which it leaves instead. An empty path keeps the dialog open, shows the error under the field and focuses it. The file path field is named by its label.

  • config::KeyboardAction::all_by_category returns only the actions whose keys are handled, in five categories, and KeyboardAction::label uses sentence case (“Zoom in more”, “Jump to latest”).

  • The go to date picker is a modal titled “Go to date” in the dialog chrome, over a dimmed backdrop, and Escape closes it. It always shows six weeks, with the days of the previous and next month muted and selectable, so it keeps its height in every month. Chevron buttons at the edges of the grid change the month, the footer has a ghost Today button and Go as the primary action, a range shows both of its ends filled and the days between in a light accent, and today has a ring. When the picker opens, the date field has the focus with its text selected, and Enter applies Go. Each day reports its date and selected state to accessibility tools and shows a focus ring. Today is the current UTC date, the time zone of the chart’s time axis by default. (#299)

  • The indicator dialog is a kit Modal: the shared title row, frame and scrim, Escape and a click outside close it, and it keeps its configured height, clamped to the window and following it when the window shrinks, with only the result list scrolling. The search field is the kit filter field with a search icon and a clear button, focused on open; Escape clears a search before it closes the dialog. Tabs use TabBar and categories SidebarTab with their own icons. Rows show a star icon with a tooltip, the name at 13 px over an 11 px description in the secondary text colour, cut off before outlined badges that sit inside the row padding clear of the scroll bar, and the theme’s selection colours when selected. ArrowDown in the search field moves to the first row, the arrows move between rows, Enter selects a row and Enter on the selected row adds it. Each empty list has its own empty state. The configuration panel lays out its parameters in a FormGrid and ends in a DialogFooter whose Back button returns to the list instead of closing the dialog.

  • Chart::set_renko_brick_size, renko_brick_size, set_kagi_reversal_amount and kagi_reversal_amount are replaced by set_chart_type_params and chart_type_params, which hold the sizes of all price-based chart types. ChartTypeParams::baseline_price is replaced by baseline: BaselineLevel, and the defaults are now 1.0 for every size (the unused struct said 4.0 and 10.0). Migration: let mut p = chart.chart_type_params().clone(); p.renko_brick_size = 2.0; chart.set_chart_type_params(p);.

  • ChartType has a new variant, Columns. Migration: an exhaustive match on ChartType needs a ChartType::Columns arm.

  • ui_kit::EmptyState::show returns bool, whether the action was clicked, instead of (). Migration: an EmptyState::show call in a place that expects (), such as the last expression of an if without else, takes a semicolon.

  • egui-charts depends on egui, egui_extras and ecolor 0.37 instead of 0.33 and needs Rust 1.95. Migration: move the application to egui and eframe 0.37 and Rust 1.95. An eframe application implements App::ui, which receives the root Ui, instead of App::update, and shows its panels inside that Ui with show(ui, ..) on egui::Panel::top, bottom, left or right (which replace TopBottomPanel and SidePanel) and on CentralPanel. egui creates the root Ui before the application runs, so a call to apply_to_egui in App::ui is followed by ui.set_style(ui.ctx().global_style()). The id and id salt parameters of UiExt::combo_select, combo_select_width, combo_str_select and combo_str_select_width, ColorPicker::new, color_picker_btn, ModalHandler::new, Modal::new, SimpleModal::new, show_modal, PromptDialog::new, prompt, prompt_with_message, ConfirmDialog::new, confirm, confirm_danger, AutocompleteEdit::id_salt, Section::new, ResponsiveToolbar::horizontal and vertical, and RangeSwitcher::with_id require Hash + Debug, as egui’s ids do, so an id type of the application’s own needs Debug. Code that builds tokens::SizingTokens with a struct literal sets the new control_height. egui 0.37’s default_fonts contain no emoji: enable egui’s monochrome_emoji_fonts feature or install a font that has them. Panel sizes and other widget state that egui persisted (window sizes, collapsed headers, scroll offsets) reset once, because egui derives panel and child ids differently. An eframe build with default features off enables eframe’s clipboard feature for copy and paste.

  • apply_to_egui sets the button padding (4 x 1), control height (18) and corner radius (2) of egui’s built-in widgets, so they keep the size they had with egui 0.33 instead of egui 0.37’s 8 x 2, 20 and 4 to 6. An application that sets these itself does so after apply_to_egui.

  • egui fills the title bar of the window on top with widgets.open.weak_bg_fill; since 0.35 it does so also for windows with their own frame, such as the Go to and compare symbol dialogs. apply_to_egui sets it to the theme’s btn_bg_hover instead of egui’s grey, which also fills an open combo box or submenu button.

  • SymbolSearchDialog and ExportDialog open centred horizontally in the window, a fifth of the way down, and can still be moved. They grow downwards as their content changes, so the search field stays in place while results appear. Since egui 0.34 a window without a position opens at the top-left corner of the window, over the application’s toolbars, instead of in the space its panels leave.

  • The floating selection toolbar’s settings, duplicate, lock, visibility and delete buttons show the crate’s SVG icons instead of emoji, which egui 0.37’s default fonts no longer contain; no bundled font had the duplicate glyph.

  • The chart widget is behind a new feature, widget, which icons and ui enable. default-features = false now builds the headless engine (model, scales, data, services, tokens and the Indicator trait layer of studies), which depends on ecolor instead of egui and on no windowing or rendering crate. Migration: a build that sets default-features = false to drop the icons adds features = ["widget"] to keep the chart.

  • Timeframe::Custom holds a NonZeroU64, so no timeframe has a zero duration: deserializing {"Custom":0} fails, as parsing "0s" already did, and the serialized form is unchanged. Migration: build a custom timeframe with Timeframe::Custom(NonZeroU64::new(seconds)?) or by parsing a label such as "45s", and read its length with seconds.get() or duration_ms().

  • egui-charts no longer enables egui’s default features. Applications built on eframe keep the default fonts (eframe enables them). Migration: an application in which no dependency enables egui’s default_fonts feature (for example eframe with default features off and no direct egui dependency) must enable it or install its own fonts.

  • The chart installs only egui_extras’ SVG image loader, and only with the icons feature, instead of every image loader (file, HTTP, PNG, JPEG, GIF, WebP). Migration: an application that loads other images must call egui_extras::install_image_loaders with the egui_extras loader features it needs enabled.

  • rand, getrandom, wasm-bindgen and web-sys are no longer dependencies, egui_extras is needed only by the icons feature and thiserror only by ui, which removes the image crate, the HTTP crates and the random number crates from a default build. Migration: a wasm32 application that relied on this crate enabling getrandom’s wasm_js backend must enable it itself.

  • Theme holds the colours and scales directly: theme.semantic.ui is theme.ui and theme.semantic.chart is theme.chart, and theme::UiSemanticTokens and theme::ChartSemanticTokens are theme::UiColors and theme::ChartColors. UiColors gains focus, the keyboard focus colour, and danger_bg, danger_bg_hover, danger_bg_active and danger_text, which kit Danger buttons and Danger list items now fill from instead of the danger button tokens. Fields that duplicated another are removed: toolbar_bg, btn_bg and btn_bg_disabled are panel_bg; toolbar_separator and border_subtle are border; icon is text_secondary and icon_hover is text; icon_active, border_focus and text_link are accent; candle_up_border and candle_up_wick are candle_up, and likewise for down; volume_up and volume_down are methods using volume_alpha. In the dark theme the separators and resting icons that read the removed fields are drawn in the border and secondary text colours, and hovered icons in the text colour; in the light theme the separators are the border colour and the resting icons the secondary text colour. Migration: replace .semantic.ui. with .ui. and .semantic.chart. with .chart., theme::UiSemanticTokens with theme::UiColors and theme::ChartSemanticTokens with theme::ChartColors, and a removed field with the one it duplicated; theme.is_dark_ui() is theme.dark; the colour accessors such as theme.background() are the fields, such as theme.chart.bg.

  • Theme::default() is the dark theme. It was Classic, light UI chrome with the dark chart.

  • ContextMenuStyle, DialogStyle and SettingsDialogStyle are built with from_theme(&Theme) instead of from_semantic.

  • The bottom toolbar, timeframe bar, date picker, range switcher and right panel tabs follow any change of the applied theme, including an edited preset, instead of only a change of preset.

  • scales::PriceScale is the chart’s price axis and keeps its visible range in scale units: PriceScale::new(options), autoscale, zoom, set_range, reset, range, is_manual, options and options_mut, and map, which returns the frame’s scales::PriceMap for a scales::PriceTransform (mode and base price). PriceMap::price_to_y and y_to_price do not clamp to the pane. Migration: PriceScale::new(options) replaces new(height) and with_options; map(transform, top, bottom).price_to_y(price) and .y_to_price(y) replace price_to_coord and coord_to_price; autoscale, set_range, reset and range replace auto_scale, set_manual_range, reset_auto_scale, price_range and visible_price_range; options_mut replaces set_options; the pane extent and PriceTransform::base passed to map replace set_height and set_first_val.

  • PriceScaleOptions no longer has auto_scale; use PriceScale::is_manual and PriceScale::reset. PriceScaleMargins fields are f64 and default to 0.1 at the top and the bottom, the margins the chart has always drawn.

  • ChartMapping holds the frame’s price: PriceMap instead of price_min and price_max, and ChartMapping::new takes it as its last argument. price keeps its own vertical extent, so ChartMapping::with_rect moves only the x mapping and the bounds checks. Migration: pass PriceMap::new(PriceTransform::default(), PriceRange::new(min, max), rect.min.y, rect.max.y, false) for a linear axis.

  • ChartState owns the main price scale: price_scale, price_scale_mut and fit_price_scale replace price_range, set_price_range, set_price_auto_scale and is_price_auto_scale. Migration: state.price_scale_mut().set_range(min, max), .reset() and state.price_scale().is_manual(); the fitted range is state.price_scale().range() after state.fit_price_scale(). ZoomState::price_range holds a manual range in scale units.

  • PriceMarkGenerator::generate_marks takes the frame’s &PriceMap instead of a price range, height, mode and pane bounds. In percentage and indexed modes PriceMark::price holds the percentage or index value, not a price.

  • Chart::handle_drawings takes the frame’s &PriceMap instead of the lowest and highest price.

  • model::Tick is #[non_exhaustive] and has an id field. Migration: build it with Tick::new(ts, price, size, side), adding .with_id(id) when the feed has trade ids.

  • model::SymbolType is #[non_exhaustive]. Migration: add a wildcard arm to matches on it.

  • tokens::UiSemanticTokens replaces warning and success with per-theme status colours {success,warning,error,info}_{light,dark}, and gains text_disabled_light, text_disabled_dark, border_control_light, border_control_dark, selection_bg_light and selection_text_light; theme::UiColors has border_control, the outline apply_to_egui gives inactive and hovered widgets. Migration: read DESIGN_TOKENS.semantic.ui.warning_dark and success_dark for the old values, or the theme’s ui.warning and success to follow the active theme; struct literals must set the new fields.

  • The theme’s accent_active (pressed accent) is a darker accent, (31, 78, 205), instead of the grey buttons.primary_bg_active, and accent_hover is (35, 88, 230) instead of the lighter blue_600. tokens::BrandSemanticTokens gains accent_active; struct literals must set it. The buttons.danger_bg, danger_bg_hover and danger_bg_active tokens are darker reds.

  • Replaced the bundled icon set with original artwork drawn on a 24 px grid. Toolbar, chart-type and widget-bar icons now render at 24 px, and close buttons, the cross cursor, alert and toast states, move to pane, add to watchlist, the replay next-bar button, the price range tool, the arrow tool and the note, callout, comment, table, image and other annotation tools show their own icons.

  • Drawing::render, Drawing::render_original, and DrawingManager::render_all take a drawings::rendering::ChartView holding the chart’s bars and coordinate mapping. Migration: build ChartView { bars, bar_to_x, price_to_y } from the series and the closures passed to update_all_screen_coords, and pass it as the last argument.

  • drawings::rendering::ChartView has a revision field, under which results computed from the bars are cached. Migration: set it to ChartState::revision() of the state the bars come from, or to a value that changes whenever a bar before the last one changes.

  • The regression trend draws one pair of bands at its configured distance (two standard deviations by default) instead of bands at one and two.

  • Long and short position tools size their quantity from Drawing::position_size; without a setting the quantity is one unit, so P&L reads per unit, instead of a fixed 100. The target and stop labels no longer repeat the quantity, and a quantity that is not whole is shown with up to four decimals, or four significant digits below 0.1. Migration: Drawing::quantity is replaced by Drawing::position_size; quantity: Some(q) becomes position_size: Some(PositionSize::Quantity(f64::from(q))).

  • Chart::handle_drawings no longer takes the last close price.

  • TooltipOptions::default() leaves background_color, text_color and tracking_bar_background as Color32::PLACEHOLDER, which resolves from the active theme; set them explicitly to keep fixed colours.

  • SymbolHeaderConfig::default() text, label and separator colours are Color32::PLACEHOLDER and follow the egui style; SymbolHeaderConfig::from_theme now uses the theme it is given.

  • apply_to_egui styles the selection per theme. Dark themes fill it with the accent and set visuals.selection.stroke to white; light themes fill it with a pale accent, (219, 229, 255), and set the stroke to a darker accent, (31, 78, 205), which also outlines a focused text input. Migration: code that read selection.bg_fill or selection.stroke.color as the accent colour should read the theme’s ui.accent; text painted on selection.bg_fill should use selection.stroke.color, not white.

  • apply_to_egui sets item_spacing to 8 x 4, window_margin to 12 and menu_margin to 8 x 4 instead of zero. Layouts that relied on zero spacing should set ui.spacing_mut().item_spacing = Vec2::ZERO locally.

  • apply_to_egui sets visuals.window_fill to UiColors::panel_bg_floating, which in dark themes is now (42, 46, 57), one step above panel_bg, instead of equal to it. Popups and windows also get a hairline border and a smaller shadow.

  • The chart’s context menus follow the theme applied with theme::apply_to_egui (Theme::dark() until one is applied); ChartBuilder::with_theme sets the chart’s colours only.

  • ChartBuilder no longer defaults the symbol to BTCUSDT: a chart built without with_symbol has an empty symbol, shows no symbol and asks its feed for nothing until Chart::set_symbol is called. Migration: call with_symbol to keep the previous behaviour.

  • SymbolInfo::default() (in ui::symbol_header) has empty fields instead of AAPL, Apple Inc, NASDAQ and 1D. Migration: set the fields explicitly.

  • CompareSymbolsDialog::show takes the symbols to suggest (show(ctx, &symbols), the same &[model::Symbol] that SymbolSearchDialog::show takes) and lists only those, with an empty state when there are none, instead of a built-in list of tickers the data source may not offer. Added symbols have an empty CompareSymbol::exchange, since Symbol carries no exchange. Migration: pass the symbols your data source offers.

  • ButtonVariant::bg_color, fg_color and border_color resolve colours from the theme applied with apply_to_egui and the Ui’s visuals instead of fixed design tokens, and apply_to_style sets them on a Ui instead of a Style; fg_color returns a real colour for Ghost and Outlined instead of Color32::PLACEHOLDER. Migration: pass ui as the first argument (call apply_to_style inside ui.scope); border_color no longer takes hovered.

  • IconButton, SplitButton and Button icons are 16, 20 or 24 px for small, medium and larger buttons (20 px at the default 28 px) instead of 60% of the button size; icon_scale still overrides this.

  • SplitButton occupies the same square cell as an IconButton of its size, with the chevron in the cell’s corner, instead of a cell 10 px wider.

  • dialog_close_button is an IconButton showing icons::CLOSE with a “Close” tooltip.

  • DialogFrame, dialog_header, DialogFooter, Modal, ConfirmDialog, PromptDialog and ModalHandler share one dialog chrome: the theme’s window fill, border, radius and shadow with 16 px padding, a title row with a left-aligned 14 px title and an icon close button centred on it, and a footer whose buttons are 28 px high, 8 px apart, with a filled primary and an outlined secondary. The size passed to DialogFrame::new is the preferred content size inside the padding: the dialog is at least that large, grows with its content and is limited to the application window. A DialogFooter shown directly in a DialogFrame::new frame sits at the bottom of the frame, with any free space above its rule. Modals are centred and sized to their content, and Modal::width and Modal::min_height set the outer size including the padding (before, the content size); ConfirmDialog is cancelled by Escape, the close button or a backdrop click, and ModalHandler closes on Escape.

  • UiExt::clickable_label and the alert count badge of the widget bar take their colours from the active theme: the clickable label is drawn in ui.accent, and the badge text is ui.danger_text. They used fixed token colours, so a custom accent or the high-contrast preset did not reach them.

  • tokens::DESIGN_TOKENS is a plain static of type DesignTokens defined in Rust instead of a once_cell::sync::Lazy that parsed an embedded RON file on first access, which took 10 to 40 ms and 1,224 allocations in a release build. The ron and once_cell dependencies are removed. Migration: field access is unchanged; code that dereferenced the static (*DESIGN_TOKENS, Lazy::force(&DESIGN_TOKENS)) uses DESIGN_TOKENS or &DESIGN_TOKENS.

  • The drawing storage format is version 2: a StoredDrawing holds its anchors and the Drawing (StoredDrawing::drawing) with the tool type and all settings. DrawingStorage::from_json migrates version 1 files, with defaults for the settings they lacked, and fails on any other version instead of relabelling it. It loads each drawing on its own and returns (DrawingStorage, Vec<drawings::persistence::SkippedDrawing>): a drawing it cannot read (a tool type from a newer release or an unknown version 1 tool name, a cursor tool, a missing field, a null written for a non-finite number, a number outside the range of its field, a setting out of bounds) is left out and reported with its id and error, while the file as a whole fails only on invalid JSON, an unknown version or an invalid symbol, timeframe or metadata. Saving the returned storage writes only the drawings that loaded; keep the original file if the skipped ones must be recovered. Migration: build a stored drawing with StoredDrawing::new(id, drawing), read its settings from stored.drawing, and take the storage from the first element of the from_json result, reporting or logging the skipped drawings.

  • drawing_to_stored(drawing, bar_to_time) and stored_to_drawing(stored, time_to_bar, next_id) map anchors between bar index and timestamp instead of taking screen-space closures, and stored_to_drawing returns the Drawing instead of an Option; screen points follow on the next update_screen_coords. Migration: pass the chart’s bar index to timestamp mapping and its inverse. Both must take fractional bar indices and extrapolate by the bar interval before the first and after the last bar instead of clamping, or anchors outside the loaded bars are moved onto the edge bar and saved there.

  • DrawingStorage::to_json refuses a drawing holding NaN or an infinity in its stroke width, font size, an anchor price, its position size or a Fibonacci level value, and returns drawings::persistence::SaveError::NonFinite with the drawing’s id and the field, instead of writing null and losing the drawing on the next load. from_json skips such a drawing too, so every storage it returns can be saved. Migration: to_json returns Result<String, SaveError> instead of Result<String, serde_json::Error>; a serialization error is SaveError::Json.

  • DrawingStorage::from_json skips a drawing whose id an earlier loaded drawing already has and reports it as a duplicate, so the loaded ids are unique and the first one in the file wins. SkippedDrawing::index is the entry’s position in the file, which tells skipped entries with the same id or no id apart. Migration: struct literals of SkippedDrawing must set index.

  • DrawingStorage::from_json skips a drawing with fewer anchors than its tool draws with and reports it with the tool and the anchor count, since such a drawing loaded as completed, drew nothing and could not be selected or deleted on its own, and a drawing whose timeframe filter names no timeframe loads as visible on every timeframe. DrawingStorage::to_json refuses the same drawing with SaveError::MissingAnchors, so every storage it accepts loads back whole.

  • DrawingStorage::add_drawing replaces the drawing with the same id, keeping its position and created_at, instead of storing a second one that the next load skipped as a duplicate, so saving a drawing again after an edit stores the edited version once. DrawingStorage::to_json refuses duplicate ids that reach the storage another way (the public drawings field, a struct literal or an id changed through get_drawing_mut) with SaveError::DuplicateId, instead of saving a drawing the next load skips. Migration: give each drawing its own id to keep both.

  • The cross, dot and arrow cursors are named “Cross Cursor”, “Dot Cursor” and “Arrow Cursor” (DrawingToolType::as_str and Display), so “Arrow” names only the arrow drawing and “Cross” no longer names one tool while parsing to another. The floating toolbar’s all-tools menu shows the new names. Migration: code that compares a cursor’s as_str() or to_string() with “Cross”, “Dot” or “Arrow” uses the new names.

  • Parsing a DrawingToolType fails with drawings::ParseToolTypeError, whose input field holds the name as given and whose message reads unknown drawing tool "name", instead of a String. The names that parse, and the tools they parse to, are unchanged. Migration: code that used the error as a String reads error.input or calls error.to_string().

  • OrderId and OrderSide now live in model.

  • A last-bar update or an append of SMA reads the window from the bars instead of keeping a copy of it, so it no longer copies the whole close series when the period is longer than the series.

  • DonchianChannels, IchimokuCloud, Stochastic and WilliamsR find the highest high and lowest low of each window in time linear in the number of bars, independent of the period, instead of rescanning the window for every bar; their values are unchanged. IchimokuCloud takes about 24 ms instead of 52 ms on 100,000 bars.

  • The default feature is ui, so cargo add egui-charts gives the chart with its toolbars, panels, dialogs, icons and built-in studies instead of the chart and its icons. Migration: an application that only shows charts sets default-features = false, features = ["widget"], adding "icons" for the icon set and "studies" for the built-in studies.

  • The built-in right-click menus are shown by ui::context_menu::ChartMenus (feature ui), which takes the chart’s right-click; a host that handles right-clicks itself reads Chart::take_right_click and does not show ChartMenus.

  • The built-in studies, IndicatorFactory and the studies::factory module need the new studies feature, which ui enables. Indicator, IndicatorValue, IndicatorRegistry and CustomIndicator remain in every build, so custom studies work in a bare chart. Migration: a build with default-features = false that uses built-in studies adds "studies"; it needs no egui, so a headless build keeps computing the same studies.

  • ext (UiExt, ResponseExt, ButtonWidgetExt, TextEditWidgetExt, RoundingExt) needs the ui feature instead of widget. Migration: enable ui.

  • ui::context_menu::MenuItem is generic over its action, MenuItem<A = ContextMenuAction>, holds its shortcut as an egui::KeyboardShortcut instead of a string, and gains danger. Migration: replace with_shortcut("Cmd R") with with_shortcut(KeyboardShortcut::new(Modifiers::COMMAND, Key::R)), which egui formats for the platform; struct literals set danger.

  • The top toolbar is 32 px high, with 28 px buttons, 20 px icons and 13 px labels, except Save, which keeps its look. When the window is too narrow, Indicators, Alert and Replay show only their icons, then the least important controls move into a menu at the right end, so no control overlaps another. TOOLBAR_HEIGHT, BUTTON_SIZE and ICON_SIZE in ui::top_toolbar::config are 32, 28 and 20. The keyboard focus ring fills the 2 px around a control instead of sitting 2 to 4 px outside it, so a control that fills its strip keeps all four sides of the ring.

  • The symbol pill and the interval and chart type buttons are sized to their laid-out labels and drawn alike: an icon where they have one, the label and a chevron, with an outline at rest, the hover fill on hover and the pressed fill while pressed or open. The pill is visible at rest in the light theme, shows the symbol in the primary text colour and no longer overdraws its last letter, and the interval button no longer shows a missing-glyph box. The three report themselves to accessibility tools as buttons and show the keyboard focus ring. TimeframeSelectorConfig::btn_width and ChartTypeSelectorConfig::btn_width are minimum widths, 0 by default.

  • The symbol header shows the last close with its change instead of the bar’s open, high, low and close, which the chart legend shows. Its up and down colours default to the theme’s success and error text colours, which read at 4.5:1 or better where the candle colours do not (Color32::PLACEHOLDER in SymbolHeaderConfig::default, resolved while painting), and SymbolHeaderConfig::from_theme sets them.

  • Widget bar icons are 20 px, as in the top toolbar, and their tooltips open to the left of the button instead of over the button below. The bottom bar’s date button icon is 16 px.

  • BarData::from_csv requires the header row ts,open,high,low,close,volume (any case, spaces around names ignored) and returns an error naming it otherwise, instead of taking the first row as a header unchecked and reading the columns by position, which lost the first bar of a file without a header and swapped the columns of a file in another order. An empty file is refused too. Migration: give the file that header, with the columns in that order.

  • Every CI job has a timeout-minutes limit, so a hung job fails in minutes instead of after the 6 hour default.

  • CI runs default, all-feature and headless library tests on stable and Rust 1.95.0 on Linux, macOS and Windows. Headless Chrome also runs the widget’s pan, pointer zoom, drawing selection and degenerate-history tests with all features and with the widget alone. (#254)

  • ChartState::set_data returns the index of the first bar that differs from the previous bars, the shorter length when one series is a prefix of the other, or None when they are identical.

  • Chart::show draws the chart’s studies, overlays on the main pane and the others in panes below it, and its drawings, and the chart updates its studies once per frame from the first bar changed since the last one. Migration: move the studies in with add_indicator and the drawings with drawings_mut(), replace show_with_indicators, show_with_drawings and show_with_indicators_plot with show, and drop the calculate_all calls that followed bar updates.

  • The close button in a study pane’s legend removes the study. Migration: drop calls to Chart::take_indicator_remove, which is removed.

  • ChartElementId::OverlayIndicator(usize) and ChartElementId::PaneIndicator(usize) are replaced by ChartElementId::Indicator(SeriesId), the id add_indicator returned. Migration: find the study with Chart::indicators.

  • DrawingManager::shift_bar_indices, Drawing::shift_bar_indices, HistoryService::shift_bar_indices and DrawingCommand::shift_bar_indices take the first bar index to shift, from, before the shift. Migration: pass f32::NEG_INFINITY to shift every point, as before.

  • Chart holds its studies as Box<dyn Indicator>, which is Send but not Sync, so Chart is no longer Sync. Migration: share it behind a Mutex; Arc<Mutex<Chart>> still works.

  • Chart’s fields are private. Migration: chart.config becomes chart.config() or chart.config_mut(), chart.chart_options becomes chart.chart_options(), chart.marks = markers becomes chart.set_markers(SeriesId::MAIN, markers), chart.state.data().bars becomes chart.bars(SeriesId::MAIN), chart.state.price_scale_mut() becomes chart.price_scale_mut() and chart.last_rendered_price_rect becomes chart.get_rendered_price_rect(). Other reads of the state, such as revision, visible_range, visible_data, time_scale and has_zoom_history, go through chart.state(); time_scale_mut, fit_price_scale and the zoom history’s push_zoom_state, pop_zoom_state and clear_zoom_history have no public replacement, since the chart scrolls, fits and zooms itself.

  • The floating replay bar opens docked at the bottom of its dock rect instead of at the window’s top left corner over the top toolbar, which it did wherever the platform does not report the window position (the web, Wayland). It uses the kit’s 28 px icon buttons, a 28 px speed control named “Playback speed” and a secondary “Exit replay” button, shows the symbol and progress at 12 px in the theme’s text colours with the progress always shown, keeps its width as the progress and speed change, and casts the popup shadow.

  • ReplayControls, CompactReplayControls and ReplayToolbar use the kit’s icon buttons instead of text glyphs and egui image buttons. ReplayToolbar shows its progress percentage beside the bar instead of over the fill, and the single-step buttons of ReplayControls and ReplayToolbar show arrows instead of the skip icons.

  • ReplayColors::default takes the dark theme’s colours, and the replay widgets paint with the active theme’s colours while the configured colours are the defaults.

  • ReplayStatusIndicator takes its colours from the active theme, reads “Replay”, “Paused” and “Complete” at the theme’s small text size, and takes no space for ReplayStatus::Inactive.

  • ChartBuilder::with_initial_bars takes a usize. Migration: Some(n) becomes n; for None, build without a feed.

  • Chart::set_symbol and Chart::set_timeframe reload a chart built with a feed at its next show when the value changes: the series and its studies are cleared and the new one is loaded, once however many of the two changed. Without a feed they set the label only. Chart::set_symbol takes impl Into<String>. Migration: set_timeframe_label(tf.as_str()) becomes set_timeframe(tf).

  • ChartBuilder::build returns a Chart and never blocks. Migration: tc.chart.x() and tc.x() become chart.x(), drop tc.update() (show applies updates), tc.take_context_action() becomes menus.show(ctx, &mut chart) with a ChartMenus kept next to the chart (feature ui).

  • ChartBuilder moved to widget::builder. Migration: import egui_charts::ChartBuilder or egui_charts::widget::ChartBuilder instead of egui_charts::chart::builder::ChartBuilder.

  • ChartBuilder::price_chart hides the horizontal and vertical grid lines; it used to clear a flag the chart does not read.

  • While bars stream, each frame recomputes at most one study in full, the one that has waited longest, and a study then waits 0.25 s, or four times what that recompute took if longer, before its next one. An incremental study follows a new bar or a new close of the last bar on the same frame. Chart::indicators can therefore return values that lag the bars by that wait, and after the bars change from the first one on, as when set_data loads other bars or older bars are loaded in front, a study has no values until its turn, one study per frame. Migration: a host that reads study values right after set_data, for alerts or exports, reads them on a later frame once the study has values again, or calls calculate on a clone of the study (Indicator::clone_box) with Chart::bars.

  • While the view is scrolled back, new bars no longer move the visible bars.

  • Exportable::export_png takes no arguments, since the export has no size or background options. Migration: export_png(w, h, transparent) becomes export_png().

  • TopToolbarAction::IntervalSelected carries a model::Timeframe instead of the menu label, so every interval the menu offers, a custom one included, reaches the host: before, 12 of the 21 labels had no Timeframe::from_resolution mapping, and FromStr read bare minute labels as custom timeframes. Migration: match on the value instead of parsing the label; an interval with no preset of its length arrives as Timeframe::Custom(seconds).

  • HideMenu::show_submenu takes whether to show the positions and orders rows. Migration: pass true to keep them.

  • TopToolbar and WidgetBar have a private field and can no longer be built with a struct literal. Migration: start from TopToolbar::default() or WidgetBar::default() and set the public fields.

  • The drawing bar draws its menus in one flyout. SubmenuBuilder::new takes only the Ui, SubmenuBuilder::with_category_rect is gone and show draws the rows into that Ui; SubmenuItem gains is_checked and is_danger and implements Default; SubmenuBuilder::checked and danger set them on the item added last. ToolCategory::render_submenu(ui, sel_tool, favorites) and categories::trend_lines::render_tool_submenu(ui, sections, sel_tool, favorites) draw rows into the Ui they are given, take the favourites as &mut Vec<DrawingToolType> and no longer take an anchor rect or an id; ToolCategory::all_tools, sections and render_submenu have default implementations that read data::get_category_sections. Migration: show the rows inside your own popup, or use DrawingToolbar.

  • MagnetButton::show, HideMenu::show and RemoveMenu::show return the button’s Response, where they returned tuples of flags and a rect. MagnetButton::show_submenu(ui, magnet_on, magnet_type), HideMenu::show_submenu(ui, trading, state), RemoveMenu::show_submenu(ui) and TemplatesButton::show_submenu(ui, templates) draw into the Ui they are given. components::render_svg_at_rect_themed no longer moves the layout cursor.

  • model::Annotation and model::MarkerType, which nothing drew, with the unnameable AnnotationPos. Migration: use Marker. (#1310)

  • The loose ALMA smoothness check, drawing-tool inventory pins, a duplicate tracking default check and an enum-distinctness tautology. (#258)

  • model::QuoteSource and QuoteSourceError, a polled quote source nothing consumed, ui::widget_bar::WatchlistQuote and ui::symbol_header::QuoteData. Migration: implement services::Quotes and attach it with WatchlistPanel::set_service, and use model::Quote in place of the two quote types. (#222)

  • TradeSide::Unknown and model::RangeTickData. A trade of unknown side has Tick::side set to None, the one way to say it, and to_range_bars_from_ticks builds range bars from Tick, the crate’s one trade type. Migration: replace Some(TradeSide::Unknown) with None, and build Tick::new(ts, price, volume, None) in place of a RangeTickData. (#228)

  • Unread design token fields: UiSemanticTokens::{panel_bg_dark, panel_bg_secondary_dark, panel_bg_floating_dark, text_dark, text_secondary_dark, text_disabled_dark, text_disabled_light, border_subtle_dark, border_control_dark, border_control_light, btn_bg_dark, btn_bg_hover_dark, btn_bg_active_dark, selection_bg_light, selection_text_light, error_light, warning_dark, info_dark}, ChartSemanticTokens::{bg_selection, bg_selection_light, bg_light, bg_axis_light, grid_line_light, grid_line_major_light, crosshair_line_light}, IndicatorSemanticTokens::{bb_fill, rsi_overbought, rsi_oversold, macd_hist_pos, macd_hist_neg}, DrawingSemanticTokens::{default_line, handle, handle_hover, handle_active, line_hover, line_selected, label_bg, fib_0, fib_236, fib_382, fib_618}, TpoSemanticTokens::opening_range, ToolbarSizingTokens::top_height and ShadowTokens::offset_md. Migration: remove these fields from token struct literals; read applied colours from ThemeExt::active_theme and keep host-specific constants where no theme field applies. UiSemanticTokens::border_dark and DrawingSemanticTokens::fib_50 retain their rendering readers, and ChartSemanticTokens::watermark_alpha remains available as the documented watermark migration target. (#367)

  • Unread layout timestamps, cloud/default flags and the LayoutInfo wrapper, unused LayoutAction::OpenMenu and SetDefault, and unused LayoutMenuConfig colours and item height. Migration: supply LayoutMenu::layouts as Vec<String> and update that list directly instead of calling add_layout; LayoutMenuConfig retains only menu_width.

  • The “Correlation”, “CorrLogRet”, “Ratio”, “Spread” and advance/decline “A/D Line” studies and their Rust types, since one symbol’s bars cannot supply a second series or market breadth, and “Vol Index” (VolatilityIndex), whose annualised ATR percentage follows no published definition. Accumulation/Distribution keeps its “A/D Line” output. Migration: the two-series and breadth studies return when studies can read another symbol (#175); a host can compute them today as a custom study in Rust. An annualised ATR percentage can also be written as a custom study.

  • ui::chart_controls::ChartControlBar, ChartControlBarState, ChartControlBarConfig and ChartControlAction, which nothing drew or handled and whose icons did not match their actions. Migration: remove any use of them; the chart draws and handles its navigation buttons itself, and ChartConfig::navigation_buttons sets when they show.

  • studies::list_builtin_indicators, whose table listed seven names the factory could not create, and the factory names “CVD”, “C2C Vol”, “HL2”, “HLC3” and “Price Channel”, which computed the same studies as “A/D”, “HV”, “MP”, “TP” and “Donchian”, and “Ehlers Fisher”, a variant of the Fisher Transform recursion with length 10 and a clamp on the normalised price. IndicatorFactory is now the one catalogue: IndicatorFactory::category gives each built-in’s category, and a study added with register is in IndicatorFactory::CUSTOM. Migration: list studies with IndicatorFactory::list and describe each with Indicator::desc and IndicatorFactory::category; create the registered twin of a removed name, or build CVD, CloseToCloseVol, HL2, HLC3, PriceChannel or EhlersFisher directly.

  • chart::overlays::{OrderLine, OrderLineOverlay, OrderLineAction, OrderLineType}, which nothing in the crate drew, with the re-exports chart::overlays::{OrderId, OrderSide} and the sizing tokens ChartsExtSizingTokens::{order_line_label_width, order_line_label_height}. Migration: draw each order’s price as a model::PriceLine with its label as the title, for example PriceLine::new(order.price, color).with_title(label), and pass the lines to Chart::set_price_lines(SeriesId::MAIN, lines); the chart places them through its own price scale, so no price_to_y mapping is needed. Selecting, dragging and cancelling an order line (OrderLineAction) and its cancel button have no replacement: price lines do not respond to the pointer. Import OrderId and OrderSide from model. Code that read the two tokens uses the values they held, 120.0 and 20.0, and ChartsExtSizingTokens literals drop the two fields.

  • BoxZoomMode and BoxZoomState::mode: no chart could select the measure mode, and a box released in it showed nothing. Migration: remove any use of them; box zoom always zooms, and the Measure drawing tool measures the price change, percentage and bar count between two points.

  • DatePickerConfig, which no API ever passed to a DatePicker. Migration: remove any use of it; the go to date picker takes its colours from the active theme.

  • IndicatorDialogConfig::bg_color and IndicatorDialogConfig::sidebar_color, which had no effect: the dialog takes its surface from the kit modal and its sidebar from SidebarTab. Migration: drop both fields from struct literals; the dialog surface is Theme::ui.panel_bg_floating, which apply_to_egui applies as egui’s Visuals::window_fill.

  • ChartSettingsState::color_based_on_prev_close, which had no effect.

  • Timeframe::total_seconds, Timeframe::as_seconds and Timeframe::to_seconds, which returned 0 for Ms100, Ms250 and Ms500. The demo’s sample bars at those timeframes were one second apart and now follow the timeframe. Migration: use Timeframe::duration_ms(), or duration() for a chrono::Duration; time intervals always have a positive duration.

  • ThemePreset, ThemeManager, Theme::{classic, midnight, from_preset, name, is_dark_ui, is_dark_chart}, Theme::components with ComponentStyles and the unused BtnStyle, ToolbarStyle, PanelStyle, MenuStyle, InputStyle, ChartStyle, CandleStyle and VolumeStyle, the colour accessors on Theme (background, grid, text, bullish, tpo_*, footprint_* and the others), theme::all_presets, theme::all_themes, and theme::SemanticTokens with IndicatorSemanticTokens and DrawingSemanticTokens, whose fields nothing read. Migration: use Theme::dark(), Theme::light() or Theme::high_contrast(), and theme::presets() for the list; the Classic look is Theme { chart: Theme::dark().chart, ..Theme::light() }; Midnight was identical to Dark; persist a theme choice in the application (with the serde feature, serialise the Theme). TPO and footprint colours are in DESIGN_TOKENS.semantic.tpo and DESIGN_TOKENS.semantic.footprint.

  • Fields of the old theme colour structs that nothing drew with, and their constructors and alpha helpers. Migration: UiSemanticTokens::icon_disabled is ui.text_disabled; ChartSemanticTokens::bg_legend is chart.bg_tooltip; price_line is chart.axis_text; price_label_bg and price_label_text are chart.crosshair_label_bg and chart.crosshair_label_text; watermark was the secondary axis text in dark themes and the muted text in light ones at DESIGN_TOKENS.semantic.chart.watermark_alpha; bg_selection has no replacement. For candle_up_alpha(a) and candle_down_alpha(a), build the colour from chart.candle_up or chart.candle_down with Color32::from_rgba_unmultiplied. For UiSemanticTokens::from_design_tokens(dark) and ChartSemanticTokens::from_design_tokens(dark), take ui or chart from Theme::dark() or Theme::light(); the from_design_tokens constructors of SemanticTokens, IndicatorSemanticTokens and DrawingSemanticTokens went with those types.

  • Design tokens that nothing read: tokens::ListItemSemanticTokens, HeatmapSemanticTokens, ToastSemanticTokens, TierSemanticTokens, AuthDialogSizingTokens, BurgerMenuSizingTokens, ChartSizingTokens, CursorSizingTokens, EmojiPickerSizingTokens, FootprintSizingTokens, RightSidebarSizingTokens, WatermarkSizingTokens and WidgetSizingTokens with the SemanticTokens and SizingTokens fields that held them, and 111 unread fields of the other token structs. Migration: code that named a removed token uses the value it held, listed in src/tokens/design_tokens.ron of 0.2.0; colour tokens there name a palette entry (for example blue_500) whose RGB value is in the file’s palette section.

  • theme::ThemeData, theme::ThemeContextExt, theme::ThemeUiExt, theme::context::{get_icon_color, get_icon_hover_color, get_icon_active_color}, ext::DesignTokens, ext::HasDesignTokens, ext::ContextExt and the theming module, which were five ways to read the same colours, and styles::margin and the styles::sizing modules toolbar, auth_dialog, footprint, indicator and candle, which nothing used. Migration: ctx.active_theme() and ui.active_theme() (trait theme::ThemeExt) return the theme last applied, or the dark theme, instead of an Option, and ctx.theme_data() and DesignTokens::from_context(ctx) are ctx.active_theme(); set_theme_data is apply_to_egui; a ThemeData or DesignTokens colour is the Theme field of the same meaning (ui_text and text_primary() are ui.text, chart_bg_axis and chart_axis_bg() are chart.bg_axis, crosshair() is chart.crosshair_line, volume_bullish is chart.volume_up()), and page_bg was ui.panel_bg_secondary in dark themes and chart.bg in light ones; colours that egui models are read from ui.visuals(). By replacement: visuals.panel_fill for theming::toolbar_bg, panel_fill() and theme_panel_bg(); visuals.widgets.hovered.bg_fill for theming::hover_color, theming::btn_bg_hover, hover_bg() and theme_hover_bg(); visuals.widgets.active.bg_fill for theming::sel_color, theming::btn_bg_pressed, active_bg() and theme_active_bg(); Color32::TRANSPARENT for theming::btn_bg_normal; visuals.widgets.noninteractive.fg_stroke.color for theming::icon_color, icon_normal and muted_color, icon_color(), text_secondary(), theme_icon() and theme_text_secondary(); visuals.widgets.hovered.fg_stroke.color for theming::icon_hover_color and theming::icon_active, icon_hover() and theme_icon_hover(); visuals.strong_text_color() for theming::active_icon_color, HasDesignTokens::text_color() and theme_text(); visuals.text_color() for theming::text_color; visuals.widgets.noninteractive.bg_stroke.color for theming::separator_color, border_color() and theme_border(); visuals.weak_text_color() for ThemeData::ui_text_muted and text_muted(); visuals.warn_fg_color for warning_color() and theme_warning(); the theme’s ui.accent for theme_accent(), theme_icon_active(), accent_color(), icon_active() and theming::publish_button_bg, and ui.accent_hover, ui.accent_active and ui.accent_text for publish_button_bg_hover, publish_button_bg_pressed and publish_button_text; ui.accent_text for ThemeData::ui_accent_text; ui.danger_text for theming::badge_text_color; ui.success for success_color() and theme_success(); chart.bg, chart.grid_line, chart.axis_text, chart.candle_up and chart.candle_down for chart_bg(), chart_grid(), theme_chart_text(), bullish_color() and bearish_color() and their theme_ forms; DESIGN_TOKENS.semantic.footprint for the footprint colour getters; theme.dark for is_dark_ui() and ContextExt::is_dark_mode(), and theme.chart.bg.intensity() < 0.5 for is_dark_chart(). theming::active_hover_color, pill_bg, lighten_color and darken_color have no replacement; for an opaque colour, lighten_color(c, f) is c.lerp_to_gamma(Color32::WHITE, f) up to rounding. The ContextExt device queries returned constants, and is_touch_active is ctx.input(|i| i.any_touches()). For styles::margin, use the egui::Margin constructors. Widgets drawn before any apply_to_egui call read the dark theme, not the light colours of ThemeData::default().

  • The unused panel_bg, panel_border and header_bg fields of tokens::ModalSemanticTokens. Migration: use the theme’s ui.panel_bg_floating and ui.border.

  • scales::{DualPriceScaleManager, PosedPriceScaleOptions, SeriesScaleAssignment, PriceDisplayMode, AutoScaleMode}, which nothing used. scales::PriceScaleId stays.

  • ChartMapping::x_only and ChartMapping::with_price_range, which nothing called. Migration: build the mapping with the PriceMap it needs.

  • widget::apply_price_zoom and widget::y_to_price, which assumed a linear axis. Migration: PriceScale::zoom and PriceMap::y_to_price.

  • Chart::get_rendered_price_range. Migration: Chart::get_chart_mapping().price maps prices exactly as the last frame drew them.

  • Chart::apply_price_zoom, a step of Chart::show. Migration: zoom the price axis with chart.price_scale_mut().zoom(factor, anchor).

  • PriceScaleOptions::{align_labels, border_visible, visible, ticks_visible, entire_text_only}, which nothing read. Migration: remove them from struct literals; ChartConfig::show_right_axis shows or hides the price axis.

  • ui_kit::buttons::button_bg and ui_kit::buttons::icon_color, which had no pressed state. Migration: use ButtonVariant::Ghost.bg_color(ui, hovered, pressed), or ButtonVariant::Primary for a selected button, and ButtonVariant::fg_color.

  • The Volume Footprint and Session Volume chart types, which approximated per-price volume from bar totals, with their icons::icons::CHART_VOLUME_FOOTPRINT and icons::icons::CHART_SESSION_VOLUME icons, and the unused model::footprint module.

  • The chart::series_api module (ISeriesApi, IPriceScaleApi, ITimeScaleApi, IStudyApi, their implementations and option types), which nothing constructed.

  • The series context menu “Hide” entry (SeriesContextMenuAction::Hide), which had no effect.

  • DrawingManager::update_pos_prices, Drawing::format_timestamp, and the Drawing fields is_closed, curr_price, forecast_start_price, forecast_target_price, forecast_start_time, and forecast_target_time; position and forecast results come from the chart’s bars.

  • Unused icon constants AREA_CHART, LINE_CHART, ORDER_BOOK, TIME_AND_SALES, HIDE, RISK_REWARD_SHORT, TREND_BASED_FIB_EXTENSION, ZOOM_TOGGLE, EMOJI_EAGLE, EMOJI_ORNAMENT, WIDGET_BAR_NOTIFICATIONS, WATCHLIST_44, SCREENER_44, PINE_SCRIPT_44, COMMUNITY_44 and PRODUCTS_44. Migration: use CHART_AREA, CHART_LINE, WATCHLIST, EYE_HIDE (or EYE for the visible state), SHORT_POSITION and FIB_EXTENSION; the others have no replacement.

  • The unused series renderers chart::series::{LineSeries, AreaSeries, BaselineSeries, HistogramSeries, BarSeries} and the Series trait with SeriesData and SeriesType, which the chart never drew through. No replacement; the chart renders its series from ChartType.

  • The model::enums module of wire-format enums, which nothing used, with ChartType::to_chart_style and From<ChartStyle> for ChartType. Migration: use scales::PriceScaleMode for PriceScaleMode, ChartType for ChartStyle, and model::LineStyle for LineStyle (it has no large-dashed or sparse-dotted style); CrosshairMode and ColorType are unrelated to config::CrosshairMode and model::ColorType and, like ChartMode, Timezone, MagnetMode, Orientation, Size, Resolution, ChartTheme, PriceLineSource, ScaleLocation, BackgroundType, OverrideLineStyle, OverridePriceAxisLastValueMode, ChartStyleParameters, ClearMarksMode, MarkLocation, StudyPlotType, StudyDisplayTarget, StudyInputType, StudyTargetPriceScale, LineStudyPlotStyle, OhlcStudyPlotStyle and FilledAreaType, have no replacement.

  • ui::top_toolbar::components::symbol_search::popular_symbols, a fixed list of index, crypto, commodity and forex tickers. Migration: pass your own symbols to CompareSymbolsDialog::show.

  • The templates module. Migration: import SettingsTemplate and TemplateManager from ui::model.

  • CVDMode::TickSplit, which computed the same estimate as CVDMode::ClosePosition while claiming footprint data; use ClosePosition. CVD::with_histogram, which had no effect, with no replacement.

  • The Iceberg, Liquidity and Stop Run studies: IcebergDetector, IcebergDetection, LiquidityTracker, LiquidityLevel, LiquiditySweep, LiquidityZone, LiquidityZoneType, SweepDirection, StopRunIndicator, StopRunDetection and StopRunType, and the factory names “Iceberg”, “Liquidity” and “Stop Run”. Bars carry no trades and no order book, so these studies guessed hidden orders, swept liquidity and stop runs from bar shapes and from volume spread evenly over each bar’s range. Studies compute fixed aggregations of the data the chart receives; CVD, Net Volume and the volume profiles are unchanged. Migration: detect these events in your application or on your server, from your own trade and order book data. IndicatorFactory::create returns None for the three names, so code that builds studies from stored names should skip unknown ones.

  • The ui::watermark module (Watermark, WatermarkManager, TextWatermark, TextWatermarkLineOptions, ImageWatermark, ImageScaleMode, HorizontalAlign, VerticalAlign and its own WatermarkPos), which the chart never drew. Migration: ui::watermark is removed; the chart’s watermark is configured through ChartConfig (show_watermark, watermark_text, watermark_color, watermark_font_size and watermark_pos, a config::WatermarkPos). Image watermarks, custom pixel positions and a font size, colour or weight per line have no replacement; watermark_text may contain \n for several lines in one style.

  • StoredColor, StoredValue, StoredDrawing::{tool_type, color, line_width, selected, locked, visible, properties}, StoredDrawing::{set_property, get_property} and StoredCoord::{from_screen, to_screen} from drawings::persistence. Migration: read and set the settings on StoredDrawing::drawing; selection is not stored.

  • Deserialize for drawings::persistence::DrawingStorage, which skipped the version check, the migration and per-drawing loading. Migration: load with DrawingStorage::from_json. To keep drawings inside your own serde state, store the to_json text and pass it to from_json.

  • The scripting feature and module, the script editor dialog in ui::dialogs with its action enum, and the indicator dialog’s “My scripts” category (IndicatorCategory::MyScripts), which listed the built-in indicators. The interpreter ignored the source argument of most ta functions, never reported a crossover and ran one statement per block, and the editor ran scripts on no bars and could not add one to a chart. Migration: write custom studies in Rust with studies::CustomIndicator; 0.2.0 keeps the module.

  • The backtest feature and module, and the indicator dialog’s “Strategies” tab (IndicatorTab::Strategies), which listed the built-in indicators. The backtester filled orders at the close of the signal bar, stamped trades with the wall-clock time, dropped orders larger than the cash without notice and left several metrics unset. The dialog is titled “Indicators” and the series context menu entry reads “Add indicator”. Migration: run backtests in the host or on a server against the headless engine with the built-in studies (default-features = false, features = ["studies"]); 0.2.0 keeps the module.

  • IndicatorPalette, IndicatorColorSchemes and ColorCategory, which no study or component used. Study colours come from Indicator::colors and the theme.

  • ToastKind::bg_color and ToastKind::text_color, fixed colours that ignored the theme. Migration: ToastKind::color(&theme.ui) gives the kind’s status colour; a toast draws on visuals.window_fill with theme.ui.text.

  • AlertKind::bg_color, AlertKind::border_color and AlertKind::icon_color, fixed colours tuned for the dark theme. Migration: AlertKind::color(&theme.ui) gives the kind’s status colour; an alert fills with color.gamma_multiply(0.1) and outlines with color.gamma_multiply(0.4).

  • Chart::update_data and Chart::data. Migration: chart.update_data(BarData::from_bars(bars)) becomes chart.set_data(SeriesId::MAIN, bars), or chart.update(SeriesId::MAIN, bar) for each new or changed bar, and chart.data().bars becomes chart.bars(SeriesId::MAIN). The bool that update_data returned has no replacement: the chart follows the live edge itself when ChartOptions::time_scale.shift_visible_range_on_new_bar is set.

  • The validation module (DataValidator and its result types) and Chart::{enable_validation, disable_validation, set_validator, is_validation_enabled}, which only logged problems: every bar is validated and invalid ones are dropped. Migration: remove the calls; Chart::feed_state(SeriesId::MAIN).rejected_bars counts the dropped bars.

  • ChartBuilder::extended and ChartBuilder::with_drawing_tools: every chart has studies and drawings. Migration: use ChartBuilder::new().

  • The consuming Chart::config(self, config), whose name now reads the configuration. Migration: build with Chart::with_config(data, config) or set *chart.config_mut() = config.

  • Chart::timescale_marks, which was never drawn.

  • examples/tauri_integration.rs, replaced by examples/live_feed.rs.

  • TradingChart: use Chart, built with ChartBuilder (see Changed). Its studies and drawings live on the chart: tc.indicators.add(s) becomes chart.add_indicator(s), tc.drawing_manager becomes chart.drawings_mut(), tc.remove_indicator(i) becomes chart.remove_series(id), tc.set_indicator_visible(i, v) becomes chart.set_indicator_visible(id, v) with the study’s SeriesId, tc.remove_drawing(id) becomes chart.drawings_mut().delete_drawing(id), tc.get_last_bar() becomes chart.bars(SeriesId::MAIN).last(), tc.get_symbol() and tc.symbol become chart.symbol(), tc.timeframe becomes chart.timeframe() (an Option), and tc.data_src has no replacement: pass the feed to ChartBuilder::with_feed.

  • data::DataSource, DataSourceError, DataUpdate, HistoricalDataRequest, SymbolSearchResult, PaginatedSearchResult, BarMark and TimescaleMark, and the DataSource re-export at the crate root. Migration: implement data::Datafeed: answer history through the Reply (HistoryRequest::before is an exclusive DateTime<Utc>, None for the latest bars), and for live data push into the Sink given to subscribe. Errors map to FeedError: ConnError, FetchError and IoError to Network, ParseError and InvalidTimeRange to InvalidData, SymbolNotFound to SymbolNotFound, RateLimited to RateLimited { retry_after: None } and NotSupported to NotSupported. Symbol search is the services::SymbolSearch service.

  • ChartBuilder::{with_data_src, with_auto_fetch, with_auto_fetch_on_symbol_change, with_auto_fetch_on_timeframe_change}: use with_feed; a feed always reloads on a change.

  • ChartBuilder::{with_left_price_scale, with_left_axis_width, with_right_axis_width}, which set fields the chart never read.

  • ui::context_menu::ContextMenuAction::RemoveIndicator, which no menu produced. Remove a study with Chart::remove_series.

  • model::TickSource and model::OrderBookSource, which the chart never polled: push trades with Sink::push_tick and the order book with Sink::push_depth_snapshot and Sink::push_depth_delta.

  • model::LibrarySymbolInfo, SymbolFormat, SubsessionInfo and the model::symbol_info module, which nothing read: describe an instrument with model::Instrument. SymbolType is unchanged at model::SymbolType. model::DataStatus is now the type of Instrument::data_status, with the variants Realtime (formerly Streaming), Delayed and EndOfDay; Pulsed has no replacement, and the type no longer implements Default, Display or serde’s traits.

  • model::bar::{MAX_BARS, MAX_VISIBLE_BARS} and BarData::{trim_to_limit, push_with_limit}, which nothing applied.

  • TopToolbarAction::{ChartGridChanged, SetSyncOptions} and the TopToolbar::{chart_grid_selector, sync_button} fields, which the toolbar never drew: no control emits them. ChartGridSelector and SyncButton stay in top_toolbar::components.

  • DrawingToolbarAction::{ClearSelection, AddFavorite, RemoveFavorite, OpenSettings, DeleteTemplate}, which no control emits.

  • TimeframeToolbarAction::{TimeframeChanged, GoToDate, TimezoneChanged, SessionChanged, ZoomFitAll, ZoomToRange, ToggleTradingPanel, TradingPanelFullscreen}, which no control emits, and ui::timeframe_toolbar::{TradingPanelRow, TradingPanelRowAction, TradingPanelRowConfig}, which nothing drew, with the PanelSizingTokens::{trading_panel_row_height, trading_panel_row_icon_size, trading_panel_row_btn_size} tokens that sized it and TimeframeToolbarState::{trading_panel_expanded, toggle_trading_panel, set_trading_panel_expanded}, which nothing read. Migration: the date picker emits DatePickerAction::GoToDate.

  • ObjectTreeAction::{ShowSelected, LockSelected, UnlockSelected, UpdateProperties, Reorder, BringSelectedToFront, SendSelectedToBack, PanTo, SaveAsTemplate, LoadTemplate, DeleteTemplate, ToggleDataWindow}, which no control emits.

  • ContextMenuAction::{GoToDate, ChangeSymbol, ChangeInterval, SymbolInfo, InsertIndicator, CompareOrAddSymbol, DrawingTools, HideMarksOnBars, PriceScale, TimeScale}, which no menu entry emits.

  • SettingsAction::LayoutStyleChanged and SeriesSettingsAction::ResetToDefault, which no control emits.

  • The top toolbar’s Menu, Trade and Publish buttons with TopToolbarAction::{OpenMenu, OpenTradingPanel, Publish}, and top_toolbar::buttons::{PillButtonFilled, PillButtonOutlined}, whose only users they were. No service backs them: the order ticket brings its own buttons, and a desktop app has its own main menu.

  • The chart context menu’s Paste, Add order, Lock vertical cursor line by time and Table view entries with ContextMenuAction::{Paste, AddOrder, LockVerticalCursor, TableView}, which nothing implemented.

  • The series context menu’s Add order, Add financial metric, Security info, Metrics, Paste, Table view, Visual order, Move to, Pin to scale, Add to watchlist and Add text note entries with their SeriesContextMenuAction variants, which nothing implemented. The menu offers Add alert, Add indicator, Copy price and Settings.

  • The drawing context menu’s Copy entry and DrawingContextMenuAction::Copy: there is no drawing clipboard. Migration: match Clone to duplicate a drawing.

  • MenuItem::submenu and MenuItem::is_submenu, with the ContextMenuSizingTokens::submenu_arrow_font_size token of their arrow: no menu row opens a submenu.

  • ExportConfig::{include_title, include_timestamp, include_watermark, width, height, transparent_background} and the export dialog’s checkboxes and size options for them, which no export applied, and ExportFormat::Svg with Exportable::export_svg, which nothing rendered. Migration: build ExportConfig { format }; an image export has the size of the chart on screen.

  • TimeframeUnit::Tick and the tick intervals of the interval menu: no data contract carries tick bars.

  • DrawingToolType::Paintbrush, which drew exactly as Brush and was on no menu. Migration: use DrawingToolType::Brush. Drawings saved in the crate’s JSON format (DrawingStorage, versions 1 and 2) and other formats that store the tool by name, and names parsed with FromStr, load Paintbrush as a brush. Data that stores the variant index (bincode, postcard) must be re-saved in a name-based format before upgrading.

  • The drawing bar’s Favourites button, utilities::FavoritesButton, DrawingToolbarAction::ToggleFavoritesToolbar and ToolbarState::show_favorites_toolbar: the button filled and nothing else changed. The stars in the flyouts keep the favourites list. categories::trend_lines::get_shortcut and categories::fibonacci::get_shortcut are gone; the flyouts read DrawingToolShortcuts. The Remove menu no longer has a separate “Remove All Studies” row; DrawingToolbarAction::RemoveAllStudies remains.

  • Click-to-select for indicators and series on a single unified selection model, with on-chart selection handles.
  • Right-click context menus for the chart background, a series, and a drawing, opened directly from the chart.
  • Hover tooltip with an OHLC readout, in floating, tracking, and magnifier modes.
  • Session-break dividers and optional background shading, with a ChartBuilder::with_session_breaks toggle (timeframe-aware day, week, and month boundaries).
  • TPO / Market Profile chart type with point-of-control and a contiguous 70% value-area computation, rendered as letters or blocks.
  • Remove an indicator from its pane legend; Chart::take_indicator_remove surfaces the request to host applications.
  • Host interaction plumbing: Chart::take_right_click and RightClickTarget, TradingChart::take_context_action and ChartContextAction.
  • TradingChart controller helpers: config_mut, apply_series_settings, remove_indicator, set_indicator_visible, and remove_drawing.
  • The bundled demo is now a complete application: every toolbar action, all dialogs, the object-tree and alerts panels, and bar replay are wired, and it is published as a live WebAssembly build.
  • Backtest equity now signs short positions correctly, and the Sharpe, Sortino, and Calmar ratios are no longer inflated by a percent-versus-fraction unit mismatch.
  • RSI output length now matches the bar count and is no longer misaligned by one bar.
  • The indicator factory constructs every built-in indicator by name rather than a small subset.
  • Heikin-Ashi candles are computed over the full series, so they no longer change shape on pan and zoom.
  • Coordinate and formatter transforms guard against flat price ranges and zero denominators.
  • Drawing hit-testing is unified through a single path, and an undone add now survives history pruning so redo still works.
  • Selection handles render correctly when the chart is scrolled.
  • Embedded SVG icons render because the image loaders are now installed automatically, and notification timing no longer panics on WebAssembly.
  • The bundled examples compile again.
  • Issue #1: the focus ring appeared when the pointer merely hovered the chart. Issue #2: the examples did not compile.
  • Renamed ui::stubs to ui::model.
  • Corrected the documented metrics to match the code.
  • CI now builds the examples and runs the documentation and feature-gated tests.
  • The unused egui_plot dependency.
  • Superseded legacy renderers and the unused render pipeline.

Thanks to @intelligentnet and @sstscrypto for the reports that became issues #2 and #1.