diff --git a/src/fxhnt/application/combined_book_factory.py b/src/fxhnt/application/combined_book_factory.py new file mode 100644 index 0000000..ab0bf82 --- /dev/null +++ b/src/fxhnt/application/combined_book_factory.py @@ -0,0 +1,12 @@ +"""Composition helper: build the CombinedBookSource the settings select (the reversible cutover seam).""" +from __future__ import annotations + +from fxhnt.application.combined_book_source import CombinedBookSource, RawFileSource, WarehouseSource +from fxhnt.config import Settings + + +def make_combined_book_source(settings: Settings, data_dir: str) -> CombinedBookSource: + if settings.combined_book_data_source == "warehouse": + from fxhnt.adapters.warehouse.duckdb_feature_store import DuckDbFeatureStore + return WarehouseSource(DuckDbFeatureStore(settings.warehouse_path)) + return RawFileSource(data_dir) diff --git a/src/fxhnt/cli.py b/src/fxhnt/cli.py index e6b7142..f6b09fa 100644 --- a/src/fxhnt/cli.py +++ b/src/fxhnt/cli.py @@ -210,9 +210,11 @@ def forward_track( """Forward-validate the combined book: book today's realized return into the paper track. Run daily on a cron alongside the data fetch — the forward NAV/Sharpe is the only ground truth before capital.""" from fxhnt.application.combined_book import CombinedBook + from fxhnt.application.combined_book_factory import make_combined_book_source from fxhnt.application.forward_tracker import CombinedBookForwardTracker - book = CombinedBook(data_dir, _FUTURES_UNIVERSE) + book = CombinedBook(data_dir, _FUTURES_UNIVERSE, + source=make_combined_book_source(get_settings(), data_dir)) st = CombinedBookForwardTracker(book, state).step() typer.echo(f"forward track since {st.inception} (last {st.last_date}): {st.forward_days} forward days, " f"booked {st.booked_today} today") diff --git a/src/fxhnt/config.py b/src/fxhnt/config.py index 3bd59a2..d56e3fb 100644 --- a/src/fxhnt/config.py +++ b/src/fxhnt/config.py @@ -106,6 +106,9 @@ class Settings(BaseSettings): analytical_path: str = Field(default=str(_DATA_DIR / "analytical.duckdb")) # Warehouse (point-in-time SSOT: bars, funding, microstructure features) — DuckDB embedded file. warehouse_path: str = Field(default=str(_DATA_DIR / "warehouse.duckdb")) + # Combined-book data path: "raw" (crypto_pit/.dbn files) or "warehouse" (SSOT). Default raw for safety; + # the B0 Dagster deploy sets FXHNT_COMBINED_BOOK_DATA_SOURCE=warehouse. + combined_book_data_source: str = Field(default="raw") cost_bps_per_turnover: float = 10.0 # round-trip cost model (bps of traded notional) gauntlet: GauntletSettings = Field(default_factory=GauntletSettings) diff --git a/tests/unit/test_combined_book_factory.py b/tests/unit/test_combined_book_factory.py new file mode 100644 index 0000000..e90d9ac --- /dev/null +++ b/tests/unit/test_combined_book_factory.py @@ -0,0 +1,16 @@ +"""The factory picks WarehouseSource vs RawFileSource from settings (combined_book_data_source).""" +from __future__ import annotations + +from fxhnt.application.combined_book_factory import make_combined_book_source +from fxhnt.application.combined_book_source import RawFileSource, WarehouseSource +from fxhnt.config import Settings + + +def test_factory_raw_default(tmp_path) -> None: + s = Settings(combined_book_data_source="raw", warehouse_path=str(tmp_path / "wh.duckdb")) + assert isinstance(make_combined_book_source(s, "/data/surfer"), RawFileSource) + + +def test_factory_warehouse(tmp_path) -> None: + s = Settings(combined_book_data_source="warehouse", warehouse_path=str(tmp_path / "wh.duckdb")) + assert isinstance(make_combined_book_source(s, "/data/surfer"), WarehouseSource)