#!/usr/bin/env python3 """ Simple Windows-compatible COB Dashboard """ import asyncio import json import logging import time from datetime import datetime from http.server import HTTPServer, SimpleHTTPRequestHandler from socketserver import ThreadingMixIn import threading import webbrowser from urllib.parse import urlparse, parse_qs from core.multi_exchange_cob_provider import MultiExchangeCOBProvider logger = logging.getLogger(__name__) class COBHandler(SimpleHTTPRequestHandler): """HTTP handler for COB dashboard""" def __init__(self, *args, cob_provider=None, **kwargs): self.cob_provider = cob_provider super().__init__(*args, **kwargs) def do_GET(self): """Handle GET requests""" path = urlparse(self.path).path if path == '/': self.serve_dashboard() elif path.startswith('/api/cob/'): self.serve_cob_data() elif path == '/api/status': self.serve_status() else: super().do_GET() def serve_dashboard(self): """Serve the dashboard HTML""" html_content = """ COB Dashboard

Consolidated Order Book Dashboard

Hybrid WebSocket + REST API | Real-time + Deep Market Data
Loading...

Market Analysis

Chart data will be displayed here

Current implementation shows:
  • ✓ Real-time order book data (WebSocket)
  • ✓ Deep market data (REST API)
  • ✓ Session Volume Profile
  • ✓ Hybrid data merging

Order Book Ladder

Price
Size
Total
$--
Total Liquidity
--
Book Depth
--
Spread
-- bps
""" self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(html_content.encode()) def serve_cob_data(self): """Serve COB data""" try: # Extract symbol from path symbol = self.path.split('/')[-1].replace('%2F', '/') if not self.cob_provider: data = self.get_mock_data(symbol) else: data = self.get_real_data(symbol) self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(json.dumps(data).encode()) except Exception as e: logger.error(f"Error serving COB data: {e}") self.send_error(500, str(e)) def serve_status(self): """Serve status""" status = { 'server': 'running', 'timestamp': datetime.now().isoformat(), 'cob_provider': 'active' if self.cob_provider else 'mock' } self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(json.dumps(status).encode()) def get_real_data(self, symbol): """Get real data from COB provider""" try: cob_snapshot = self.cob_provider.get_consolidated_orderbook(symbol) if not cob_snapshot: return self.get_mock_data(symbol) # Convert to dashboard format bids = [] asks = [] for level in cob_snapshot.consolidated_bids[:20]: bids.append({ 'price': level.price, 'size': level.total_size, 'volume': level.total_volume_usd }) for level in cob_snapshot.consolidated_asks[:20]: asks.append({ 'price': level.price, 'size': level.total_size, 'volume': level.total_volume_usd }) return { 'symbol': symbol, 'bids': bids, 'asks': asks, 'stats': { 'mid_price': cob_snapshot.volume_weighted_mid, 'spread_bps': cob_snapshot.spread_bps, 'bid_liquidity': cob_snapshot.total_bid_liquidity, 'ask_liquidity': cob_snapshot.total_ask_liquidity, 'bid_levels': len(cob_snapshot.consolidated_bids), 'ask_levels': len(cob_snapshot.consolidated_asks), 'imbalance': cob_snapshot.liquidity_imbalance } } except Exception as e: logger.error(f"Error getting real data: {e}") return self.get_mock_data(symbol) def get_mock_data(self, symbol): """Get mock data for testing""" base_price = 50000 if 'BTC' in symbol else 3000 bids = [] asks = [] # Generate mock bids for i in range(20): price = base_price - (i * 10) size = 1.0 + (i * 0.1) bids.append({ 'price': price, 'size': size, 'volume': price * size }) # Generate mock asks for i in range(20): price = base_price + 10 + (i * 10) size = 1.0 + (i * 0.1) asks.append({ 'price': price, 'size': size, 'volume': price * size }) return { 'symbol': symbol, 'bids': bids, 'asks': asks, 'stats': { 'mid_price': base_price + 5, 'spread_bps': 2.5, 'bid_liquidity': sum(b['volume'] for b in bids), 'ask_liquidity': sum(a['volume'] for a in asks), 'bid_levels': len(bids), 'ask_levels': len(asks), 'imbalance': 0.1 } } class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """Thread pool server""" allow_reuse_address = True def start_cob_dashboard(): """Start the COB dashboard""" print("Starting Simple COB Dashboard...") # Initialize COB provider cob_provider = None try: print("Initializing COB provider...") cob_provider = MultiExchangeCOBProvider(symbols=['BTC/USDT', 'ETH/USDT']) # Start in background thread def run_provider(): asyncio.run(cob_provider.start_streaming()) provider_thread = threading.Thread(target=run_provider, daemon=True) provider_thread.start() time.sleep(2) # Give it time to connect print("COB provider started") except Exception as e: print(f"Warning: COB provider failed to start: {e}") print("Running in mock mode...") # Start HTTP server def handler(*args, **kwargs): COBHandler(*args, cob_provider=cob_provider, **kwargs) port = 8053 server = ThreadedHTTPServer(('localhost', port), handler) print(f"COB Dashboard running at http://localhost:{port}") print("Press Ctrl+C to stop") # Open browser try: webbrowser.open(f'http://localhost:{port}') except: pass try: server.serve_forever() except KeyboardInterrupt: print("\nStopping dashboard...") server.shutdown() if cob_provider: asyncio.run(cob_provider.stop_streaming()) if __name__ == "__main__": logging.basicConfig(level=logging.INFO) start_cob_dashboard()