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