COB integration - finally
This commit is contained in:
@ -336,6 +336,146 @@ class DashboardComponentManager:
|
||||
logger.error(f"Error formatting COB data: {e}")
|
||||
return [html.P(f"Error: {str(e)}", className="text-danger small")]
|
||||
|
||||
def format_cob_data_with_buckets(self, cob_snapshot, symbol, price_buckets, memory_stats, bucket_size=1.0):
|
||||
"""Format COB data with price buckets for high-frequency display"""
|
||||
try:
|
||||
components = []
|
||||
|
||||
# Symbol header with memory stats
|
||||
buffer_count = memory_stats.get('buffer_updates', 0)
|
||||
memory_count = memory_stats.get('memory_snapshots', 0)
|
||||
total_updates = memory_stats.get('total_updates', 0)
|
||||
|
||||
components.append(html.Div([
|
||||
html.Strong(f"{symbol}", className="text-info"),
|
||||
html.Span(f" - High-Freq COB", className="small text-muted"),
|
||||
html.Br(),
|
||||
html.Span(f"Buffer: {buffer_count} | Memory: {memory_count} | Total: {total_updates}",
|
||||
className="small text-success")
|
||||
], className="mb-2"))
|
||||
|
||||
# COB snapshot data (if available)
|
||||
if cob_snapshot:
|
||||
if hasattr(cob_snapshot, 'volume_weighted_mid'):
|
||||
# Real COB snapshot
|
||||
mid_price = getattr(cob_snapshot, 'volume_weighted_mid', 0)
|
||||
spread_bps = getattr(cob_snapshot, 'spread_bps', 0)
|
||||
imbalance = getattr(cob_snapshot, 'liquidity_imbalance', 0)
|
||||
|
||||
components.append(html.Div([
|
||||
html.Div([
|
||||
html.I(className="fas fa-dollar-sign text-success me-2"),
|
||||
html.Span(f"Mid: ${mid_price:.2f}", className="small fw-bold")
|
||||
], className="mb-1"),
|
||||
html.Div([
|
||||
html.I(className="fas fa-arrows-alt-h text-warning me-2"),
|
||||
html.Span(f"Spread: {spread_bps:.1f} bps", className="small")
|
||||
], className="mb-1")
|
||||
]))
|
||||
|
||||
# Imbalance
|
||||
imbalance_color = "text-success" if imbalance > 0.1 else "text-danger" if imbalance < -0.1 else "text-muted"
|
||||
imbalance_text = "Bid Heavy" if imbalance > 0.1 else "Ask Heavy" if imbalance < -0.1 else "Balanced"
|
||||
|
||||
components.append(html.Div([
|
||||
html.I(className="fas fa-balance-scale me-2"),
|
||||
html.Span(f"{imbalance_text} ({imbalance:.3f})", className=f"small {imbalance_color}")
|
||||
], className="mb-2"))
|
||||
else:
|
||||
# Fallback for other data formats
|
||||
components.append(html.Div([
|
||||
html.I(className="fas fa-chart-bar text-info me-2"),
|
||||
html.Span("COB: Active", className="small")
|
||||
], className="mb-2"))
|
||||
|
||||
# Price Buckets Section
|
||||
components.append(html.H6([
|
||||
html.I(className="fas fa-layer-group me-2 text-primary"),
|
||||
f"${bucket_size:.0f} Price Buckets (±5 levels)"
|
||||
], className="mb-2"))
|
||||
|
||||
if price_buckets:
|
||||
# Sort buckets by price
|
||||
sorted_buckets = sorted(price_buckets, key=lambda x: x['price'])
|
||||
|
||||
bucket_rows = []
|
||||
for bucket in sorted_buckets:
|
||||
price = bucket['price']
|
||||
total_vol = bucket['total_volume']
|
||||
bid_pct = bucket['bid_pct']
|
||||
ask_pct = bucket['ask_pct']
|
||||
|
||||
# Format volume
|
||||
if total_vol > 1000000:
|
||||
vol_str = f"${total_vol/1000000:.1f}M"
|
||||
elif total_vol > 1000:
|
||||
vol_str = f"${total_vol/1000:.0f}K"
|
||||
else:
|
||||
vol_str = f"${total_vol:.0f}"
|
||||
|
||||
# Color based on bid/ask dominance
|
||||
if bid_pct > 60:
|
||||
row_class = "border-success"
|
||||
dominance = "BID"
|
||||
dominance_class = "text-success"
|
||||
elif ask_pct > 60:
|
||||
row_class = "border-danger"
|
||||
dominance = "ASK"
|
||||
dominance_class = "text-danger"
|
||||
else:
|
||||
row_class = "border-secondary"
|
||||
dominance = "BAL"
|
||||
dominance_class = "text-muted"
|
||||
|
||||
bucket_row = html.Div([
|
||||
html.Div([
|
||||
html.Span(f"${price:.0f}", className="fw-bold me-2"),
|
||||
html.Span(vol_str, className="text-info me-2"),
|
||||
html.Span(f"{dominance}", className=f"small {dominance_class}")
|
||||
], className="d-flex justify-content-between"),
|
||||
html.Div([
|
||||
# Bid bar
|
||||
html.Div(
|
||||
style={
|
||||
"width": f"{bid_pct}%",
|
||||
"height": "4px",
|
||||
"backgroundColor": "#28a745",
|
||||
"display": "inline-block"
|
||||
}
|
||||
),
|
||||
# Ask bar
|
||||
html.Div(
|
||||
style={
|
||||
"width": f"{ask_pct}%",
|
||||
"height": "4px",
|
||||
"backgroundColor": "#dc3545",
|
||||
"display": "inline-block"
|
||||
}
|
||||
)
|
||||
], className="mt-1")
|
||||
], className=f"border {row_class} rounded p-2 mb-1 small")
|
||||
|
||||
bucket_rows.append(bucket_row)
|
||||
|
||||
components.extend(bucket_rows)
|
||||
else:
|
||||
components.append(html.P("No price bucket data", className="text-muted small"))
|
||||
|
||||
# High-frequency update rate info
|
||||
components.append(html.Div([
|
||||
html.Hr(),
|
||||
html.Div([
|
||||
html.I(className="fas fa-tachometer-alt text-info me-2"),
|
||||
html.Span("High-Freq: 50-100 Hz | UI: 10 Hz", className="small text-muted")
|
||||
])
|
||||
]))
|
||||
|
||||
return components
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error formatting COB data with buckets: {e}")
|
||||
return [html.P(f"Error: {str(e)}", className="text-danger small")]
|
||||
|
||||
def format_training_metrics(self, metrics_data):
|
||||
"""Format training metrics for display - Enhanced with loaded models"""
|
||||
try:
|
||||
|
Reference in New Issue
Block a user