better cob integration

This commit is contained in:
Dobromir Popov
2025-06-27 02:38:05 +03:00
parent 97ea27ea84
commit d791ab8b14
4 changed files with 678 additions and 450 deletions

View File

@ -421,29 +421,17 @@ class CleanTradingDashboard:
[Input('interval-component', 'n_intervals')]
)
def update_cob_data(n):
"""Update COB data displays with price buckets"""
"""Update COB data displays with real order book ladders"""
try:
# ETH/USDT COB with $1 price buckets
eth_cob = self._get_cob_snapshot('ETH/USDT')
eth_buckets = self.get_cob_price_buckets('ETH/USDT')
eth_memory_stats = self.get_cob_memory_stats('ETH/USDT')
eth_components = self.component_manager.format_cob_data_with_buckets(
eth_cob, 'ETH/USDT', eth_buckets, eth_memory_stats, bucket_size=1.0
)
# BTC/USDT COB with $10 price buckets - Reference data for ETH models
btc_cob = self._get_cob_snapshot('BTC/USDT')
btc_buckets = self.get_cob_price_buckets('BTC/USDT')
btc_memory_stats = self.get_cob_memory_stats('BTC/USDT')
btc_components = self.component_manager.format_cob_data_with_buckets(
btc_cob, 'BTC/USDT', btc_buckets, btc_memory_stats, bucket_size=10.0
)
# Get real COB data from the working integration
eth_components = self._create_cob_ladder_display('ETH/USDT')
btc_components = self._create_cob_ladder_display('BTC/USDT')
return eth_components, btc_components
except Exception as e:
logger.error(f"Error updating COB data: {e}")
error_msg = html.P(f"Error: {str(e)}", className="text-danger")
error_msg = html.P(f"COB Error: {str(e)}", className="text-danger small")
return error_msg, error_msg
@self.app.callback(
@ -2947,47 +2935,243 @@ class CleanTradingDashboard:
self.training_system = None
def _initialize_cob_integration(self):
"""Initialize COB integration with high-frequency data handling"""
"""Initialize COB integration with high-frequency data handling - LAZY INITIALIZATION"""
try:
if not COB_INTEGRATION_AVAILABLE:
logger.warning("COB integration not available - skipping")
return
logger.info("Setting up COB integration for lazy initialization (will start when dashboard runs)")
# Initialize COB integration with dashboard callback
self.cob_integration = COBIntegration(
data_provider=self.data_provider,
symbols=['ETH/USDT', 'BTC/USDT']
)
# Don't initialize COB here - just set up for lazy initialization
self.cob_integration = None
self.cob_integration_started = False
self.latest_cob_data = {}
self.cob_update_timestamps = {}
# Register dashboard callback for COB updates
self.cob_integration.add_dashboard_callback(self._on_high_frequency_cob_update)
# Register CNN callback for COB features (for next price prediction)
self.cob_integration.add_cnn_callback(self._on_cob_cnn_features)
# Register DQN callback for COB state features (for RL training)
self.cob_integration.add_dqn_callback(self._on_cob_dqn_features)
# Start COB integration in background thread
import threading
def start_cob():
import asyncio
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(self.cob_integration.start())
except Exception as e:
logger.error(f"Error starting COB integration: {e}")
finally:
loop.close()
cob_thread = threading.Thread(target=start_cob, daemon=True)
cob_thread.start()
logger.info("High-frequency COB integration initialized (50-100 Hz data handling)")
logger.info("COB integration setup complete - will initialize when event loop is available")
except Exception as e:
logger.error(f"Error initializing COB integration: {e}")
logger.error(f"Error setting up COB integration: {e}")
self.cob_integration = None
def _start_cob_integration_lazy(self):
"""Start COB integration when dashboard is running (lazy initialization)"""
if self.cob_integration_started:
return
try:
logger.info("Starting COB integration with lazy initialization pattern")
# Import COB integration directly (same as working dashboard)
from core.cob_integration import COBIntegration
# Start COB integration in a background thread with proper event loop
def start_cob_worker():
"""Start COB integration using the exact same pattern as working dashboard"""
try:
# Create new event loop for COB (same as working dashboard)
import asyncio
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
async def cob_main():
"""Main COB loop (same pattern as working dashboard)"""
try:
# Initialize COB integration with our symbols (same pattern as working dashboard)
self.cob_integration = COBIntegration(symbols=['ETH/USDT', 'BTC/USDT'])
# Register callback to receive real-time COB data (same as working dashboard)
self.cob_integration.add_dashboard_callback(self._on_cob_update)
# Start COB data streaming as background task (same as working dashboard)
await self.cob_integration.start()
logger.info("COB integration started successfully with lazy initialization")
logger.info("High-frequency COB data streaming active")
# Keep running (same as working dashboard)
while True:
await asyncio.sleep(1)
except Exception as e:
logger.error(f"Error in COB main loop: {e}")
# Run the COB integration (same as working dashboard)
loop.run_until_complete(cob_main())
except Exception as e:
logger.error(f"Error in COB worker thread: {e}")
finally:
try:
loop.close()
except:
pass
# Start COB worker in background thread
import threading
self.cob_thread = threading.Thread(target=start_cob_worker, daemon=True)
self.cob_thread.start()
self.cob_integration_started = True
logger.info("COB integration lazy initialization completed")
except Exception as e:
logger.error(f"Error in lazy COB initialization: {e}")
self.cob_integration = None
def _on_cob_update(self, symbol: str, data: Dict):
"""Handle COB data updates (same callback pattern as working dashboard)"""
try:
# Store latest COB data
self.latest_cob_data[symbol] = data
self.cob_update_timestamps[symbol] = datetime.now()
# Provide data to orchestrator models
if hasattr(self.orchestrator, '_on_cob_dashboard_data'):
self.orchestrator._on_cob_dashboard_data(symbol, data)
# Provide data to enhanced training system
if hasattr(self, 'training_system') and self.training_system:
# Add COB snapshot to training system
if hasattr(self.training_system, 'real_time_data'):
cob_snapshot = {
'timestamp': time.time(),
'symbol': symbol,
'stats': data.get('stats', {}),
'levels': len(data.get('bids', [])) + len(data.get('asks', [])),
'imbalance': data.get('stats', {}).get('imbalance', 0),
'spread_bps': data.get('stats', {}).get('spread_bps', 0)
}
self.training_system.real_time_data['cob_snapshots'].append(cob_snapshot)
logger.debug(f"COB update processed: {symbol} - {len(data.get('bids', []))} bids, {len(data.get('asks', []))} asks")
except Exception as e:
logger.debug(f"Error processing COB update: {e}")
def get_cob_data(self, symbol: str) -> Optional[Dict]:
"""Get latest COB data for a symbol"""
try:
return self.latest_cob_data.get(symbol)
except Exception as e:
logger.debug(f"Error getting COB data: {e}")
return None
def get_cob_statistics(self, symbol: str) -> Optional[Dict]:
"""Get COB statistics for a symbol"""
try:
if symbol in self.latest_cob_data:
return self.latest_cob_data[symbol].get('stats', {})
return None
except Exception as e:
logger.debug(f"Error getting COB statistics: {e}")
return None
def _create_cob_ladder_display(self, symbol: str) -> List:
"""Create real COB ladder display showing order book"""
try:
# Get COB data from the working integration
cob_data = self.get_cob_data(symbol)
if not cob_data:
return [
html.Div([
html.H6(f"{symbol} - COB", className="text-muted mb-2"),
html.P("COB data not available", className="text-warning small"),
html.P("Initializing connections...", className="text-muted small")
])
]
components = []
# Header with symbol and status
components.append(html.Div([
html.H6(f"{symbol} - Order Book", className="text-info mb-2"),
html.Small(f"Last update: {datetime.now().strftime('%H:%M:%S')}", className="text-muted")
]))
# Get order book data
bids = cob_data.get('bids', [])
asks = cob_data.get('asks', [])
stats = cob_data.get('stats', {})
# Display key statistics
if stats:
spread = stats.get('spread_bps', 0)
imbalance = stats.get('imbalance', 0)
components.append(html.Div([
html.P([
html.Span("Spread: ", className="text-muted small"),
html.Span(f"{spread:.1f} bps", className="text-warning small fw-bold")
], className="mb-1"),
html.P([
html.Span("Imbalance: ", className="text-muted small"),
html.Span(f"{imbalance:.3f}", className="text-info small fw-bold")
], className="mb-2")
]))
# Order book ladder - Asks (top, descending)
if asks:
components.append(html.Div([
html.H6("ASKS", className="text-danger small mb-1"),
html.Div([
html.Div([
html.Span(f"${ask['price']:.2f}", className="text-danger small me-2"),
html.Span(f"{ask['size']:.4f}", className="text-muted small")
], className="d-flex justify-content-between mb-1")
for ask in asks[:5] # Top 5 asks
], className="border-start border-danger ps-2 mb-2")
]))
# Current price (mid)
if bids and asks:
mid_price = (bids[0]['price'] + asks[0]['price']) / 2
components.append(html.Div([
html.Hr(className="my-1"),
html.P([
html.Strong(f"${mid_price:.2f}", className="text-primary")
], className="text-center mb-1"),
html.Hr(className="my-1")
]))
# Order book ladder - Bids (bottom, descending)
if bids:
components.append(html.Div([
html.H6("BIDS", className="text-success small mb-1"),
html.Div([
html.Div([
html.Span(f"${bid['price']:.2f}", className="text-success small me-2"),
html.Span(f"{bid['size']:.4f}", className="text-muted small")
], className="d-flex justify-content-between mb-1")
for bid in bids[:5] # Top 5 bids
], className="border-start border-success ps-2")
]))
# Summary stats
if bids and asks:
total_bid_volume = sum(bid['size'] * bid['price'] for bid in bids[:10])
total_ask_volume = sum(ask['size'] * ask['price'] for ask in asks[:10])
components.append(html.Div([
html.Hr(className="my-2"),
html.P([
html.Span("Bid Vol: ", className="text-muted small"),
html.Span(f"${total_bid_volume:,.0f}", className="text-success small")
], className="mb-1"),
html.P([
html.Span("Ask Vol: ", className="text-muted small"),
html.Span(f"${total_ask_volume:,.0f}", className="text-danger small")
], className="mb-1")
]))
return components
except Exception as e:
logger.error(f"Error creating COB ladder for {symbol}: {e}")
return [
html.Div([
html.H6(f"{symbol} - COB", className="text-muted mb-2"),
html.P(f"Error: {str(e)}", className="text-danger small")
])
]
def _initialize_unified_orchestrator_features(self):
"""Initialize unified orchestrator features including COB integration"""
@ -3068,6 +3252,10 @@ class CleanTradingDashboard:
logging.getLogger('werkzeug').setLevel(logging.ERROR)
logger.info(f"Starting Clean Trading Dashboard at http://{host}:{port}")
# Start lazy COB integration now that dashboard is running
self._start_cob_integration_lazy()
self.app.run(host=host, port=port, debug=debug, dev_tools_silence_routes_logging=True)
def stop(self):
@ -3479,47 +3667,7 @@ class CleanTradingDashboard:
except Exception as e:
logger.error(f"Error broadcasting COB update to UI: {e}")
def get_cob_price_buckets(self, symbol: str) -> List[Dict]:
"""Get price buckets for display in dashboard"""
try:
if symbol not in self.cob_price_buckets:
return []
buckets = self.cob_price_buckets[symbol]
# Sort buckets by price and return as list
sorted_buckets = []
for price_key in sorted(buckets.keys(), key=float):
bucket = buckets[price_key]
if bucket['total_volume'] > 0: # Only return buckets with volume
sorted_buckets.append(bucket)
return sorted_buckets
except Exception as e:
logger.error(f"Error getting COB price buckets for {symbol}: {e}")
return []
def get_cob_memory_stats(self, symbol: str) -> Dict:
"""Get COB memory statistics for debugging"""
try:
if symbol not in self.cob_memory:
return {}
memory = self.cob_memory[symbol]
buffer = self.cob_data_buffer[symbol]
return {
'memory_snapshots': len(memory),
'buffer_updates': len(buffer),
'total_updates': self.cob_update_count,
'last_update': self.last_cob_broadcast.get(symbol, 0),
'bucket_count': len(self.cob_price_buckets.get(symbol, {}))
}
except Exception as e:
logger.error(f"Error getting COB memory stats: {e}")
return {}
# REMOVED: Complex COB bucket methods - using simplified real order book display instead
def _on_cob_cnn_features(self, symbol: str, cob_features: Dict):
"""Handle COB features for CNN models (next price prediction)"""