COB data and dash
This commit is contained in:
597
core/cob_integration.py
Normal file
597
core/cob_integration.py
Normal file
@ -0,0 +1,597 @@
|
||||
"""
|
||||
Consolidated Order Book (COB) Integration Module
|
||||
|
||||
This module integrates the Multi-Exchange COB Provider with the existing
|
||||
gogo2 trading system architecture, providing:
|
||||
|
||||
- Integration with existing DataProvider
|
||||
- CNN/DQN model data feeding
|
||||
- Dashboard data formatting
|
||||
- Trading signal generation based on COB analysis
|
||||
- Enhanced market microstructure analysis
|
||||
|
||||
Connects to the main trading dashboard and AI models.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Optional, Any, Callable
|
||||
from threading import Thread
|
||||
import json
|
||||
import math
|
||||
from collections import defaultdict
|
||||
|
||||
from .multi_exchange_cob_provider import MultiExchangeCOBProvider, COBSnapshot, ConsolidatedOrderBookLevel
|
||||
from .data_provider import DataProvider, MarketTick
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class COBIntegration:
|
||||
"""
|
||||
Integration layer for Multi-Exchange COB data with gogo2 trading system
|
||||
"""
|
||||
|
||||
def __init__(self, data_provider: DataProvider = None, symbols: List[str] = None):
|
||||
"""
|
||||
Initialize COB Integration
|
||||
|
||||
Args:
|
||||
data_provider: Existing DataProvider instance
|
||||
symbols: List of symbols to monitor
|
||||
"""
|
||||
self.data_provider = data_provider
|
||||
self.symbols = symbols or ['BTC/USDT', 'ETH/USDT']
|
||||
|
||||
# Initialize COB provider
|
||||
self.cob_provider = MultiExchangeCOBProvider(
|
||||
symbols=self.symbols,
|
||||
bucket_size_bps=1.0 # 1 basis point granularity
|
||||
)
|
||||
|
||||
# Register callbacks
|
||||
self.cob_provider.subscribe_to_cob_updates(self._on_cob_update)
|
||||
self.cob_provider.subscribe_to_bucket_updates(self._on_bucket_update)
|
||||
|
||||
# CNN/DQN integration
|
||||
self.cnn_callbacks: List[Callable] = []
|
||||
self.dqn_callbacks: List[Callable] = []
|
||||
self.dashboard_callbacks: List[Callable] = []
|
||||
|
||||
# COB analysis and signals
|
||||
self.cob_signals: Dict[str, List[Dict]] = {}
|
||||
self.liquidity_alerts: Dict[str, List[Dict]] = {}
|
||||
self.arbitrage_opportunities: Dict[str, List[Dict]] = {}
|
||||
|
||||
# Performance tracking
|
||||
self.cob_feature_cache: Dict[str, np.ndarray] = {}
|
||||
self.last_cob_features_update: Dict[str, datetime] = {}
|
||||
|
||||
# Initialize signal tracking
|
||||
for symbol in self.symbols:
|
||||
self.cob_signals[symbol] = []
|
||||
self.liquidity_alerts[symbol] = []
|
||||
self.arbitrage_opportunities[symbol] = []
|
||||
|
||||
logger.info("COB Integration initialized")
|
||||
logger.info(f"Symbols: {self.symbols}")
|
||||
|
||||
async def start(self):
|
||||
"""Start COB integration"""
|
||||
logger.info("Starting COB Integration")
|
||||
|
||||
# Start COB provider
|
||||
await self.cob_provider.start_streaming()
|
||||
|
||||
# Start analysis threads
|
||||
asyncio.create_task(self._continuous_cob_analysis())
|
||||
asyncio.create_task(self._continuous_signal_generation())
|
||||
|
||||
logger.info("COB Integration started successfully")
|
||||
|
||||
async def stop(self):
|
||||
"""Stop COB integration"""
|
||||
logger.info("Stopping COB Integration")
|
||||
await self.cob_provider.stop_streaming()
|
||||
logger.info("COB Integration stopped")
|
||||
|
||||
def add_cnn_callback(self, callback: Callable[[str, Dict], None]):
|
||||
"""Add CNN model callback for COB features"""
|
||||
self.cnn_callbacks.append(callback)
|
||||
logger.info(f"Added CNN callback: {len(self.cnn_callbacks)} total")
|
||||
|
||||
def add_dqn_callback(self, callback: Callable[[str, Dict], None]):
|
||||
"""Add DQN model callback for COB state features"""
|
||||
self.dqn_callbacks.append(callback)
|
||||
logger.info(f"Added DQN callback: {len(self.dqn_callbacks)} total")
|
||||
|
||||
def add_dashboard_callback(self, callback: Callable[[str, Dict], None]):
|
||||
"""Add dashboard callback for COB visualization data"""
|
||||
self.dashboard_callbacks.append(callback)
|
||||
logger.info(f"Added dashboard callback: {len(self.dashboard_callbacks)} total")
|
||||
|
||||
async def _on_cob_update(self, symbol: str, cob_snapshot: COBSnapshot):
|
||||
"""Handle COB update from provider"""
|
||||
try:
|
||||
# Generate CNN features
|
||||
cnn_features = self._generate_cnn_features(symbol, cob_snapshot)
|
||||
if cnn_features is not None:
|
||||
self.cob_feature_cache[symbol] = cnn_features
|
||||
self.last_cob_features_update[symbol] = datetime.now()
|
||||
|
||||
# Notify CNN callbacks
|
||||
for callback in self.cnn_callbacks:
|
||||
try:
|
||||
callback(symbol, {
|
||||
'features': cnn_features,
|
||||
'timestamp': cob_snapshot.timestamp,
|
||||
'type': 'cob_features'
|
||||
})
|
||||
except Exception as e:
|
||||
logger.warning(f"Error in CNN callback: {e}")
|
||||
|
||||
# Generate DQN state features
|
||||
dqn_features = self._generate_dqn_features(symbol, cob_snapshot)
|
||||
if dqn_features is not None:
|
||||
for callback in self.dqn_callbacks:
|
||||
try:
|
||||
callback(symbol, {
|
||||
'state': dqn_features,
|
||||
'timestamp': cob_snapshot.timestamp,
|
||||
'type': 'cob_state'
|
||||
})
|
||||
except Exception as e:
|
||||
logger.warning(f"Error in DQN callback: {e}")
|
||||
|
||||
# Generate dashboard data
|
||||
dashboard_data = self._generate_dashboard_data(symbol, cob_snapshot)
|
||||
for callback in self.dashboard_callbacks:
|
||||
try:
|
||||
if asyncio.iscoroutinefunction(callback):
|
||||
asyncio.create_task(callback(symbol, dashboard_data))
|
||||
else:
|
||||
callback(symbol, dashboard_data)
|
||||
except Exception as e:
|
||||
logger.warning(f"Error in dashboard callback: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing COB update for {symbol}: {e}")
|
||||
|
||||
async def _on_bucket_update(self, symbol: str, price_buckets: Dict):
|
||||
"""Handle price bucket update from provider"""
|
||||
try:
|
||||
# Analyze bucket distribution and generate alerts
|
||||
await self._analyze_bucket_distribution(symbol, price_buckets)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing bucket update for {symbol}: {e}")
|
||||
|
||||
def _generate_cnn_features(self, symbol: str, cob_snapshot: COBSnapshot) -> Optional[np.ndarray]:
|
||||
"""Generate CNN input features from COB data"""
|
||||
try:
|
||||
features = []
|
||||
|
||||
# Order book depth features (200 features: 20 levels x 5 features x 2 sides)
|
||||
max_levels = 20
|
||||
|
||||
# Process bids
|
||||
for i in range(max_levels):
|
||||
if i < len(cob_snapshot.consolidated_bids):
|
||||
level = cob_snapshot.consolidated_bids[i]
|
||||
price_offset = (level.price - cob_snapshot.volume_weighted_mid) / cob_snapshot.volume_weighted_mid
|
||||
features.extend([
|
||||
price_offset,
|
||||
level.total_volume_usd / 1000000, # Normalize to millions
|
||||
level.total_size / 1000, # Normalize to thousands
|
||||
len(level.exchange_breakdown),
|
||||
level.liquidity_score
|
||||
])
|
||||
else:
|
||||
features.extend([0.0, 0.0, 0.0, 0.0, 0.0])
|
||||
|
||||
# Process asks
|
||||
for i in range(max_levels):
|
||||
if i < len(cob_snapshot.consolidated_asks):
|
||||
level = cob_snapshot.consolidated_asks[i]
|
||||
price_offset = (level.price - cob_snapshot.volume_weighted_mid) / cob_snapshot.volume_weighted_mid
|
||||
features.extend([
|
||||
price_offset,
|
||||
level.total_volume_usd / 1000000,
|
||||
level.total_size / 1000,
|
||||
len(level.exchange_breakdown),
|
||||
level.liquidity_score
|
||||
])
|
||||
else:
|
||||
features.extend([0.0, 0.0, 0.0, 0.0, 0.0])
|
||||
|
||||
# Market microstructure features (20 features)
|
||||
features.extend([
|
||||
cob_snapshot.spread_bps / 100, # Normalize spread
|
||||
cob_snapshot.liquidity_imbalance,
|
||||
cob_snapshot.total_bid_liquidity / 1000000,
|
||||
cob_snapshot.total_ask_liquidity / 1000000,
|
||||
len(cob_snapshot.exchanges_active) / 5, # Normalize to max 5 exchanges
|
||||
cob_snapshot.volume_weighted_mid / 100000, # Normalize price
|
||||
|
||||
# Exchange diversity metrics
|
||||
self._calculate_exchange_diversity(cob_snapshot.consolidated_bids),
|
||||
self._calculate_exchange_diversity(cob_snapshot.consolidated_asks),
|
||||
|
||||
# Price bucket concentration
|
||||
self._calculate_bucket_concentration(cob_snapshot.price_buckets, 'bids'),
|
||||
self._calculate_bucket_concentration(cob_snapshot.price_buckets, 'asks'),
|
||||
|
||||
# Liquidity depth metrics
|
||||
self._calculate_liquidity_depth_ratio(cob_snapshot.consolidated_bids, 5),
|
||||
self._calculate_liquidity_depth_ratio(cob_snapshot.consolidated_asks, 5),
|
||||
|
||||
# Time-based features
|
||||
cob_snapshot.timestamp.hour / 24,
|
||||
cob_snapshot.timestamp.minute / 60,
|
||||
cob_snapshot.timestamp.weekday() / 7,
|
||||
|
||||
# Additional features
|
||||
0.0, 0.0, 0.0, 0.0, 0.0
|
||||
])
|
||||
|
||||
return np.array(features, dtype=np.float32)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating CNN features for {symbol}: {e}")
|
||||
return None
|
||||
|
||||
def _generate_dqn_features(self, symbol: str, cob_snapshot: COBSnapshot) -> Optional[np.ndarray]:
|
||||
"""Generate DQN state features from COB data"""
|
||||
try:
|
||||
state_features = []
|
||||
|
||||
# Normalized order book state (20 features)
|
||||
total_liquidity = cob_snapshot.total_bid_liquidity + cob_snapshot.total_ask_liquidity
|
||||
|
||||
if total_liquidity > 0:
|
||||
# Top 10 bid levels (normalized by total liquidity)
|
||||
for i in range(10):
|
||||
if i < len(cob_snapshot.consolidated_bids):
|
||||
level = cob_snapshot.consolidated_bids[i]
|
||||
state_features.append(level.total_volume_usd / total_liquidity)
|
||||
else:
|
||||
state_features.append(0.0)
|
||||
|
||||
# Top 10 ask levels (normalized by total liquidity)
|
||||
for i in range(10):
|
||||
if i < len(cob_snapshot.consolidated_asks):
|
||||
level = cob_snapshot.consolidated_asks[i]
|
||||
state_features.append(level.total_volume_usd / total_liquidity)
|
||||
else:
|
||||
state_features.append(0.0)
|
||||
else:
|
||||
state_features.extend([0.0] * 20)
|
||||
|
||||
# Market state indicators (10 features)
|
||||
state_features.extend([
|
||||
cob_snapshot.spread_bps / 1000, # Normalized spread
|
||||
cob_snapshot.liquidity_imbalance,
|
||||
len(cob_snapshot.exchanges_active) / 5, # Exchange count ratio
|
||||
min(1.0, total_liquidity / 10000000), # Liquidity abundance
|
||||
0.5, # Price efficiency placeholder
|
||||
min(1.0, total_liquidity / 5000000), # Market impact resistance
|
||||
0.0, # Arbitrage score placeholder
|
||||
0.0, # Liquidity fragmentation placeholder
|
||||
(datetime.now().hour * 60 + datetime.now().minute) / 1440, # Time of day
|
||||
0.5 # Market regime indicator placeholder
|
||||
])
|
||||
|
||||
return np.array(state_features, dtype=np.float32)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating DQN features for {symbol}: {e}")
|
||||
return None
|
||||
|
||||
def _generate_dashboard_data(self, symbol: str, cob_snapshot: COBSnapshot) -> Dict:
|
||||
"""Generate formatted data for dashboard visualization"""
|
||||
try:
|
||||
# Get fixed bucket size for the symbol
|
||||
bucket_size = self.cob_provider.fixed_usd_buckets.get(symbol, 1.0)
|
||||
|
||||
# Calculate price range for buckets
|
||||
mid_price = cob_snapshot.volume_weighted_mid
|
||||
price_range = 100 # Show 100 price levels on each side
|
||||
|
||||
# Initialize bucket arrays
|
||||
bid_buckets = defaultdict(float)
|
||||
ask_buckets = defaultdict(float)
|
||||
|
||||
# Process bids into fixed USD buckets
|
||||
for bid in cob_snapshot.consolidated_bids:
|
||||
bucket_price = math.floor(bid.price / bucket_size) * bucket_size
|
||||
bid_buckets[bucket_price] += bid.total_volume_usd
|
||||
|
||||
# Process asks into fixed USD buckets
|
||||
for ask in cob_snapshot.consolidated_asks:
|
||||
bucket_price = math.floor(ask.price / bucket_size) * bucket_size
|
||||
ask_buckets[bucket_price] += ask.total_volume_usd
|
||||
|
||||
# Convert to sorted arrays for visualization
|
||||
bid_data = []
|
||||
ask_data = []
|
||||
|
||||
# Generate price levels
|
||||
min_price = math.floor((mid_price - (price_range * bucket_size)) / bucket_size) * bucket_size
|
||||
max_price = math.ceil((mid_price + (price_range * bucket_size)) / bucket_size) * bucket_size
|
||||
|
||||
# Fill bid data
|
||||
current_price = mid_price
|
||||
while current_price >= min_price:
|
||||
bucket_price = math.floor(current_price / bucket_size) * bucket_size
|
||||
volume = bid_buckets.get(bucket_price, 0)
|
||||
if volume > 0:
|
||||
bid_data.append({
|
||||
'price': bucket_price,
|
||||
'volume': volume,
|
||||
'side': 'bid'
|
||||
})
|
||||
current_price -= bucket_size
|
||||
|
||||
# Fill ask data
|
||||
current_price = mid_price
|
||||
while current_price <= max_price:
|
||||
bucket_price = math.floor(current_price / bucket_size) * bucket_size
|
||||
volume = ask_buckets.get(bucket_price, 0)
|
||||
if volume > 0:
|
||||
ask_data.append({
|
||||
'price': bucket_price,
|
||||
'volume': volume,
|
||||
'side': 'ask'
|
||||
})
|
||||
current_price += bucket_size
|
||||
|
||||
# Get actual Session Volume Profile (SVP) from trade data
|
||||
svp_data = []
|
||||
try:
|
||||
svp_result = self.cob_provider.get_session_volume_profile(symbol, bucket_size)
|
||||
if svp_result and 'data' in svp_result:
|
||||
svp_data = svp_result['data']
|
||||
logger.debug(f"Retrieved SVP data for {symbol}: {len(svp_data)} price levels")
|
||||
else:
|
||||
logger.warning(f"No SVP data available for {symbol}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting SVP data for {symbol}: {e}")
|
||||
|
||||
# Generate market stats
|
||||
stats = {
|
||||
'symbol': symbol,
|
||||
'timestamp': cob_snapshot.timestamp.isoformat(),
|
||||
'mid_price': cob_snapshot.volume_weighted_mid,
|
||||
'spread_bps': cob_snapshot.spread_bps,
|
||||
'total_bid_liquidity': cob_snapshot.total_bid_liquidity,
|
||||
'total_ask_liquidity': cob_snapshot.total_ask_liquidity,
|
||||
'liquidity_imbalance': cob_snapshot.liquidity_imbalance,
|
||||
'exchanges_active': cob_snapshot.exchanges_active,
|
||||
'bucket_size': bucket_size
|
||||
}
|
||||
|
||||
# Add exchange diversity metrics
|
||||
stats['bid_exchange_diversity'] = self._calculate_exchange_diversity(cob_snapshot.consolidated_bids[:20])
|
||||
stats['ask_exchange_diversity'] = self._calculate_exchange_diversity(cob_snapshot.consolidated_asks[:20])
|
||||
|
||||
# Add SVP statistics
|
||||
if svp_data:
|
||||
total_traded_volume = sum(item['total_volume'] for item in svp_data)
|
||||
stats['total_traded_volume'] = total_traded_volume
|
||||
stats['svp_price_levels'] = len(svp_data)
|
||||
stats['session_start'] = svp_result.get('session_start', '')
|
||||
else:
|
||||
stats['total_traded_volume'] = 0
|
||||
stats['svp_price_levels'] = 0
|
||||
stats['session_start'] = ''
|
||||
|
||||
# Add real-time statistics for NN models
|
||||
try:
|
||||
realtime_stats = self.cob_provider.get_realtime_stats(symbol)
|
||||
if realtime_stats:
|
||||
stats['realtime_1s'] = realtime_stats.get('1s_stats', {})
|
||||
stats['realtime_5s'] = realtime_stats.get('5s_stats', {})
|
||||
else:
|
||||
stats['realtime_1s'] = {}
|
||||
stats['realtime_5s'] = {}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting real-time stats for {symbol}: {e}")
|
||||
stats['realtime_1s'] = {}
|
||||
stats['realtime_5s'] = {}
|
||||
|
||||
return {
|
||||
'type': 'cob_update',
|
||||
'data': {
|
||||
'bids': bid_data,
|
||||
'asks': ask_data,
|
||||
'svp': svp_data,
|
||||
'stats': stats
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating dashboard data for {symbol}: {e}")
|
||||
return {
|
||||
'type': 'error',
|
||||
'data': {'error': str(e)}
|
||||
}
|
||||
|
||||
def _calculate_exchange_diversity(self, levels: List[ConsolidatedOrderBookLevel]) -> float:
|
||||
"""Calculate exchange diversity in order book levels"""
|
||||
if not levels:
|
||||
return 0.0
|
||||
|
||||
exchange_counts = {}
|
||||
total_volume = 0
|
||||
|
||||
for level in levels[:10]: # Top 10 levels
|
||||
total_volume += level.total_volume_usd
|
||||
for exchange in level.exchange_breakdown:
|
||||
exchange_counts[exchange] = exchange_counts.get(exchange, 0) + level.exchange_breakdown[exchange].volume_usd
|
||||
|
||||
if total_volume == 0:
|
||||
return 0.0
|
||||
|
||||
# Calculate diversity score
|
||||
hhi = sum((volume / total_volume) ** 2 for volume in exchange_counts.values())
|
||||
return 1 - hhi
|
||||
|
||||
def _calculate_bucket_concentration(self, price_buckets: Dict, side: str) -> float:
|
||||
"""Calculate concentration of liquidity in price buckets"""
|
||||
buckets = price_buckets.get(side, {})
|
||||
if not buckets:
|
||||
return 0.0
|
||||
|
||||
volumes = [bucket['volume_usd'] for bucket in buckets.values()]
|
||||
total_volume = sum(volumes)
|
||||
|
||||
if total_volume == 0:
|
||||
return 0.0
|
||||
|
||||
sorted_volumes = sorted(volumes, reverse=True)
|
||||
top_20_percent = int(len(sorted_volumes) * 0.2) or 1
|
||||
return sum(sorted_volumes[:top_20_percent]) / total_volume
|
||||
|
||||
def _calculate_liquidity_depth_ratio(self, levels: List[ConsolidatedOrderBookLevel], top_n: int) -> float:
|
||||
"""Calculate ratio of top N levels liquidity to total"""
|
||||
if not levels:
|
||||
return 0.0
|
||||
|
||||
top_n_volume = sum(level.total_volume_usd for level in levels[:top_n])
|
||||
total_volume = sum(level.total_volume_usd for level in levels)
|
||||
|
||||
return top_n_volume / total_volume if total_volume > 0 else 0.0
|
||||
|
||||
async def _continuous_cob_analysis(self):
|
||||
"""Continuously analyze COB data for patterns and signals"""
|
||||
while True:
|
||||
try:
|
||||
for symbol in self.symbols:
|
||||
cob_snapshot = self.cob_provider.get_consolidated_orderbook(symbol)
|
||||
if cob_snapshot:
|
||||
await self._analyze_cob_patterns(symbol, cob_snapshot)
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in COB analysis loop: {e}")
|
||||
await asyncio.sleep(5)
|
||||
|
||||
async def _analyze_cob_patterns(self, symbol: str, cob_snapshot: COBSnapshot):
|
||||
"""Analyze COB data for trading patterns and signals"""
|
||||
try:
|
||||
# Large liquidity imbalance detection
|
||||
if abs(cob_snapshot.liquidity_imbalance) > 0.4:
|
||||
signal = {
|
||||
'timestamp': cob_snapshot.timestamp.isoformat(),
|
||||
'type': 'liquidity_imbalance',
|
||||
'side': 'buy' if cob_snapshot.liquidity_imbalance > 0 else 'sell',
|
||||
'strength': abs(cob_snapshot.liquidity_imbalance),
|
||||
'confidence': min(1.0, abs(cob_snapshot.liquidity_imbalance) * 2)
|
||||
}
|
||||
self.cob_signals[symbol].append(signal)
|
||||
|
||||
# Cleanup old signals
|
||||
self.cob_signals[symbol] = self.cob_signals[symbol][-100:]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error analyzing COB patterns for {symbol}: {e}")
|
||||
|
||||
async def _analyze_bucket_distribution(self, symbol: str, price_buckets: Dict):
|
||||
"""Analyze price bucket distribution for patterns"""
|
||||
try:
|
||||
# Placeholder for bucket analysis
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error analyzing bucket distribution for {symbol}: {e}")
|
||||
|
||||
async def _continuous_signal_generation(self):
|
||||
"""Continuously generate trading signals based on COB analysis"""
|
||||
while True:
|
||||
try:
|
||||
await asyncio.sleep(5)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in signal generation loop: {e}")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
# Public interface methods
|
||||
|
||||
def get_cob_features(self, symbol: str) -> Optional[np.ndarray]:
|
||||
"""Get latest CNN features for a symbol"""
|
||||
return self.cob_feature_cache.get(symbol)
|
||||
|
||||
def get_cob_snapshot(self, symbol: str) -> Optional[COBSnapshot]:
|
||||
"""Get latest COB snapshot for a symbol"""
|
||||
return self.cob_provider.get_consolidated_orderbook(symbol)
|
||||
|
||||
def get_market_depth_analysis(self, symbol: str) -> Optional[Dict]:
|
||||
"""Get detailed market depth analysis"""
|
||||
return self.cob_provider.get_market_depth_analysis(symbol)
|
||||
|
||||
def get_exchange_breakdown(self, symbol: str) -> Optional[Dict]:
|
||||
"""Get liquidity breakdown by exchange"""
|
||||
return self.cob_provider.get_exchange_breakdown(symbol)
|
||||
|
||||
def get_price_buckets(self, symbol: str) -> Optional[Dict]:
|
||||
"""Get fine-grain price buckets"""
|
||||
return self.cob_provider.get_price_buckets(symbol)
|
||||
|
||||
def get_recent_signals(self, symbol: str, count: int = 20) -> List[Dict]:
|
||||
"""Get recent COB-based trading signals"""
|
||||
return self.cob_signals.get(symbol, [])[-count:]
|
||||
|
||||
def get_statistics(self) -> Dict[str, Any]:
|
||||
"""Get COB integration statistics"""
|
||||
provider_stats = self.cob_provider.get_statistics()
|
||||
|
||||
return {
|
||||
**provider_stats,
|
||||
'cnn_callbacks': len(self.cnn_callbacks),
|
||||
'dqn_callbacks': len(self.dqn_callbacks),
|
||||
'dashboard_callbacks': len(self.dashboard_callbacks),
|
||||
'cached_features': list(self.cob_feature_cache.keys()),
|
||||
'total_signals': {symbol: len(signals) for symbol, signals in self.cob_signals.items()}
|
||||
}
|
||||
|
||||
def get_realtime_stats_for_nn(self, symbol: str) -> Dict:
|
||||
"""Get real-time statistics formatted for NN models"""
|
||||
try:
|
||||
realtime_stats = self.cob_provider.get_realtime_stats(symbol)
|
||||
if not realtime_stats:
|
||||
return {}
|
||||
|
||||
# Format for NN consumption
|
||||
nn_stats = {
|
||||
'symbol': symbol,
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'current': {
|
||||
'mid_price': 0.0,
|
||||
'spread_bps': 0.0,
|
||||
'bid_liquidity': 0.0,
|
||||
'ask_liquidity': 0.0,
|
||||
'imbalance': 0.0
|
||||
},
|
||||
'1s_window': realtime_stats.get('1s_stats', {}),
|
||||
'5s_window': realtime_stats.get('5s_stats', {})
|
||||
}
|
||||
|
||||
# Get current values from latest COB snapshot
|
||||
cob_snapshot = self.cob_provider.get_consolidated_orderbook(symbol)
|
||||
if cob_snapshot:
|
||||
nn_stats['current'] = {
|
||||
'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,
|
||||
'imbalance': cob_snapshot.liquidity_imbalance
|
||||
}
|
||||
|
||||
return nn_stats
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting NN stats for {symbol}: {e}")
|
||||
return {}
|
Reference in New Issue
Block a user