minor UI changes
This commit is contained in:
@ -273,13 +273,13 @@ class DashboardComponentManager:
|
||||
overview_panel = self._create_cob_overview_panel(symbol, stats, cumulative_imbalance_stats)
|
||||
|
||||
# --- Right Panel: Compact Ladder ---
|
||||
ladder_panel = self._create_cob_ladder_panel(bids, asks, mid_price)
|
||||
ladder_panel = self._create_cob_ladder_panel(bids, asks, mid_price, symbol)
|
||||
|
||||
return dbc.Row([
|
||||
dbc.Col(overview_panel, width=5, className="pe-1"),
|
||||
dbc.Col(ladder_panel, width=7, className="ps-1")
|
||||
], className="g-0") # g-0 removes gutters
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error formatting split COB data: {e}")
|
||||
return html.P(f"Error: {str(e)}", className="text-danger small")
|
||||
@ -347,7 +347,7 @@ class DashboardComponentManager:
|
||||
html.Div(value, className="fw-bold")
|
||||
], className="text-center")
|
||||
|
||||
def _create_cob_ladder_panel(self, bids, asks, mid_price):
|
||||
def _create_cob_ladder_panel(self, bids, asks, mid_price, symbol=""):
|
||||
"""Creates the right panel with the compact COB ladder."""
|
||||
bucket_size = 10
|
||||
num_levels = 5
|
||||
@ -356,52 +356,77 @@ class DashboardComponentManager:
|
||||
buckets = {}
|
||||
for order in orders:
|
||||
price = order.get('price', 0)
|
||||
size = order.get('size', 0)
|
||||
# Handle both old format (size) and new format (total_size)
|
||||
size = order.get('total_size', order.get('size', 0))
|
||||
volume_usd = order.get('total_volume_usd', size * price)
|
||||
if price > 0:
|
||||
bucket_key = round(price / bucket_size) * bucket_size
|
||||
if bucket_key not in buckets:
|
||||
buckets[bucket_key] = 0
|
||||
buckets[bucket_key] += size * price
|
||||
buckets[bucket_key] = {'usd_volume': 0, 'crypto_volume': 0}
|
||||
buckets[bucket_key]['usd_volume'] += volume_usd
|
||||
buckets[bucket_key]['crypto_volume'] += size
|
||||
return buckets
|
||||
|
||||
bid_buckets = aggregate_buckets(bids)
|
||||
ask_buckets = aggregate_buckets(asks)
|
||||
|
||||
all_volumes = list(bid_buckets.values()) + list(ask_buckets.values())
|
||||
max_volume = max(all_volumes) if all_volumes else 1
|
||||
all_usd_volumes = [b['usd_volume'] for b in bid_buckets.values()] + [a['usd_volume'] for a in ask_buckets.values()]
|
||||
max_volume = max(all_usd_volumes) if all_usd_volumes else 1
|
||||
|
||||
center_bucket = round(mid_price / bucket_size) * bucket_size
|
||||
ask_levels = [center_bucket + i * bucket_size for i in range(1, num_levels + 1)]
|
||||
bid_levels = [center_bucket - i * bucket_size for i in range(num_levels)]
|
||||
|
||||
def create_ladder_row(price, volume, max_vol, row_type):
|
||||
progress = (volume / max_vol) * 100 if max_vol > 0 else 0
|
||||
def create_ladder_row(price, bucket_data, max_vol, row_type):
|
||||
usd_volume = bucket_data.get('usd_volume', 0)
|
||||
crypto_volume = bucket_data.get('crypto_volume', 0)
|
||||
|
||||
progress = (usd_volume / max_vol) * 100 if max_vol > 0 else 0
|
||||
color = "danger" if row_type == 'ask' else "success"
|
||||
text_color = "text-danger" if row_type == 'ask' else "text-success"
|
||||
|
||||
vol_str = f"${volume/1e3:.0f}K" if volume > 1e3 else f"${volume:,.0f}"
|
||||
# Format USD volume (no $ symbol)
|
||||
if usd_volume > 1e6:
|
||||
usd_str = f"{usd_volume/1e6:.1f}M"
|
||||
elif usd_volume > 1e3:
|
||||
usd_str = f"{usd_volume/1e3:.0f}K"
|
||||
else:
|
||||
usd_str = f"{usd_volume:,.0f}"
|
||||
|
||||
# Format crypto volume (no unit symbol)
|
||||
if crypto_volume > 1000:
|
||||
crypto_str = f"{crypto_volume/1000:.1f}K"
|
||||
elif crypto_volume > 1:
|
||||
crypto_str = f"{crypto_volume:.1f}"
|
||||
else:
|
||||
crypto_str = f"{crypto_volume:.3f}"
|
||||
|
||||
return html.Tr([
|
||||
html.Td(f"${price:,.2f}", className=f"{text_color} price-level"),
|
||||
html.Td(f"${price:,.0f}", className=f"{text_color} price-level small"),
|
||||
html.Td(
|
||||
dbc.Progress(value=progress, color=color, className="vh-25 compact-progress"),
|
||||
className="progress-cell"
|
||||
className="progress-cell p-0"
|
||||
),
|
||||
html.Td(vol_str, className="volume-level text-end")
|
||||
], className="compact-ladder-row")
|
||||
html.Td(usd_str, className="volume-level text-end fw-bold small p-0 pe-1"),
|
||||
html.Td(crypto_str, className="volume-level text-start small text-muted p-0 ps-1")
|
||||
], className="compact-ladder-row p-0")
|
||||
|
||||
ask_rows = [create_ladder_row(p, ask_buckets.get(p, 0), max_volume, 'ask') for p in sorted(ask_levels, reverse=True)]
|
||||
bid_rows = [create_ladder_row(p, bid_buckets.get(p, 0), max_volume, 'bid') for p in sorted(bid_levels, reverse=True)]
|
||||
def get_bucket_data(buckets, price):
|
||||
return buckets.get(price, {'usd_volume': 0, 'crypto_volume': 0})
|
||||
|
||||
ask_rows = [create_ladder_row(p, get_bucket_data(ask_buckets, p), max_volume, 'ask') for p in sorted(ask_levels, reverse=True)]
|
||||
bid_rows = [create_ladder_row(p, get_bucket_data(bid_buckets, p), max_volume, 'bid') for p in sorted(bid_levels, reverse=True)]
|
||||
|
||||
mid_row = html.Tr([
|
||||
html.Td(f"${mid_price:,.2f}", colSpan=3, className="text-center fw-bold small mid-price-row")
|
||||
html.Td(f"${mid_price:,.0f}", colSpan=4, className="text-center fw-bold small mid-price-row p-0")
|
||||
])
|
||||
|
||||
ladder_table = html.Table([
|
||||
html.Thead(html.Tr([
|
||||
html.Th("Price", className="small"),
|
||||
html.Th("Volume", className="small"),
|
||||
html.Th("Total", className="small text-end")
|
||||
html.Th("Price", className="small p-0"),
|
||||
html.Th("Volume", className="small p-0"),
|
||||
html.Th("USD", className="small text-end p-0 pe-1"),
|
||||
html.Th("Crypto", className="small text-start p-0 ps-1")
|
||||
])),
|
||||
html.Tbody(ask_rows + [mid_row] + bid_rows)
|
||||
], className="table table-sm table-borderless cob-ladder-table-compact m-0 p-0") # Compact classes
|
||||
@ -477,7 +502,10 @@ class DashboardComponentManager:
|
||||
bid_pct = bucket['bid_pct']
|
||||
ask_pct = bucket['ask_pct']
|
||||
|
||||
# Format volume
|
||||
# Get crypto volume if available (some bucket formats include crypto_volume)
|
||||
crypto_vol = bucket.get('crypto_volume', bucket.get('size', 0))
|
||||
|
||||
# Format USD volume
|
||||
if total_vol > 1000000:
|
||||
vol_str = f"${total_vol/1000000:.1f}M"
|
||||
elif total_vol > 1000:
|
||||
@ -485,6 +513,17 @@ class DashboardComponentManager:
|
||||
else:
|
||||
vol_str = f"${total_vol:.0f}"
|
||||
|
||||
# Format crypto volume based on symbol
|
||||
crypto_unit = "BTC" if "BTC" in symbol else "ETH" if "ETH" in symbol else "CRYPTO"
|
||||
if crypto_vol > 1000:
|
||||
crypto_str = f"{crypto_vol/1000:.1f}K {crypto_unit}"
|
||||
elif crypto_vol > 1:
|
||||
crypto_str = f"{crypto_vol:.1f} {crypto_unit}"
|
||||
elif crypto_vol > 0:
|
||||
crypto_str = f"{crypto_vol:.3f} {crypto_unit}"
|
||||
else:
|
||||
crypto_str = ""
|
||||
|
||||
# Color based on bid/ask dominance
|
||||
if bid_pct > 60:
|
||||
row_class = "border-success"
|
||||
@ -503,8 +542,9 @@ class DashboardComponentManager:
|
||||
html.Div([
|
||||
html.Span(f"${price:.0f}", className="fw-bold me-2"),
|
||||
html.Span(vol_str, className="text-info me-2"),
|
||||
html.Span(crypto_str, className="small text-muted me-2") if crypto_str else "",
|
||||
html.Span(f"{dominance}", className=f"small {dominance_class}")
|
||||
], className="d-flex justify-content-between"),
|
||||
], className="d-flex justify-content-between align-items-center"),
|
||||
html.Div([
|
||||
# Bid bar
|
||||
html.Div(
|
||||
|
Reference in New Issue
Block a user