# Faithful delta-neutral carry (spot ingest + basis) — Design (Phase 2F-A5)

**Date:** 2026-06-22
**Status:** Design (approved)
**Repo:** fxhnt
**Follows:** A4. Fixes the xsfunding carry artifact (Sharpe 30.9 / book +4320%) by modeling the REAL
delta-neutral return instead of funding-only.

## Motivation (root cause, verified)

A4 added xsfunding as a carry sleeve but modeled **funding-only** (`Σ w·funding`) because the warehouse had
no spot prices. Funding-only is near-deterministic (sort by persistent funding → collect it → ~zero daily
variance → **Sharpe 30.9**), and the ISV-adaptive overlay then crowds + levers it → **+4320% fantasy**. The
LIVE strategy books the true **delta-neutral** return `w·((spot_ret − perp_ret) + funding)` — the **basis
term `(spot_ret − perp_ret)` is the missing daily variance** (and it's capturable from price data). Restoring
it gives the carry its real risk, so the existing system sizes it correctly. User decisions: **"just build the
correct model"** (no interim 2-edge revert) and **"it should match the system"** (size via the existing
ISV-adaptive overlay — no bespoke carry allocation/floor/cap; the faithful return is the fix).

## Key facts (grounded)

- `BinanceSpotHistory.daily_close(symbol) -> {epoch_day: close}` already exists (used by stablecoin) — reuse
  for spot ingest.
- Live formula (`xsfunding_strategy.py:50`): `realized += w*((spot_ret−perp_ret)+tf_today)`; `realized -=
  turnover*cost/2`.
- Warehouse generic feature store: `feature='close'` = PERP closes (crypto_close_panel); add
  `feature='spot_close'` for spot. `feature='funding'` already ingested (A4).
- `sleeve_daily_carry(prev_positions, x_by_symbol) = Σ(qty·entry)·x / Σ|qty·entry|` — generic; A4 fed it raw
  funding. Feeding it the **delta-neutral return** (basis+funding) makes it faithful with NO change to the fn.

## Decisions

- **Ingest Binance SPOT daily closes** for the perp universe → `feature='spot_close'`; accessor
  `crypto_spot_panel()`. Mirror the funding ingest (CLI `crypto-spot-ingest` + Dagster asset, daily,
  single-writer). Reuse `BinanceSpotHistory` (per-symbol never-raise; coins with a perp but no spot are simply
  absent → funding-only fallback for those, exactly as the live strategy's documented fallback).
- **`delta_neutral_return_panel(spot_panel, perp_panel, funding_panel) -> {sym:{day: dn_ret}}`** where
  `dn_ret(d) = (spot[d]/spot[d-1] − 1) − (perp[d]/perp[d-1] − 1) + funding[d]`; **funding-only fallback**
  (`dn_ret = funding[d]`) for a coin/day lacking a spot pair or a prior spot/perp close. (= the live formula.)
- **Feed the carry sleeve the delta-neutral return, not raw funding:** the backfill (and snapshot) build
  `dn_by_date = {iso:{sym: dn_ret}}` from the three panels and pass it where `funding_by_date` was;
  `sleeve_daily_carry` is unchanged (`Σ w·dn_ret / gross`). The basis term injects real variance.
- **Sizing = the existing ISV-adaptive overlay, unchanged** ("match the system"). No vol-floor, no carry-only
  cap, no separate allocation. The faithful return is what makes the system's risk estimate (and thus its
  inverse-vol weight + vol-target leverage) correct.
- **Gross in the book (matches the system):** carry return is gross (basis+funding); costs are captured
  post-hoc on turnover (the existing cost analysis already costs xsfunding's trades) — consistent with the
  directional sleeves being gross. (The live strategy nets cost; the paper book's convention is gross + a
  post-hoc cost lens.)

## Components

1. **Spot ingest** — `application/spot_ingest.py` `ingest_spot(store, fetcher, symbols) -> int` (per symbol
   `daily_close` → `feature='spot_close'` rows `(day·86400, {'spot_close': c})` → `write_features_bulk`;
   per-symbol skip-on-empty, idempotent). `DuckDbFeatureStore.crypto_spot_panel(*, suffix='USDT')` (mirror
   `crypto_funding_panel`, `feature='spot_close'`). CLI `crypto-spot-ingest [--days]` + asset `crypto_spot`.
2. **`application/funding_panel.py` `delta_neutral_return_panel(spot, perp, funding) -> {sym:{day: dn_ret}}`**
   (basis + funding; funding-only fallback). Pure.
3. **`cli.py` `_paper_backfill_*` / `paper_backfill`**: build the spot panel + `dn_by_date` from
   `delta_neutral_return_panel`; pass `funding_by_date=dn_by_date` (the carry input) to `backfill_paper_book`.
   (xsfunding sleeve construction unchanged — still `XsFundingReplay(warehouse_funding_panel(...))` for its
   current_weights; only the RETURN input becomes delta-neutral.)
4. **`assets.py` snapshot assembly** (live path): same — provide the delta-neutral return per symbol for as_of
   so live==replay (carry-mode booking consistent).
5. **Verify**: deploy → ingest spot (+ funding already done) → re-backfill → check **xsfunding standalone
   Sharpe is now plausible (~1–3, not 30)** and the book is sane; per-sleeve + OOS H1/H2 + cost. Report
   honestly — **if the Sharpe is STILL absurd after the basis term, that proves the daily book can't represent
   carry → fall back to live-only** (the rigorous, pre-agreed exit).

## Risks / safety

- **Spot ingest external:** per-symbol never-raise (reuse `BinanceSpotHistory`'s retry/`_get`), idempotent
  writes; coins without spot → funding-only (documented, = live fallback). One-shot single-writer.
- **Causal:** `dn_ret(d)` uses `d` and `d-1` closes + `d` funding; carry booked = prior weights × `dn_ret(d)`.
  No look-ahead (same as A4's carry causality).
- **Read-only/additive:** new `spot_close` feature + a return-input change for the carry sleeve. A3f
  accounting, A3h overlay, directional sleeves, live xsfunding_nav untouched. Sizing system unchanged.
- **Honest limit:** even the full delta-neutral daily return omits deep tails (squeeze/liquidation/funding-
  flip/exchange failure). The replay is therefore indicative; the **live `xsfunding_nav` forward-track remains
  the ground truth** for the carry's real risk. The verify's success bar is "plausible, non-dominating," not
  "exactly 1.27".

## Out of scope

Netting cost into the carry return (kept gross to match the system; post-hoc cost lens); modeling deep
liquidation/counterparty tails; switching live xsfunding off its snapshot.

## Acceptance criteria

- `ingest_spot` + `crypto_spot_panel` (feature='spot_close'); idempotent; tested (fake fetcher + in-memory store).
- `delta_neutral_return_panel`: `dn = basis + funding`, funding-only fallback on missing spot/prior; tested.
- backfill/snapshot feed the carry sleeve the delta-neutral return (basis injects variance — a unit test
  shows a carry return that MOVES with basis, not the near-constant funding-only value).
- CLI `crypto-spot-ingest` + asset wired to the warehouse path/universe; full suite green.
- in-cluster: ingest spot → re-backfill → **xsfunding standalone Sharpe drops to a plausible band**; report
  the 3-edge curve + per-sleeve + OOS H1/H2 + cost HONESTLY (incl. the live-only fallback verdict if still
  absurd). `/paper` + `/paper/replay` render.
- read-only/additive; sizing system unchanged; no `*.dbn` staged.
