vike
ConceptsData

perp_metrics

The perp_metrics store kind: its columns, partitioning, what venue and symbol mean for it, and the producers that write it.

perp_metrics is one of the shapes the historical store holds. A stored series lives under a kind= path segment, and that segment is the layout contract its producers and its consumers have to agree on: the columns, how the leaf is partitioned, and what venue and symbol mean for this particular kind. All of it is below, rendered from the same table the runtime dispatches on.

One decoded row becomes a crate::perp_metrics_log::PerpMetricRow. The codec that owns the schema is PerpMetricsCodec; the store writes through append_perp_metrics and reads through scan_perp_metrics, and parts carry the Parquet metadata key vike.schema.perp_metrics.

Identity

venue = the perp venue; symbol = the SAME store symbol the market funding-rate series uses for that perp, so the two align by ts without a translation step — crates/vike-backfill/src/funding_rate.rs's backfill_funding_rate writes both from one response and passes its symbol argument to each

This is the field most often assumed and most often wrong, which is why it is stated per kind rather than once for the store.

Columns

Every Arrow column today's writer emits, in schema order, with the codec flavor that picks its Arrow type and nullability.

ColumnFlavorNote
tsi64—
premiumf64—
open_interestf64_addmay be ABSENT ENTIRELY from a part sealed before the column was added

Layout

PropertyValue
Partitioningsymbol
Grouped formno — one series per part
In the cross-kind tick reportno

Traps

⚠ THE NARROWEST KIND IN THE STORE — one timestamp, one number — and both of the numbers a reader expects beside it are missing on purpose. ⚠ The market funding RATE is NOT here: it rides vike_model::Bar::funding in the bar row above, under the reserved interval=funding label, and the premium and the rate arrive in the SAME Hyperliquid fundingHistory row at the same ts. Storing the rate here too would give one number two homes that can disagree, which is a worse version of the name collision the funding row already pins. ⚠ open_interest JOINED as the additive column this note always promised: the revisit condition was A SOURCE, and one arrived — data.vike.io's /v1/hyperliquid/assets/hourly panel serves hourly OI history from its own HL node. The paragraph below KEEPS its facts because they still hold for the VENUE'S OWN surface — which is why the column is nullable and only the panel collector fills it. Hyperliquid publishes open interest only as a CURRENT snapshot — the POST /info \{"type":"metaAndAssetCtxs"} body and the activeAssetCtx websocket channel — and its /info surface has no historical open-interest verb, so no backfill can reconstruct a past value at any granularity. BINANCE is the opposite case and the note exists so nobody re-derives it: its keyless REST GET /futures/data/openInterestHist holds only ~30 rolling days (a startTime 31 days back is refused with code -1130, measured), but its public archive at data.binance.vision publishes a metrics dataset carrying sum_open_interest/sum_open_interest_value at FIVE-MINUTE cadence back to 2020-09-01 for BTCUSDT — free, keyless, and read by nothing in this workspace today. That is a different VENUE's open interest, so it is not a drop-in for a Hyperliquid study; it is a live option rather than a dead end. This row is shaped so either could later join as a COLUMN rather than as a second kind: an added open_interest takes an _add flavor, whose absent-column tolerance is what lets it read the parts written today. ⚠ Identity is the PATH only — no column repeats venue or symbol, unlike cohort and chain, because this row carries no further dimension that has to be stored anyway (the funding row's shape, not theirs).

Pinned rather than fixed: the contradiction is recorded with both sides named, so a reader meets it here instead of in production.

Known producers

Idempotency in this store is batch-level and keyed on a commit-key string, never on per-row value dedup. Two producers that collide on one template silently no-op each other's appends, and a producer that changes its template re-admits history it already wrote — both invisible unless the shapes are written side by side.

ProducerCommit-key template
crates/vike-backfill/src/funding_rate.rsperp_metrics:{venue}:{symbol}:{start_ms}-{end_ms}
crates/vike-backfill/src/vikedata/panel.rsperp_panel:{exchange}:{asset}:{start_secs}-{end_secs}

⚠ That list is observed, not exhaustive, and no gate can make it so: a commit key is an ordinary string argument, so proving the list complete would mean following every call in the workspace. What is gated per listed entry is that the producer exists and spells the template verbatim. Read it as "these producers write this kind", never as "only these do".

Where this comes from

vike_data::store_kind::STORE_KINDS, exported as rosters.json at every release. The store's own gate derives the live kind set from the code — the series directory literals, the compaction dispatch and the write verbs — and fails until a new kind has a row, so this page cannot describe a shape the store does not write.

On this page