bybit is fxhnt's sole paper book (Task 7f hardcoded every PaperRepo read/write to it); the prod purge left every paper_* table bybit-only. Remove the now-constant `venue` column at the SCHEMA level so the paper book is single-venue by construction. - cockpit_models.py: drop `venue` from all 7 paper models; re-key the 5 composite-PK tables on their remaining columns; paper_nav_summary swaps its sole `venue` PK for a singleton surrogate `id` (=1); paper_trades drops the non-PK venue index+column. - paper_book_migration.py (new): Postgres-only, idempotent reverse migration invoked by PaperRepo.migrate(). Guarded on the live `venue` column so it is a pure no-op after the first run (heavy DDL on every cockpit startup would crashloop). Sole home of the column-drop DDL, keeping paper_repo free of any discriminator logic. - paper_repo.py: delete `_BYBIT_VENUE`/`_VENUE_TABLES`; strip every venue kwarg/predicate; PK lookups use (1) / (key). `grep -n venue paper_repo.py` → 0. - test_no_binance_data.py: 7f venue-default guard → schema guard (no paper model has a `venue` column). Full suite green: `uv run pytest -q` → 1853 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
124 lines
5.6 KiB
Python
124 lines
5.6 KiB
Python
"""Guard (Phase 0b Task 7e): Binance is LITERALLY 0% in src/fxhnt — CODE AND COMMENTS. SUBSTRING guard
|
|
(mirrors test_no_alpaca.py): `grep -rin binance src/fxhnt` must return 0 hits.
|
|
|
|
This SUPERSEDES the narrower Task 7b/7c guard that used to live here (which explicitly scoped itself to
|
|
CODE, not comments, and intentionally kept historical/documentary Binance mentions). Task 7e closes that
|
|
gap: it retires the crypto_pit Binance fetch/panel/ingest/research surface (`crypto_fetch`,
|
|
`crypto_pit_panel`, `ts_trend_strategy`, `silver_crypto`, `silver_ingest_helpers`, the `crypto_pit_dir`
|
|
setting, the `backtest-funding` CLI, the `--crypto`/`--source crypto` legs of `fetch`/`warehouse-ingest`)
|
|
and rewords every remaining Binance-naming comment. No knowledge is lost — the mirage/venue-history
|
|
findings are preserved (just not attributed by name) and are banked in memory under
|
|
`project_fxhnt_measured_cost_mirage_and_postgres`.
|
|
|
|
The module/asset/CLI existence checks below are a SECOND, code-level guard against reintroduction —
|
|
complementary to the substring grep, not a replacement for it."""
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import pathlib
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
|
|
def test_no_binance_symbols_in_src() -> None:
|
|
root = pathlib.Path(__file__).parents[2] / "src" / "fxhnt"
|
|
hits = subprocess.run(["grep", "-rin", "binance", str(root)], capture_output=True, text=True).stdout
|
|
assert not hits.strip(), f"residual Binance references:\n{hits}"
|
|
|
|
|
|
_DELETED_MODULES = [
|
|
"fxhnt.adapters.data.binance_funding",
|
|
"fxhnt.adapters.data.binance_xsfunding_live",
|
|
"fxhnt.adapters.exchange.binance_funding_history",
|
|
"fxhnt.adapters.exchange.ccxt_live_price",
|
|
"fxhnt.adapters.data.unlock_calendar_live",
|
|
"fxhnt.application.funding_dispersion_eval",
|
|
"fxhnt.application.bybit_xvenue_funding_eval",
|
|
"fxhnt.application.funding_ingest",
|
|
"fxhnt.application.spot_ingest",
|
|
"fxhnt.application.basis_panel_builder",
|
|
"fxhnt.domain.strategies.funding_carry",
|
|
# Task 7c — the Binance worst_basis Parquet side-store + the dormant vendored VRP PoC.
|
|
"fxhnt.adapters.data.binance_vision_klines",
|
|
"fxhnt.adapters.data.binance_spot_history",
|
|
"fxhnt.application.worst_basis_ingest",
|
|
"fxhnt.adapters.persistence.worst_basis_store",
|
|
"fxhnt.vendor.surfer.surfer_poc",
|
|
# Task 7e — the crypto_pit Binance fetch/panel/ingest/research surface.
|
|
"fxhnt.adapters.data.crypto_fetch",
|
|
"fxhnt.adapters.data.crypto_pit_panel",
|
|
"fxhnt.application.ts_trend_strategy",
|
|
"fxhnt.adapters.warehouse.silver_crypto",
|
|
"fxhnt.application.silver_ingest_helpers",
|
|
]
|
|
|
|
# Binance DATA ingest assets (fed only the retired `features` warehouse funding/spot columns).
|
|
_DELETED_INGEST_ASSETS = ("crypto_bars", "crypto_funding", "crypto_spot")
|
|
|
|
# Binance-specific CLIs (ingest / cross-venue-dispersion / manual delta-neutral-order bridge / crypto_pit
|
|
# research).
|
|
_DELETED_CLIS = {
|
|
"crypto-funding-ingest", "crypto-spot-ingest", "build-basis-panel", "xsfunding-orders",
|
|
"funding-dispersion-test", "bybit-xvenue-funding-eval",
|
|
"ingest-worst-basis", # Task 7c — the Binance worst_basis Parquet side-store CLI.
|
|
"backtest-funding", # Task 7e — its only data source was the crypto_pit panel.
|
|
}
|
|
|
|
# CLIs that MUST survive (Bybit/IBKR paths, Bybit-only measured cost, or the futures-only fetch/ingest).
|
|
_KEPT_CLIS = {
|
|
"bybit-carry-revalidate", "bybit-edges-eval", "cross-venue-carry-eval",
|
|
"compare-measured-precompute", "bybit-ingest-worst-basis", "fetch", "warehouse-ingest",
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize("mod", _DELETED_MODULES)
|
|
def test_binance_module_gone(mod: str) -> None:
|
|
with pytest.raises(ModuleNotFoundError):
|
|
importlib.import_module(mod)
|
|
|
|
|
|
def test_binance_ingest_assets_gone() -> None:
|
|
from fxhnt.adapters.orchestration import assets
|
|
for a in _DELETED_INGEST_ASSETS:
|
|
assert not hasattr(assets, a), f"{a} Binance ingest asset still present"
|
|
|
|
|
|
def test_binance_clis_gone() -> None:
|
|
from fxhnt.cli import app
|
|
names = {c.name or (c.callback.__name__ if c.callback else None) for c in app.registered_commands}
|
|
assert not (_DELETED_CLIS & names), f"binance CLIs still registered: {_DELETED_CLIS & names}"
|
|
|
|
|
|
def test_bybit_ibkr_and_futures_clis_survive() -> None:
|
|
"""No over-deletion: the decoupled Bybit/IBKR commands + the futures-only fetch/warehouse-ingest legs
|
|
are still wired."""
|
|
from fxhnt.cli import app
|
|
names = {c.name or (c.callback.__name__ if c.callback else None) for c in app.registered_commands}
|
|
missing = _KEPT_CLIS - names
|
|
assert not missing, f"a KEPT command was wrongly removed: {missing}"
|
|
|
|
|
|
def test_paper_models_have_no_venue_column() -> None:
|
|
"""Guard (Phase 0c): the paper book is single-venue at the SCHEMA level — bybit is fxhnt's sole paper book,
|
|
so the vestigial `venue` discriminator column has been dropped from every paper_* table (Task 7f had already
|
|
hardcoded every `PaperRepo` read/write to bybit; this removes the now-constant column). The invariant is no
|
|
longer 'writes use one hardcoded venue value' but 'the models carry NO venue column at all'."""
|
|
from fxhnt.adapters.persistence.cockpit_models import (
|
|
PaperBookStateRow,
|
|
PaperNavRow,
|
|
PaperNavSummaryRow,
|
|
PaperPositionRow,
|
|
PaperShadowPositionRow,
|
|
PaperSleeveRetRow,
|
|
PaperTradeRow,
|
|
)
|
|
|
|
paper_models = (
|
|
PaperPositionRow, PaperTradeRow, PaperNavRow, PaperNavSummaryRow,
|
|
PaperBookStateRow, PaperSleeveRetRow, PaperShadowPositionRow,
|
|
)
|
|
for model in paper_models:
|
|
cols = {c.name for c in model.__table__.columns}
|
|
assert "venue" not in cols, f"{model.__name__} still has a venue column: {sorted(cols)}"
|