84 lines
2.6 KiB
Python
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"]
|
|
|