#!/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()