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.
| Category | Built-in rows | Picker label |
|---|---|---|
| overlap | 21 | Trend |
| momentum | 36 | Momentum |
| volatility | 16 | Volatility |
| volume | 14 | Volume |
| statistics | 13 | Statistics |
| pattern | 63 | Patterns |
| price | 4 | Price |
| structure | 4 | Structure |
| user | 0 | User |
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.
Cheatsheet
Every host function a strategy script can call, every hook it can define, and the indicator call forms — one scannable page beside the full ones.
Overlap indicators
The 21 built-in overlap indicators Vike Trader ships, with every parameter, its default and its sweep range — rendered from the indicator registry.