COB heatmap WIP

This commit is contained in:
Dobromir Popov
2025-08-10 02:51:06 +03:00
parent 4ea2386d07
commit 1cc8509e87
3 changed files with 186 additions and 101 deletions

View File

@ -1473,7 +1473,7 @@ class CleanTradingDashboard:
def update_cob_heatmap_eth(n):
"""Render ETH COB 1s heatmap (±10 buckets, last 5 minutes)."""
try:
# Unified heatmap source from provider
# Unified heatmap source from provider (show last 300s)
times, prices, matrix = [], [], []
if hasattr(self.data_provider, 'get_cob_heatmap_matrix'):
times, prices, matrix, mids = self.data_provider.get_cob_heatmap_matrix('ETH/USDT', seconds=300, bucket_radius=10, metric='liquidity')
@ -1483,13 +1483,13 @@ class CleanTradingDashboard:
fig.update_layout(margin=dict(l=10, r=10, t=20, b=10))
return fig
z = np.array(matrix, dtype=float)
# Normalize per-column for visualization stability (visual only)
# Normalize per-time column (visual only) and transpose to [buckets x time]
col_max = np.maximum(z.max(axis=0), 1e-9)
zn = z / col_max
zn = (z / col_max).T
fig = go.Figure(data=go.Heatmap(
z=zn.T,
x=[t.strftime('%H:%M:%S') for t in times],
y=[f"{p:.2f}" for p in prices],
z=zn,
x=times,
y=prices,
colorscale='Turbo',
colorbar=dict(title='Norm'),
zmin=0.0,
@ -1523,7 +1523,8 @@ class CleanTradingDashboard:
fig.update_layout(
title="ETH COB Heatmap (liquidity, per-bucket normalized)",
xaxis_title="Time",
yaxis_title="Price",
yaxis_title="Price (USD)",
xaxis_type='date',
margin=dict(l=10, r=10, t=30, b=10)
)
return fig
@ -1540,7 +1541,7 @@ class CleanTradingDashboard:
)
def update_cob_heatmap_btc(n):
try:
# Unified heatmap source from provider
# Unified heatmap source from provider (show last 300s)
times, prices, matrix = [], [], []
if hasattr(self.data_provider, 'get_cob_heatmap_matrix'):
times, prices, matrix, mids = self.data_provider.get_cob_heatmap_matrix('BTC/USDT', seconds=300, bucket_radius=10, metric='liquidity')
@ -1551,11 +1552,11 @@ class CleanTradingDashboard:
return fig
z = np.array(matrix, dtype=float)
col_max = np.maximum(z.max(axis=0), 1e-9)
zn = z / col_max
zn = (z / col_max).T
fig = go.Figure(data=go.Heatmap(
z=zn.T,
x=[t.strftime('%H:%M:%S') for t in times],
y=[f"{p:.2f}" for p in prices],
z=zn,
x=times,
y=prices,
colorscale='Turbo',
colorbar=dict(title='Norm'),
zmin=0.0,
@ -1586,7 +1587,8 @@ class CleanTradingDashboard:
fig.update_layout(
title="BTC COB Heatmap (liquidity, per-bucket normalized)",
xaxis_title="Time",
yaxis_title="Price",
yaxis_title="Price (USD)",
xaxis_type='date',
margin=dict(l=10, r=10, t=30, b=10)
)
return fig
@ -2189,7 +2191,20 @@ class CleanTradingDashboard:
if symbol in self.current_prices and self.current_prices[symbol] > 0:
return self.current_prices[symbol]
# Return None instead of hardcoded fallbacks - let the UI handle missing data
# FINAL FALLBACK: Use latest COB mid_price (real data) if available
try:
if hasattr(self.data_provider, 'get_latest_cob_data'):
snap = self.data_provider.get_latest_cob_data(symbol)
if snap and isinstance(snap.get('stats'), dict):
mid = float(snap['stats'].get('mid_price', 0) or 0)
if mid > 0:
self.current_prices[symbol] = mid
logger.info(f"Using COB mid_price as current price for {symbol}: ${mid:.2f}")
return mid
except Exception as _:
pass
# Return None if absolutely nothing available
return None
def _create_price_chart(self, symbol: str) -> go.Figure:
@ -2422,50 +2437,7 @@ class CleanTradingDashboard:
# Mini 1-second chart (if available)
if has_mini_chart and ws_data_1s is not None:
# Overlay COB heatmap (up to 5 minutes) behind the 1s price line
try:
hm_seconds = 300 # 5 minutes
bucket_radius = 10 # ±10 buckets
# Prefer raw liquidity for visual; models can still use normalized features internally
times, prices, matrix, mids = self.data_provider.get_cob_heatmap_matrix(
symbol=symbol,
seconds=hm_seconds,
bucket_radius=bucket_radius,
metric='liquidity'
)
if times and prices and matrix:
# Align times to local tz-naive to match chart
try:
_local_tz = datetime.now().astimezone().tzinfo
except Exception:
_local_tz = None
x_vals = []
for t in times:
try:
if hasattr(t, 'tzinfo') and t.tzinfo is not None:
tt = t.astimezone(_local_tz) if _local_tz else t
tt = tt.replace(tzinfo=None)
else:
tt = t
x_vals.append(tt)
except Exception:
x_vals.append(t)
# Plot heatmap beneath the 1s price line
fig.add_trace(
go.Heatmap(
x=x_vals,
y=prices, # numeric prices to share axis with 1s line
z=matrix,
colorscale='Turbo',
showscale=False,
zsmooth='best',
opacity=0.8,
name='COB Liquidity'
),
row=2, col=1
)
except Exception as e:
logger.debug(f"COB heatmap overlay skipped: {e}")
# Removed COB heatmap overlay on the mini 1s chart per request
# Align mini chart to local tz-naive
try:
if hasattr(ws_data_1s.index, 'tz') and ws_data_1s.index.tz is not None: