feat(combined-book): CombinedBookSource port + RawFileSource (existing path)
This commit is contained in:
34
src/fxhnt/application/combined_book_source.py
Normal file
34
src/fxhnt/application/combined_book_source.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""Data source for the combined book — the A→B seam. The book reads its crypto panel + futures series
|
||||
through this port; RawFileSource is the existing raw-file path, WarehouseSource (next task) reads the SSOT."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Protocol
|
||||
|
||||
import numpy as np
|
||||
|
||||
from fxhnt.adapters.data.dbn_local import LocalDbnLoader
|
||||
from fxhnt.application.crypto_momentum_research import load_crypto_panel
|
||||
from fxhnt.domain.models import PriceSeries
|
||||
|
||||
|
||||
class CombinedBookSource(Protocol):
|
||||
def crypto_panel(self) -> tuple[list[int], list[str], np.ndarray, np.ndarray]:
|
||||
"""(days, syms, close[d×s], ret[d×s]) — same shape as load_crypto_panel."""
|
||||
...
|
||||
|
||||
def futures_series(self, root: str) -> PriceSeries:
|
||||
"""Continuous front-month PriceSeries for a futures root."""
|
||||
...
|
||||
|
||||
|
||||
class RawFileSource:
|
||||
def __init__(self, data_dir: str, crypto_subdir: str = "crypto_pit") -> None:
|
||||
self._dir = data_dir
|
||||
self._sub = crypto_subdir
|
||||
self._loader = LocalDbnLoader()
|
||||
|
||||
def crypto_panel(self) -> tuple[list[int], list[str], np.ndarray, np.ndarray]:
|
||||
return load_crypto_panel(f"{self._dir}/{self._sub}")
|
||||
|
||||
def futures_series(self, root: str) -> PriceSeries:
|
||||
return self._loader.load(f"{self._dir}/{root}.dbn", root)
|
||||
14
tests/unit/test_combined_book_source.py
Normal file
14
tests/unit/test_combined_book_source.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""CombinedBookSource: RawFileSource reproduces load_crypto_panel; WarehouseSource (next task) matches it."""
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def test_raw_file_source_crypto_panel_matches_loader(tmp_path) -> None:
|
||||
from fxhnt.application.combined_book_source import RawFileSource
|
||||
cp = tmp_path / "crypto_pit"; cp.mkdir()
|
||||
np.savez(cp / "BTCUSDT.npz", day=np.array([19000, 19001]), close=np.array([100.0, 110.0]))
|
||||
np.savez(cp / "ETHUSDT.npz", day=np.array([19001]), close=np.array([50.0]))
|
||||
days, syms, close, ret = RawFileSource(str(tmp_path)).crypto_panel()
|
||||
assert days == [19000, 19001] and syms == ["BTCUSDT", "ETHUSDT"]
|
||||
assert close[1, 0] == 110.0 and abs(ret[1, 0] - 0.10) < 1e-12
|
||||
Reference in New Issue
Block a user