Venue-direct
The seven collectors that page a venue's own keyless history endpoint into the store — five klines bins sharing one CLI body, plus Dukascopy ticks and Hyperliquid candles.
Seven bins in crates/vike-backfill talk to a venue directly, and all seven sit behind the
venue-backfill feature (crates/vike-backfill/Cargo.toml): binance_backfill,
bybit_backfill, okx_backfill, aster_backfill, deribit_backfill, dukascopy_backfill and
hyperliquid_backfill. A default build has neither the module nor the bridge dependency, so the
invocation is cargo run -p vike-backfill --features venue-backfill --bin <name>. What they have
in common, from crates/vike-backfill/src/caps.rs: every one of them writes kind=bar, and
Dukascopy is the only venue-direct source that also serves a tick kind — quotes, never trades,
because .bi5 is a quote feed. None of them can repair a recorded trade or book gap.
The five klines bins
binance, bybit, okx, aster and deribit differ in nothing but the venue.
crates/vike-backfill/src/klines.rs is the one place their shape lives: commit_key is the
idempotency format, backfill_klines the fetch→ingest orchestration each venue binds with its own
VENUE constant and bridge fetcher, and run_klines_backfill_cli the CLI body every bin calls.
Its klines_usage text is what --help prints, and it is exact about the arguments:
<venue>_backfill <ROOT_DIR> <SYMBOL> <INTERVAL> <START_MS> <END_MS>All five are required and positional, in that order, and the window is in epoch
milliseconds — the usage names seconds as the mistake that silently backfills 1970. Bars land
under kind=bar/venue={venue}/symbol=SYMBOL/interval=INTERVAL, re-running the same window writes
0 rows, and a still-forming final candle is dropped. The crates/vike-backfill/src/lib.rs header
gives the key's shape: {venue}:{symbol}:{interval}:{start}-{end}. There is no resample step —
klines are already bars.
Per venue, from each bin's own header:
- Binance (
crates/vike-backfill/src/bin/binance_backfill.rs) pages the public REST endpoint at 1000 rows per request. It is the one bin of the family whose persisted pace actually steers, because Binance is the only venue of the five that publishes aREQUEST_WEIGHTbudget for the pager to discover; the record is keyed(binance, spot|perp)because the two hosts publish different budgets (6000 vs 2400 weight per minute) and price/klinesdifferently (weight 2 vs 5). - Bybit (
bybit_backfill.rs) pages 1000 rows per request, newest-first and reversed by the fetcher.crates/vike-backfill/src/bybit.rswarns that the endpoint is end-anchored — it ignoresstartonce the window exceeds the cap and answers the newest 1000 rows withretCode: 0— so the bridge pages backward and a window wider than 1000 intervals is normal here, never silently clipped. - OKX (
okx_backfill.rs) pages thehistory-candlesendpoint backward through its 100-row cap via theaftercursor. Its per-page cost was measured on prod2 on 2026-08-04 at 476–486 ms, against a 200 ms delay nobody had ever checked. - Aster (
aster_backfill.rs) reads keyless public mainnet REST; a symbol carrying the.Psuffix (BTCUSDT.P) fetches the USDⓈ-M perpetual and is stored under that suffixed key, a bare symbol fetches spot.crates/vike-backfill/src/aster.rssays why mainnet is not a risk decision here: klines are a keyless public read, so the standing rule to exclude Aster from validation runs — which is about authenticated account calls — does not reach this path. - Deribit (
deribit_backfill.rs) pages the venue's public, keyless chart-data JSON-RPC endpoint.SYMBOLis a Deribit instrument name passed through verbatim (BTC-PERPETUAL, a dated future) — there is no.Psuffix on this venue, because the name is already unambiguous. The endpoint is end-anchored like Bybit's and is paged backward.
A 24-month 1m pull on Deribit is a lot of requests and a lot of log
deribit_backfill.rs's header: set VIKE_LOG_FILE_LEVEL=warn for it — the file layer is trace
by default and does not listen to RUST_LOG. The rule for every long run is on
log volume.
The pace book
crates/vike-backfill/src/pace_book.rs explains what the klines bins persist and why: every
backfill measures its own pace — the wall clock of a request, the weight one request costs — and
used to discard it at exit, so run N+1 opened on a pessimistic constant (on Binance spot, where a
page costs weight 2, the pacer's seed of 5 paced the first pages 2.5× slower than the venue
permits). The record is written down and the next run reads it. run_klines_backfill_cli resolves
the file through crates/vike-backfill/src/cli.rs's pace_book_path: $VIKE_PACE_BOOK, then
<project>/settings/state/pace.json, then <ROOT_DIR>/pace.json for a binary with no project
above its working directory.
The file is a cache and follows a never-brick law: a missing, unreadable or unparseable file is
"no record", deleting it costs one run's opening pages and nothing else. And a record does not mean
a faster backfill. run_klines_backfill_cli's doc is blunt: Binance's genuinely re-paces the first
page, while Bybit, OKX and Deribit's pagers answer their hardcoded PAGE_DELAY whatever is stored
— for them the record buys an ETA line from page zero and an operator-readable per-page cost.
Aster is the one bin that persists nothing at all, because its host is environment-resolved and the
bridge exposes no paced fetch to plumb a sample through (aster_backfill.rs).
Dukascopy ticks
crates/vike-backfill/src/bin/dukascopy_backfill.rs takes a different argument shape:
dukascopy_backfill <ROOT_DIR> <SYMBOL> <START_MS> <END_MS> [INTERVAL]It fetches tick history for a symbol such as EURUSD from Dukascopy's keyless .bi5 datafeed,
appends the quotes, then — if INTERVAL is given — resamples the stored quotes into OHLCV bars.
crates/vike-backfill/src/dukascopy.rs names the pipeline: fetch_ticks_range → tick_to_quote →
append_quotes → resample_quotes_to_bars, the last being the parity-tested
vike_model::consolidate_quotes. It is history-only: Dukascopy publishes with a T+1 lag. This was
the crate's first collector, and crates/vike-backfill/src/lib.rs's header still introduces it that
way — the first collector, keyless .bi5 tick history to QuoteTicks to the store, plus a
quote-to-bar resample.
Hyperliquid candles
crates/vike-backfill/src/bin/hyperliquid_backfill.rs pages the keyless candleSnapshot /info
endpoint on mainnet with named flags rather than positionals: --symbols is a comma list of
vikeSymbol=coin pairs (bare SYM means coin equals symbol — HL perps use the coin as the symbol,
BTC/HYPE), --interval is one of 1d, 1h, 5m, 1m, and --start/--end are each an
epoch-ms integer or a YYYY-MM-DD UTC date with --end defaulting to now. The fetcher pages
forward by advancing startTime past each page's last candle close
(crates/vike-backfill/src/hyperliquid.rs), and the one wrinkle is that the store symbol may
differ from the coin the fetch pages, so the commit key and append key on the symbol. Series land
as kind=bar/venue=hyperliquid, idempotent per window. The same module owns the realized-funding
backfill, which is on funding rates.
The klines trio backfill_{binance,bybit,okx}_klines is also what the desktop app's bulk Backfill
action and vike-datahub's backfill-on-demand call (lib.rs header) — see Backfill from the
GUI.
Data providers
Where backfilled history comes from — the one-shot collectors in vike-backfill, grouped by family, and the capability table that says which source can fill which kind for which venue.
Funding rates
Two collectors that look alike and write different things — the venue-wide market funding rate a strategy trades on, and one account's realized funding payments.