vike
ConceptsInstruments

Instruments

One parametric Instrument record over an eleven-variant asset-class enum, and the cross-venue catalog that fills it.

Every tradable thing in Vike Trader is the same Rust record. vike-catalog describes itself as the "universal cross-venue instrument catalog" and is deliberately bridge-free — it depends on vike-model only, so the per-venue bridge crates and the chart crate can all depend on it down-only (crates/vike-catalog/src/lib.rs). It holds the Instrument model, the AssetClass taxonomy, a two-mode CatalogProvider trait, a declarative venue registry, and the tiered fuzzy search the Symbol picker renders from.

One record, not twenty types

crates/vike-catalog/src/instrument.rs's Instrument is seven fields: venue, raw_symbol, asset_class, base, quote, description, and a SymbolProperties grid that "may be Default until fetched". Product differences are carried in those fields and in the class tag, not in a type hierarchy — the AssetClass doc states its whole job in one line: it "drives picker tabs, symbology expectations, and market-hours". Those three consequences are the three pages beside this one: symbology, the placement grid on symbol properties, and sessions.

Identity follows a {symbol}.{venue} shape. Instrument::id renders format!("{}.{}", raw_symbol, venue.to_uppercase()) — BTCUSDT.BINANCE, AAPL.ALPACA. A derivative stays distinct from its spot twin because its raw_symbol is already distinct: OKX's dashed BTC-USDT-SWAP, Deribit's instrument names, and a .P-suffixed perp symbol on the venues that reuse one string for both. No extra product suffix is applied at id() time: the body is that one format!, and the test id_disambiguates_perp_from_spot_via_distinct_raw_symbol in the same file pins distinctness to raw_symbol. The opening line of that method's own rustdoc still describes an earlier design in which id() appended .P/.F/.O; the code under it does not.

Eleven classes, eight tabs

crates/vike-model/src/asset_class.rs's AssetClass has eleven variants: Equity, Etf, CryptoSpot, CryptoPerp, CryptoFuture, Option, Fx, Future, Index, PredictionMarket, Cfd. Each has its own page in this section.

AssetClass::tab folds them onto eight picker tabs: Stocks takes Equity and Etf; Forex takes Fx and Cfd; Crypto takes CryptoSpot; Perps takes both CryptoPerp and CryptoFuture; Options, Futures, Indices and Prediction take their single class each. The "All" tab is not a Tab variant — it is Option::None in a filter, which the Tab doc says outright.

The Index class is slugged index-instrument

AssetClass::Index is documented at index-instrument, because the index slug is this page.

How a venue contributes

crates/vike-catalog/src/provider.rs's CatalogProvider is the venue contribution seam: venue(), asset_classes() and mode() are required, while list_instruments and search_remote both ship default impls returning an empty vector, so a venue implements only the half its mode uses.

CatalogMode has two variants, and its doc says the choice is made by "API shape + size, NOT asset class":

  • Enumerable — a bulk list endpoint and a cacheable universe, so the whole set is fetched once and searched locally. Bybit's provider, for instance, reads the keyless public /v5/market/instruments-info with unsigned GETs for category=spot and category=linear (crates/bridges/bybit/src/catalog.rs).
  • QueryBacked — no bulk endpoint, or a universe too big for one (the provider doc names IBKR as the case). The venue's own server is searched per query and nothing is cached.

CatalogSource is the orthogonal client-side axis — Direct or ServerBacked — and its doc marks the server-backed path as a later phase, with the type present now so the design is stable.

Providers are constructed by hand per binary. crates/vike-model/src/venues.rs says so plainly: there is no central provider registry to enumerate, which is why BRIDGE_VENUES is a flat slug list rather than something derived from the impls. That list is literally vike_model::VENUES, the canonical roster the venue pages are generated from, and a set-equality test (mirrors_the_canonical_roster) fails if a future edit ever re-points it at a private copy. It once had a private copy: Hyperliquid's bridge merged without being added here, so that venue never appeared in the credential grid at all.

Search and cache

crates/vike-catalog/src/catalog.rs's tier ranks a hit in five bands — exact symbol, symbol prefix, base prefix, substring, no match — and quote_rank breaks ties among equal-tier hits in the order USDT, USDC, USD, BTC, everything else.

The Enumerable half is cached on disk as a CatalogCache plus one VenueStamp per venue. crates/vike-catalog/src/persist.rs states the refresh discipline: the cache is "loaded instantly at startup; rewritten only on an explicit user refresh (no auto/background re-fetch)", and QueryBacked venues are never cached. Each stamp carries the venue, its last refresh time and its instrument count, which is what the Data Manager catalog view renders.

On this page