vike
Desktop app

The chart

The vike-chart engine — twenty styles, draggable panes, streaming indicators, price-scale modes, compare series, microstructure studies and timestamp-keyed cross-window sync.

The chart is its own crate. crates/vike-chart/src/lib.rs describes what it owns: the GUI-local render model (an integer bar-index model::Bar / model::ChartState, fed per core snapshot by the app), the egui_plot renderer chart::draw with its twenty styles, volume and oscillator sub-panes, follow-live edge and visible-range y-autofit, the synthetic style transforms, the per-bar order-flow rendering, and the indicator paint adapter indicators::Active over the parity-gated vike-indicators compute core. Its dependency contract is the reason it is testable at all: no windowing, no GPU layer, no execution core — data arrives as plain ChartStates, so the crate rides the ordinary CI roster while the GUI shell around it is only compile-checked.

Styles

crates/vike-chart/src/chart/mod.rs's ChartStyle::ALL lists all twenty in menu order, and STYLE_SECTIONS groups them: Bars (Candles, Hollow candles, Heikin Ashi, Volume candles, Bars, HLC bars, High-low), Lines (Line, Line with markers, Step line, Area, Baseline, HLC area, Columns), Special (Renko, Range, Line break, Kagi, Point & Figure) and Orderflow (Footprint). The order is load-bearing — a workspace file persists a style as its index into ALL, so new styles are appended and never inserted.

The five Special styles are close-based, deterministic transforms (crates/vike-chart/src/transforms.rs) that live on an ordinal axis: t becomes the unit index while each unit keeps its source bar's timestamp for approximate labels. auto_box derives the default box or reversal size from an ATR fold and falls back to 0.5% of the last price floored at one price unit, so an instrument priced under 200 gets a fallback of 1.0. Footprint is different in kind — an alternate per-bar substrate of buy/sell price cells on the same bar axis, which falls back to plain candles when no footprint input is present (default off). Where each order-flow study renders is on In the GUI.

The pane stack

Below the price pane sit Volume, an optional CVD pane, and one pane per oscillator study. crates/vike-chart/src/panes.rs's PaneFractions gives every pane a persisted, identity-keyed fraction of the available height: the key is the pane's kind plus the oscillator's stable Active::uid, never its position, so hiding, re-showing or reordering studies never scrambles which stored share belongs to which pane. PaneFractions::drag is the separator: it transfers height between exactly the two adjacent panes, clamped so neither crosses the minimum. Studies can be merged into an existing pane or moved to a new one above or below an anchor (crates/vike-app-core/src/workspace/state.rs's WinState::move_study), and the ƒx picker's "Add to" selector chooses the target at add time.

Indicators

crates/vike-chart/src/indicators.rs re-exports the registry, the picker Category axis and the render-placement axis from vike-indicators; only egui colours, visibility and the bar conversion live in the chart. Each Active keeps a persistent streaming instance folded over the closed prefix only, and Active::update does the cheapest correct thing per frame: nothing when the closed series is unchanged, one on_bar when exactly one bar closed, a full refold only on a structural change. The forming bar is previewed on a throwaway clone. The header carries a measurement worth knowing: that clone once deep-copied the retained history every frame — at vwma's registry maximum period = 400, 4.6 MB and 1006 µs per frame for one overlay — and is now bounded to a finite-window kernel that took the same clone to about 7.8 µs. A user-written Rhai indicator is still the interpreter itself, so its per-frame clone plus one script evaluation is the price of plotting it.

User indicators from user_data/indicators/*.rhai sit in a second registry rather than in the built-in catalog; WinState::add_indicator resolves through get_any, so a workspace restores one by name exactly like a built-in and silently skips a file that has since gone. The picker itself (crates/vike-app-core/src/tool_views/fx_picker.rs) offers search, category tabs, a ★ Favourites section that is global across windows, a "✎ My indicators" section, and an "On this chart" list with per-study settings and a foreign source-symbol menu. The catalog is on Indicators.

Scales, follow-live and autofit

crates/vike-chart/src/scale.rs's ScaleMode is the seam between raw price space and what egui_plot draws: Linear, Log (strictly positive prices only), Percent, and Indexed to 100; Invert is an orthogonal flag. crates/vike-chart/src/chart/controls.rs's y_gutter documents the right-click menu on the price axis (Auto / Regular / Logarithmic / Percent / Indexed to 100 / Invert), and WinState::scale notes Alt+L as the toggle hotkey. Every transcendental in scale.rs is spelled through the libm crate so a tick step never depends on which platform libm rounded the last bit.

crates/vike-chart/src/interact.rs's FollowLive pins the view to the right edge while engaged; panning or zooming away disengages, and Reset, Auto or panning back re-engages. Its auto_y flag is the visible-range y-autofit: y bounds refit every frame and interactions are x-only while engaged; a right-gutter drag disengages it, and the price-gutter double-click, the Auto button, a Reset, or a history reload re-engage it. crates/vike-chart/src/lod.rs's lod_decimate collapses a far-zoomed view to about one min-max OHLC bar per screen column, and returns the visible slice untouched at normal zoom so the LOD path is byte-identical to the pre-LOD render.

Settings, compare, studies, sync

The chart-settings dialog (crates/vike-chart/src/chart/dialogs.rs) is tabbed Symbol / Canvas / Scales and edits a working copy of crates/vike-chart/src/options.rs's ChartOptions — candle, wick and border colours, the canvas background including a vertical gradient, grid toggles, autofit margins, the last-price line, a price-precision override and the volume pane — with live preview until OK commits.

WinState::compare overlays other symbols on the price pane as %-normalized lines; a compare symbol can be moved to its own pane and pinned to its own absolute right axis (ScaleAssign::Right). crates/vike-chart/src/studies.rs is the tick-driven twin of Active: VPIN, book imbalance and order-to-trade ratio fold over the live tape and are sampled once per bar close, carrying the last value through quiet bars; the two book-dependent studies stay empty until a book snapshot has actually arrived, so no line is fabricated.

crates/vike-chart/src/sync.rs keys cross-window sync on timestamps, because bar indices do not align across symbols or intervals; WinState::sync_group (1–4) broadcasts a ghost crosshair and a sticky-leader visible range across grouped windows. Display timezone is one global setting (crates/vike-chart/src/tz.rs's DisplayTz::CURATED, thirteen zones, default Local).

One cache key is trusted by every cache

crates/vike-chart/src/model.rs's cache_key field doc records the trap: the closed length, first and last open-times and timezone identity form one key that y-extent, grid marks, the volume cache, the transform cache and the incremental sync all trust. A revised historical bar, or two venues aliased onto one symbol@interval chart key, changes the interior without changing that key and goes stale in every cache at once.

On this page