# Bybit ingestion + carry re-validation on the live venue — Design (A14)

**Date:** 2026-06-23
**Status:** Design (for sign-off)
**Repo:** fxhnt

## Why
Live execution will be **Bybit EU (MiCA)**, but every edge is backtested on **Binance** data. Before any live
capital — especially carry, which is venue-sensitive (funding + universe differ) — we must re-validate on the
*actual* venue's data. This builds the Bybit data stack and re-runs the edges on it.

## Feasibility (probed from the cluster — strong)
- **Universe**: `GET /v5/market/instruments-info?category=linear` → **590 active USDT perps** (vs Binance ~376).
- **Funding**: `GET /v5/market/funding/history` is **SURVIVORSHIP-FREE** — delisted `LUNAUSDT` returns rows
  (retCode 0); paginates back to **2022-01+** via `endTime`; 8h funding (~66 days/200-row page). This is the
  carry signal and it's fully available incl. delisted (better than Binance REST, which purges delisted).
- **Klines**: `GET /v5/market/kline?interval=D` → daily, ~2.7yr/1000-row page, paginates further via `start`.
- **Ever-listed universe**: `public.bybit.com/trading/` enumerates per-symbol dumps (active + delisted) for the
  survivorship-free symbol list (the funding API then retains each one's history).
- **Reachability**: api.bybit.com + public.bybit.com both reachable from the cluster (443 egress). Market data
  is public/global (no auth, no EU geo-restriction — the MiCA restriction is on *trading*, not data).

## Scope (phased — build A+B+C now; D later)
- **A. Bybit funding adapter** (`BybitFundingHistory`): paginate funding/history (survivorship-free) for the
  universe (active 590 + delisted from public.bybit.com) back to ~2022 → a Bybit funding panel.
- **B. Bybit klines adapter** (`BybitKlines`): perp + spot daily close (for basis + sleeve returns) → Bybit
  price panels. (Carry's return = funding + basis, so we need both legs on Bybit too.)
- **C. Carry (+ directional) re-validation on Bybit**: run `XsFundingReplay` + the carry accounting
  (funding + basis, fees=5.5bp Bybit taker) on the Bybit panels → carry Sharpe/DD **on the venue we'll trade**.
  Compare to the Binance numbers (carry ~1.33 intraday-honest). This is the GATE before live carry.
- **D. (LATER, not now) Live execution**: Bybit EU order placement, the **MiCA-restricted tradeable subset**
  (fewer coins / leverage caps), credentials. Separate workstream.

## Architecture
- New adapters in `src/fxhnt/adapters/data/`: `bybit_funding.py`, `bybit_klines.py`, `bybit_universe.py`
  (mirror the Binance adapters' shapes so the existing carry pipeline / `XsFundingReplay` reuse them).
- **Storage = Bybit-namespaced, Parquet side-store** (NOT the single-writer warehouse DuckDB — the lesson from
  the worst_basis OOM/contention): `bybit_funding.parquet`, `bybit_perp_close.parquet`, `bybit_spot_close.parquet`
  under the surfer data dir. A loader exposes `{symbol:{epoch_day:value}}` panels.
- **Universe**: active (instruments-info) ∪ delisted (public.bybit.com/trading enumeration), with the same
  rename/redenomination care as Binance (1000X tokens, delisted intervals).
- **Re-validation**: reuse `XsFundingReplay` + `carry_return_by_symbol` on the Bybit panels (same code, Bybit
  data) → a Bybit carry curve; surface it as a track in the sim (`cost_bps`=5.5).
- **Memory/infra**: paginated fetch is light (funding <100MB; daily klines small) — run as a resumable CLI /
  k8s job with adequate memory (NOT the 2Gi dagster daemon; the 1m-ingest OOM lesson). Funding+daily klines are
  far lighter than 1m, so this is tractable.

## MiCA / Bybit EU (explicit)
Ingestion uses the **global** market data (full 590 universe) — correct for *backtesting* the edge. Live
execution (Phase D) must constrain to the **Bybit EU tradeable subset** (MiCA: fewer coins, leverage caps) —
so the live carry universe will be SMALLER than the backtest universe. Flag: the Bybit-data re-validation is an
upper bound; the live EU-tradeable subset is the real constraint, applied at execution.

## Tests / acceptance
- Adapters: paginate funding + klines correctly (mock the HTTP; no network in unit tests); survivorship
  (delisted symbol returns history); rename handling.
- Parquet side-store round-trip.
- Carry re-validation runs on the Bybit panels and produces a carry curve (Sharpe/DD) comparable to Binance.
- Full suite green; no `*.dbn` staged; Bybit cache/parquet gitignored.

## Out of scope (now)
- Live order execution / credentials / the MiCA tradeable-subset enforcement (Phase D).
- 1m intraday worst_basis on Bybit (daily basis first, mirror the Binance staging).
