orderflow_backtest/run_with_existing_metrics.py

154 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""
Run interactive visualizer using PRE-CALCULATED metrics from the database.
No recalculation needed - just read and display!
"""
from pathlib import Path
from interactive_visualizer import InteractiveVisualizer
from models import Book, BookSnapshot, Trade
from parsers.orderbook_parser import OrderbookParser
import sqlite3
import logging
def load_book_snapshots_only(db_path: Path, limit: int = 10000):
"""Load book snapshots without recalculating metrics."""
book = Book()
parser = OrderbookParser()
print(f"📖 Reading book snapshots (limit: {limit})...")
# Read book data directly without triggering metric calculation
conn = sqlite3.connect(f'file:{db_path}?mode=ro', uri=True)
# Load trades first for efficiency
print(" 📈 Loading trades...")
trades_by_timestamp = {}
trade_cursor = conn.execute('SELECT id, trade_id, price, size, side, timestamp FROM trades ORDER BY timestamp')
for trade_row in trade_cursor:
timestamp = int(trade_row[5])
trade = Trade(
id=trade_row[0],
trade_id=float(trade_row[1]),
price=float(trade_row[2]),
size=float(trade_row[3]),
side=trade_row[4],
timestamp=timestamp
)
if timestamp not in trades_by_timestamp:
trades_by_timestamp[timestamp] = []
trades_by_timestamp[timestamp].append(trade)
# Get snapshots
cursor = conn.execute('''
SELECT id, instrument, bids, asks, timestamp
FROM book
ORDER BY timestamp
LIMIT ?
''', (limit,))
snapshot_count = 0
for row in cursor:
try:
row_id, instrument, bids_text, asks_text, timestamp = row
timestamp_int = int(timestamp)
# Create snapshot using the same logic as Storage._snapshot_from_row
snapshot = BookSnapshot(
id=row_id,
timestamp=timestamp_int,
bids={},
asks={},
trades=trades_by_timestamp.get(timestamp_int, []),
)
# Parse bids and asks using the parser
parser.parse_side(bids_text, snapshot.bids)
parser.parse_side(asks_text, snapshot.asks)
# Only add snapshots that have both bids and asks
if snapshot.bids and snapshot.asks:
book.add_snapshot(snapshot)
snapshot_count += 1
if snapshot_count % 1000 == 0:
print(f" 📊 Loaded {snapshot_count} snapshots...")
except Exception as e:
logging.warning(f"Error parsing snapshot {row[0]}: {e}")
continue
conn.close()
print(f"✅ Loaded {len(book.snapshots)} snapshots with trades")
return book
def main():
print("🚀 USING PRE-CALCULATED METRICS FROM DATABASE")
print("=" * 55)
# Database path
db_path = Path("../data/OKX/BTC-USDT-25-06-09.db")
if not db_path.exists():
print(f"❌ Database not found: {db_path}")
return
try:
# Load ONLY book snapshots (no metric recalculation)
book = load_book_snapshots_only(db_path, limit=5000) # Start with 5K snapshots
if not book.snapshots:
print("❌ No snapshots loaded")
return
print(f"✅ Book loaded: {len(book.snapshots)} snapshots")
print(f"✅ Time range: {book.first_timestamp} to {book.last_timestamp}")
# Create visualizer
viz = InteractiveVisualizer(
window_seconds=6*3600, # 6-hour bars
port=8050
)
# Set database path so it can load PRE-CALCULATED metrics
viz.set_db_path(db_path)
# Process book data (will load existing metrics automatically)
print("⚙️ Processing book data and loading existing metrics...")
viz.update_from_book(book)
print(f"✅ Generated {len(viz._ohlc_data)} OHLC bars")
print(f"✅ Loaded {len(viz._metrics_data)} pre-calculated metrics")
if viz._ohlc_data:
sample_bar = viz._ohlc_data[0]
print(f"✅ Sample OHLC: O={sample_bar[1]:.2f}, H={sample_bar[2]:.2f}, L={sample_bar[3]:.2f}, C={sample_bar[4]:.2f}")
print()
print("🌐 LAUNCHING INTERACTIVE DASHBOARD")
print("=" * 55)
print("🚀 Server starting at: http://127.0.0.1:8050")
print("📊 Features available:")
print(" ✅ OHLC candlestick chart")
print(" ✅ Volume bar chart")
print(" ✅ OBI line chart (from existing metrics)")
print(" ✅ CVD line chart (from existing metrics)")
print(" ✅ Synchronized zoom/pan")
print(" ✅ Professional dark theme")
print()
print("⏹️ Press Ctrl+C to stop the server")
print("=" * 55)
# Launch the dashboard
viz.show()
except KeyboardInterrupt:
print("\n⏹️ Server stopped by user")
except Exception as e:
print(f"❌ Error: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()