orderflow_backtest/tests/test_storage_integration.py

84 lines
2.6 KiB
Python

from pathlib import Path
from datetime import datetime, timezone
import sqlite3
import sys
# Ensure project root is on sys.path for direct module imports
sys.path.append(str(Path(__file__).resolve().parents[1]))
from storage import Storage
def _init_db(path: Path) -> None:
with sqlite3.connect(str(path)) as conn:
c = conn.cursor()
c.execute(
"""
CREATE TABLE IF NOT EXISTS book (
id INTEGER PRIMARY KEY,
bids TEXT NOT NULL,
asks TEXT NOT NULL,
timestamp INTEGER NOT NULL
)
"""
)
c.execute(
"""
CREATE TABLE IF NOT EXISTS trades (
id INTEGER PRIMARY KEY,
trade_id REAL NOT NULL,
price REAL NOT NULL,
size REAL NOT NULL,
side TEXT NOT NULL,
timestamp INTEGER NOT NULL
)
"""
)
conn.commit()
def test_storage_builds_snapshots_and_attaches_trades(tmp_path):
db_path = tmp_path / "test.db"
_init_db(db_path)
ts = 1_725_000_000
# Insert one valid book row and one invalid (empty asks) that should be ignored
bids = str([(100.0, 1.0, 0, 1), (99.5, 2.0, 0, 1)])
asks = str([(100.5, 1.5, 0, 1), (101.0, 1.0, 0, 1)])
invalid_asks = str([])
with sqlite3.connect(str(db_path)) as conn:
c = conn.cursor()
c.execute("INSERT INTO book (id, bids, asks, timestamp) VALUES (?, ?, ?, ?)", (1, bids, asks, ts))
c.execute("INSERT INTO book (id, bids, asks, timestamp) VALUES (?, ?, ?, ?)", (2, bids, invalid_asks, ts + 1))
# Insert trades for ts
c.execute(
"INSERT INTO trades (id, trade_id, price, size, side, timestamp) VALUES (?, ?, ?, ?, ?, ?)",
(1, 1.0, 100.25, 0.5, "buy", ts),
)
c.execute(
"INSERT INTO trades (id, trade_id, price, size, side, timestamp) VALUES (?, ?, ?, ?, ?, ?)",
(2, 2.0, 100.75, 0.75, "sell", ts),
)
conn.commit()
storage = Storage("BTC-USDT")
db_date = datetime.fromtimestamp(ts, tz=timezone.utc)
storage.build_booktick_from_db(db_path, db_date)
# Only one snapshot should be included (the valid one with non-empty asks)
assert len(storage.book.snapshots) == 1
snap = storage.book.snapshots[0]
assert snap.timestamp == ts
assert len(snap.bids) == 2
assert len(snap.asks) == 2
# Trades should be attached for the same timestamp
assert len(snap.trades) == 2
sides = sorted(t.side for t in snap.trades)
assert sides == ["buy", "sell"]