vike
Indicators

Indicators

The built-in indicator catalog — 171 single-series indicators across nine categories plus 8 pair indicators — and the one guarantee every one of them carries.

Vike Trader ships 171 built-in single-series indicators and 8 two-series pair indicators. Neither number is a hand count: crates/vike-indicators/tests/parity.rs's registry_is_complete_and_consistent asserts the registry holds exactly 171 uniquely-named rows and that make round-trips every one, and crates/vike-indicators/tests/pairs_parity.rs's pair_registry_is_complete_and_consistent does the same for the 8.

The one guarantee

Every indicator is two implementations of one series. Indicator::on_bar is the streaming path — feed the next bar, advance, get this bar's output line or lines, with no lookahead; the event engine and the live path use it. Indicator::vectorize is the batch path — the whole series at once, one Vec<f64> per output line; the vector engine and the chart use it.

They are one source of truth: on_bar folded over a series equals vectorize on that series bit-for-bit. parity.rs's on_bar_equals_vectorize_for_every_indicator is that gate, and it compares through f64::to_bits with both-NaN counted equal — never through a tolerance. vectorize is the reference kernel, warm-up positions emit f64::NAN, and fold order (naive left folds) is load-bearing rather than incidental.

Three indicators read the future, and they say so

ichimoku (its chikou line), zigzag and williams_fractal are flagged IndicatorMeta::batch_only: their batch form reads bars ahead of the one being computed, so no causal streaming path can equal it. vectorize is the authority, on_bar is a best-effort that is NaN at the unknowable tip, and the parity gate skips exactly these three. Every other row sets the flag false — the exceptions are declared in the registry, not discovered by a reader.

The nine categories

A category is a vike_indicators::Category variant — a picker grouping, not a source file. Each gets a page listing every indicator in it with parameters, defaults and sweep ranges; Category::label is where the display name comes from, which is why Overlap shows as Trend.

CategoryBuilt-in rowsPicker label
overlap21Trend
momentum36Momentum
volatility16Volatility
volume14Volume
statistics13Statistics
pattern63Patterns
price4Price
structure4Structure
user0User

Those pages are generated: crates/vike-ops/src/docs_data.rs renders indicators.json from vike_indicators::registry and pair_registry — every Category variant, empty ones included, because a category that vanished for having no rows is the silent omission that exporter's gate refuses.

Warm-up and seed history

Indicator::lookback is the index of the first bar at which vectorize yields a non-NaN value on any line. It is not a seed size for a multi-line indicator: adx's namesake line trails its +DI/-DI, macd's signal and histogram trail the macd line. Indicator::lookback_full — the first index at which every line is valid — is the number to size seed history with, and is always at least lookback; both are reachable by name and parameters through registry::lookback and lookback_full. lookback is a conservative lower bound: rows with a real parameter-derived override report IndicatorMeta::lookback_exact and are gated ==, the rest >=, and tests/lookback.rs's EXACT_FLOOR ratchet holds the exact-override count at 105 or more.

A lookback of zero does not always mean warm

Indicator::warmup_path_dependent flags the indicators whose value depends on all history since the mount rather than on a bounded window. Their lookback() of 0 is truthful — they emit a number from bar one — but it is not the number a chart holding full history shows: psar fabricates its initial trend, vwap accumulates only from the current UTC day as seen, and the cumulative series start at whatever bar the mount began at. Seed these with as much history as you have — for vwap, at least back to the UTC-day boundary.

Parameters, and where an indicator draws

Each parameter is a ParamSpec — a display name, the default that new() sets, and the min, max and step behind the dialog's sliders and the sweep grid. registry::coerce is the one value-coercion site: a missing entry or a NaN becomes the default, the result is clamped to [min, max], and extra values are ignored. Every parameterised constructor runs its slice through it, so make_with at the declared defaults reproduces make bit-for-bit.

Two axes sit orthogonal to the category. RenderKind says whether the indicator belongs on the price panel (Overlay) or in its own oscillator pane (Oscillator). OutputStyle says how each line renders — Line, Band, Histogram, Dots or Marker. Marker is pattern-exclusive and means a per-bar signal (+100 bullish, -100 bearish, 0 none) rather than a price, so the chart anchors a glyph to the flagged bar's own extreme and keeps the series out of the price pane's autofit. See the chart and the indicators pane.

Indicators you write, and pairs

The User category ships empty and always will: IndicatorMeta::user rows never sit in registry(). The variant exists because it is the one honest answer for a file the crate has never seen — filing a user indicator under Statistics would claim a classification nobody made. Writing an indicator and loading indicators cover that path; the custom-indicator tutorial proves your own kernel streaming-equals-batch with the shipped harness.

Pair indicators read a second instrument, which a single bar cannot supply, so they live behind their own PairIndicator trait and pair_registry, isolated from the single-series seam. Two of the eight — half_life and kalman_beta — port nothing: they are statistics that return a plottable number and decide nothing, which is why they sit on a shared seam rather than inside one strategy.

The same bits on every box

IEEE 754 does not require ln, log10, exp or atan to be correctly rounded, so two C runtimes may disagree in the last bit. Measured, not assumed: fisher, hvol, chop, linearreg_angle, alma and the pair kernels spread and correl_log hashed differently on Windows and Linux. The crate calls libm rather than the platform's, and two gates hold it — libm_cross_platform_pin pins the values to one committed set for all platforms, and production_code_calls_libm_not_the_platform reads every production line under src/ and refuses the platform spellings outright.

The indicators CLI verb prints this catalog from a terminal, narrowed to what a Rhai strategy can actually call: crates/vike-cli/src/cmd/indicators.rs's bound_metas keeps only the registry rows vike_script::RHAI_INDICATORS binds under a bare name or vike_script::line_accessors reaches by line, so its roster is smaller than 171 — and the three batch_only rows above, reachable by no spelling at all, appear in none of it. See reference/cli/research/indicators.

On this page