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"]