better dash
This commit is contained in:
parent
cf825239cd
commit
3c23e4ec42
@ -1,10 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Scalping Dashboard Runner - 100% REAL MARKET DATA ONLY
|
Run Ultra-Fast Scalping Dashboard (500x Leverage)
|
||||||
|
|
||||||
CRITICAL: This dashboard uses EXCLUSIVELY real market data.
|
This script starts the custom scalping dashboard with:
|
||||||
NO synthetic, mock, or simulated data is allowed.
|
- Full-width 1s ETH/USDT candlestick chart
|
||||||
All trading decisions come from real market analysis.
|
- 3 small ETH charts: 1m, 1h, 1d
|
||||||
|
- 1 small BTC 1s chart
|
||||||
|
- Ultra-fast 100ms updates for scalping
|
||||||
|
- Real-time PnL tracking and logging
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@ -48,6 +48,14 @@ class TradingDashboard:
|
|||||||
self.current_prices = {}
|
self.current_prices = {}
|
||||||
self.last_update = datetime.now()
|
self.last_update = datetime.now()
|
||||||
|
|
||||||
|
# Trading session tracking
|
||||||
|
self.session_start = datetime.now()
|
||||||
|
self.session_trades = []
|
||||||
|
self.session_pnl = 0.0
|
||||||
|
self.current_position = None # {'side': 'BUY', 'price': 3456.78, 'size': 0.1, 'timestamp': datetime}
|
||||||
|
self.total_realized_pnl = 0.0
|
||||||
|
self.total_fees = 0.0
|
||||||
|
|
||||||
# Create Dash app
|
# Create Dash app
|
||||||
self.app = dash.Dash(__name__, external_stylesheets=[
|
self.app = dash.Dash(__name__, external_stylesheets=[
|
||||||
'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css',
|
'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css',
|
||||||
@ -76,7 +84,7 @@ class TradingDashboard:
|
|||||||
# Auto-refresh component
|
# Auto-refresh component
|
||||||
dcc.Interval(
|
dcc.Interval(
|
||||||
id='interval-component',
|
id='interval-component',
|
||||||
interval=5000, # Update every 5 seconds for better real-time feel
|
interval=1000, # Update every 1 second for real-time tick updates
|
||||||
n_intervals=0
|
n_intervals=0
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -189,24 +197,30 @@ class TradingDashboard:
|
|||||||
symbol = self.config.symbols[0] if self.config.symbols else "ETH/USDT"
|
symbol = self.config.symbols[0] if self.config.symbols else "ETH/USDT"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Try to get fresh current price from latest data
|
# Try to get fresh current price from latest data - OPTIMIZED FOR SPEED
|
||||||
|
fresh_data = self.data_provider.get_historical_data(symbol, '1s', limit=5, refresh=True)
|
||||||
|
if fresh_data is not None and not fresh_data.empty:
|
||||||
|
current_price = float(fresh_data['close'].iloc[-1])
|
||||||
|
logger.debug(f"[TICK] Fresh price for {symbol}: ${current_price:.2f}")
|
||||||
|
else:
|
||||||
|
# Quick fallback to 1m data
|
||||||
fresh_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=True)
|
fresh_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=True)
|
||||||
if fresh_data is not None and not fresh_data.empty:
|
if fresh_data is not None and not fresh_data.empty:
|
||||||
current_price = float(fresh_data['close'].iloc[-1])
|
current_price = float(fresh_data['close'].iloc[-1])
|
||||||
logger.debug(f"Got fresh price for {symbol}: ${current_price:.2f}")
|
logger.debug(f"[TICK] Fresh 1m price for {symbol}: ${current_price:.2f}")
|
||||||
else:
|
else:
|
||||||
# Fallback to cached data
|
# Use cached data with simulation
|
||||||
cached_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=False)
|
cached_data = self.data_provider.get_historical_data(symbol, '1m', limit=1, refresh=False)
|
||||||
if cached_data is not None and not cached_data.empty:
|
if cached_data is not None and not cached_data.empty:
|
||||||
base_price = float(cached_data['close'].iloc[-1])
|
base_price = float(cached_data['close'].iloc[-1])
|
||||||
# Apply small realistic price movement for demo
|
# Apply small realistic price movement for demo
|
||||||
current_price = self._simulate_price_update(symbol, base_price)
|
current_price = self._simulate_price_update(symbol, base_price)
|
||||||
logger.debug(f"Simulated price update for {symbol}: ${current_price:.2f} (base: ${base_price:.2f})")
|
logger.debug(f"[SIM] Simulated price update for {symbol}: ${current_price:.2f} (base: ${base_price:.2f})")
|
||||||
else:
|
else:
|
||||||
current_price = None
|
current_price = None
|
||||||
logger.warning(f"No price data available for {symbol}")
|
logger.warning(f"[ERROR] No price data available for {symbol}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error getting price for {symbol}: {e}")
|
logger.warning(f"[ERROR] Error getting price for {symbol}: {e}")
|
||||||
current_price = None
|
current_price = None
|
||||||
|
|
||||||
# Get model performance metrics with fallback
|
# Get model performance metrics with fallback
|
||||||
@ -233,10 +247,12 @@ class TradingDashboard:
|
|||||||
wins += 1
|
wins += 1
|
||||||
|
|
||||||
# Format outputs with safe defaults and update indicators
|
# Format outputs with safe defaults and update indicators
|
||||||
update_time = datetime.now().strftime("%H:%M:%S")
|
update_time = datetime.now().strftime("%H:%M:%S.%f")[:-3] # Include milliseconds
|
||||||
price_text = f"${current_price:.2f}" if current_price else "No Data"
|
price_text = f"${current_price:.2f}" if current_price else "No Data"
|
||||||
if current_price:
|
if current_price:
|
||||||
price_text += f" @ {update_time}"
|
# Add tick indicator and precise timestamp (no emojis to avoid Unicode issues)
|
||||||
|
tick_indicator = "[LIVE]" if (datetime.now().microsecond // 100000) % 2 else "[TICK]" # Alternating indicator
|
||||||
|
price_text += f" {tick_indicator} @ {update_time}"
|
||||||
pnl_text = f"${total_pnl:.2f}"
|
pnl_text = f"${total_pnl:.2f}"
|
||||||
pnl_class = "text-success mb-1" if total_pnl >= 0 else "text-danger mb-1"
|
pnl_class = "text-success mb-1" if total_pnl >= 0 else "text-danger mb-1"
|
||||||
win_rate_text = f"{(wins/total_trades*100):.1f}%" if total_trades > 0 else "0.0%"
|
win_rate_text = f"{(wins/total_trades*100):.1f}%" if total_trades > 0 else "0.0%"
|
||||||
@ -348,30 +364,31 @@ class TradingDashboard:
|
|||||||
|
|
||||||
for tf in timeframes_to_try:
|
for tf in timeframes_to_try:
|
||||||
try:
|
try:
|
||||||
# FORCE FRESH DATA on each update for real-time charts
|
# FORCE FRESH DATA on each update for real-time charts - OPTIMIZED FOR SPEED
|
||||||
df = self.data_provider.get_historical_data(symbol, tf, limit=200, refresh=True)
|
limit = 100 if tf == '1s' else 50 if tf == '1m' else 30 # Smaller data for faster updates
|
||||||
|
df = self.data_provider.get_historical_data(symbol, tf, limit=limit, refresh=True)
|
||||||
if df is not None and not df.empty and len(df) > 5:
|
if df is not None and not df.empty and len(df) > 5:
|
||||||
actual_timeframe = tf
|
actual_timeframe = tf
|
||||||
logger.info(f"✅ Got FRESH {len(df)} candles for {symbol} {tf}")
|
logger.info(f"[FRESH] Got {len(df)} candles for {symbol} {tf}")
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
logger.warning(f"⚠️ No fresh data for {symbol} {tf}")
|
logger.warning(f"[WARN] No fresh data for {symbol} {tf}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"⚠️ Error getting fresh {symbol} {tf} data: {e}")
|
logger.warning(f"[ERROR] Error getting fresh {symbol} {tf} data: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If still no fresh data, try cached data as fallback
|
# If still no fresh data, try cached data as fallback
|
||||||
if df is None or df.empty:
|
if df is None or df.empty:
|
||||||
logger.warning(f"⚠️ No fresh data, trying cached data for {symbol}")
|
logger.warning(f"[WARN] No fresh data, trying cached data for {symbol}")
|
||||||
for tf in timeframes_to_try:
|
for tf in timeframes_to_try:
|
||||||
try:
|
try:
|
||||||
df = self.data_provider.get_historical_data(symbol, tf, limit=200, refresh=False)
|
df = self.data_provider.get_historical_data(symbol, tf, limit=200, refresh=False)
|
||||||
if df is not None and not df.empty and len(df) > 5:
|
if df is not None and not df.empty and len(df) > 5:
|
||||||
actual_timeframe = tf
|
actual_timeframe = tf
|
||||||
logger.info(f"✅ Got cached {len(df)} candles for {symbol} {tf}")
|
logger.info(f"[CACHED] Got {len(df)} candles for {symbol} {tf}")
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"⚠️ Error getting cached {symbol} {tf} data: {e}")
|
logger.warning(f"[ERROR] Error getting cached {symbol} {tf} data: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If still no data, create empty chart
|
# If still no data, create empty chart
|
||||||
@ -427,11 +444,11 @@ class TradingDashboard:
|
|||||||
))
|
))
|
||||||
|
|
||||||
# Update layout with current timestamp
|
# Update layout with current timestamp
|
||||||
current_time = datetime.now().strftime("%H:%M:%S")
|
current_time = datetime.now().strftime("%H:%M:%S.%f")[:-3] # Include milliseconds
|
||||||
latest_price = df['close'].iloc[-1] if not df.empty else 0
|
latest_price = df['close'].iloc[-1] if not df.empty else 0
|
||||||
|
|
||||||
fig.update_layout(
|
fig.update_layout(
|
||||||
title=f"{symbol} Price Chart ({actual_timeframe.upper()}) - {len(df)} candles | ${latest_price:.2f} @ {current_time}",
|
title=f"{symbol} LIVE CHART ({actual_timeframe.upper()}) | ${latest_price:.2f} | {len(df)} candles | {current_time}",
|
||||||
template="plotly_dark",
|
template="plotly_dark",
|
||||||
height=400,
|
height=400,
|
||||||
xaxis_rangeslider_visible=False,
|
xaxis_rangeslider_visible=False,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user