working charts again!!!

This commit is contained in:
Dobromir Popov 2025-05-24 01:15:16 +03:00
parent 477e5dca39
commit 0c445435d0
5 changed files with 539 additions and 38 deletions

View File

@ -1017,6 +1017,7 @@ class TickStorage:
self.current_candle = {tf: None for tf in self.timeframes}
self.last_candle_timestamp = {tf: None for tf in self.timeframes}
self.cache_dir = os.path.join(os.getcwd(), "cache", symbol.replace("/", ""))
self.cache_path = os.path.join(self.cache_dir, f"{symbol.replace('/', '')}_ticks.json") # Add missing cache_path
self.use_timescaledb = use_timescaledb
self.max_ticks = 10000 # Maximum number of ticks to store in memory
@ -1024,9 +1025,13 @@ class TickStorage:
os.makedirs(self.cache_dir, exist_ok=True)
logger.info(f"Creating new tick storage for {symbol} with timeframes {self.timeframes}")
logger.info(f"Cache directory: {self.cache_dir}")
logger.info(f"Cache file: {self.cache_path}")
if use_timescaledb:
print(f"TickStorage: TimescaleDB integration is ENABLED for {symbol}")
else:
logger.info(f"TickStorage: TimescaleDB integration is DISABLED for {symbol}")
def _save_to_cache(self):
"""Save ticks to a cache file"""
@ -1282,40 +1287,57 @@ class TickStorage:
def load_historical_data(self, symbol, limit=1000):
"""Load historical data for all timeframes"""
logger.info(f"Starting historical data load for {symbol} with limit {limit}")
# Clear existing data
self.ticks = []
self.candles = {tf: [] for tf in self.timeframes}
self.current_candle = {tf: None for tf in self.timeframes}
# Try to load ticks from cache first
logger.info("Attempting to load from cache...")
cache_loaded = self._load_from_cache()
if cache_loaded:
logger.info("Successfully loaded data from cache")
else:
logger.info("No valid cache data found")
# Check if we have TimescaleDB enabled
if self.use_timescaledb:
if self.use_timescaledb and timescaledb_handler and timescaledb_handler.enabled:
logger.info("Attempting to fetch historical data from TimescaleDB")
loaded_from_db = False
# Load candles for each timeframe from TimescaleDB
for tf in self.timeframes:
candles = timescaledb_handler.fetch_candles(symbol, tf, limit)
if candles:
self.candles[tf] = candles
loaded_from_db = True
logger.info(f"Loaded {len(candles)} {tf} candles from TimescaleDB")
try:
candles = timescaledb_handler.fetch_candles(symbol, tf, limit)
if candles:
self.candles[tf] = candles
loaded_from_db = True
logger.info(f"Loaded {len(candles)} {tf} candles from TimescaleDB")
else:
logger.info(f"No {tf} candles found in TimescaleDB")
except Exception as e:
logger.error(f"Error loading {tf} candles from TimescaleDB: {str(e)}")
if loaded_from_db:
logger.info("Successfully loaded historical data from TimescaleDB")
return True
else:
logger.info("TimescaleDB not available or disabled")
# If no TimescaleDB data and no cache, we need to get from Binance API
if not cache_loaded:
logger.info("Loading data from Binance API...")
# Create a BinanceHistoricalData instance
historical_data = BinanceHistoricalData()
# Load data for each timeframe
success_count = 0
for tf in self.timeframes:
if tf != "1s": # Skip 1s since we'll generate it from ticks
try:
logger.info(f"Fetching {tf} candles for {symbol}...")
df = historical_data.get_historical_candles(symbol, self._timeframe_to_seconds(tf), limit)
if df is not None and not df.empty:
logger.info(f"Loaded {len(df)} {tf} candles from Binance API")
@ -1334,15 +1356,23 @@ class TickStorage:
candles.append(candle)
# Also save to TimescaleDB if enabled
if self.use_timescaledb:
if self.use_timescaledb and timescaledb_handler and timescaledb_handler.enabled:
timescaledb_handler.upsert_candle(symbol, tf, candle)
self.candles[tf] = candles
success_count += 1
else:
logger.warning(f"No data returned for {tf} candles")
except Exception as e:
logger.error(f"Error loading {tf} candles: {str(e)}")
import traceback
logger.error(traceback.format_exc())
logger.info(f"Successfully loaded {success_count} timeframes from Binance API")
# For 1s, load from API if possible or compute from first available timeframe
if "1s" in self.timeframes:
logger.info("Loading 1s candles...")
# Try to get 1s data from Binance
try:
df_1s = historical_data.get_historical_candles(symbol, 1, 300) # Only need recent 1s data
@ -1363,7 +1393,7 @@ class TickStorage:
candles_1s.append(candle)
# Also save to TimescaleDB if enabled
if self.use_timescaledb:
if self.use_timescaledb and timescaledb_handler and timescaledb_handler.enabled:
timescaledb_handler.upsert_candle(symbol, "1s", candle)
self.candles["1s"] = candles_1s
@ -1372,6 +1402,7 @@ class TickStorage:
# If 1s data not available or failed to load, approximate from 1m data
if not self.candles.get("1s"):
logger.info("1s data not available, trying to approximate from 1m data...")
# If 1s data not available, we can approximate from 1m data
if "1m" in self.timeframes and self.candles["1m"]:
# For demonstration, just use the 1m candles as placeholders for 1s
@ -1381,6 +1412,7 @@ class TickStorage:
# Take the most recent 5 minutes of 1m candles
recent_1m = self.candles["1m"][-5:] if self.candles["1m"] else []
logger.info(f"Creating 1s approximations from {len(recent_1m)} 1m candles")
for candle_1m in recent_1m:
# Create 60 1s candles for each 1m candle
ts_base = candle_1m["timestamp"].timestamp()
@ -1397,17 +1429,23 @@ class TickStorage:
self.candles["1s"].append(candle_1s)
# Also save to TimescaleDB if enabled
if self.use_timescaledb:
if self.use_timescaledb and timescaledb_handler and timescaledb_handler.enabled:
timescaledb_handler.upsert_candle(symbol, "1s", candle_1s)
logger.info(f"Created {len(self.candles['1s'])} approximated 1s candles")
else:
logger.warning("No 1m data available to approximate 1s candles from")
# Set the last candle of each timeframe as the current candle
for tf in self.timeframes:
if self.candles[tf]:
self.current_candle[tf] = self.candles[tf][-1].copy()
self.last_candle_timestamp[tf] = self.current_candle[tf]["timestamp"]
logger.debug(f"Set current candle for {tf}: {self.current_candle[tf]['timestamp']}")
# If we loaded ticks from cache, rebuild candles
if cache_loaded:
logger.info("Rebuilding candles from cached ticks...")
# Clear candles
self.candles = {tf: [] for tf in self.timeframes}
self.current_candle = {tf: None for tf in self.timeframes}
@ -1419,8 +1457,17 @@ class TickStorage:
self._update_1s_candle(tick)
else:
self._update_candles_for_timeframe(tf, tick)
logger.info("Finished rebuilding candles from ticks")
return cache_loaded or (self.candles["1m"] if "1m" in self.candles else False)
# Log final results
for tf in self.timeframes:
count = len(self.candles[tf])
logger.info(f"Final {tf} candle count: {count}")
has_data = cache_loaded or any(self.candles[tf] for tf in self.timeframes)
logger.info(f"Historical data loading completed. Has data: {has_data}")
return has_data
def _try_cache_ticks(self):
"""Try to save ticks to cache periodically"""
@ -1561,6 +1608,11 @@ class RealTimeChart:
self.trades_per_minute = 0
self.trades_per_hour = 0
# Initialize trade rate tracking variables
self.trade_times = [] # Store timestamps of recent trades for rate calculation
self.last_trade_rate_calculation = datetime.now()
self.trade_rate = {"per_second": 0, "per_minute": 0, "per_hour": 0}
# Initialize interactive components
self.app = app
@ -1583,6 +1635,23 @@ class RealTimeChart:
timeframes=["1s", "1m", "5m", "15m", "1h", "4h", "1d"],
use_timescaledb=use_timescaledb
)
# Load historical data immediately for cold start
logger.info(f"Loading historical data for {symbol} during chart initialization")
try:
data_loaded = self.tick_storage.load_historical_data(symbol)
if data_loaded:
logger.info(f"Successfully loaded historical data for {symbol}")
# Log what we have
for tf in ["1s", "1m", "5m", "15m", "1h"]:
candle_count = len(self.tick_storage.candles.get(tf, []))
logger.info(f" {tf}: {candle_count} candles")
else:
logger.warning(f"Failed to load historical data for {symbol}")
except Exception as e:
logger.error(f"Error loading historical data during initialization: {str(e)}")
import traceback
logger.error(traceback.format_exc())
else:
self.tick_storage = tick_storage
@ -1592,7 +1661,7 @@ class RealTimeChart:
self.app.layout = self._create_layout()
# Register callbacks
self._register_callbacks()
self._setup_callbacks()
# Log initialization
if self.enable_logging:
@ -1653,13 +1722,10 @@ class RealTimeChart:
# Store for the selected timeframe
dcc.Store(id='interval-store', data={'interval': 1}),
# Chart content container that will be updated by callbacks
html.Div(id='chart-content', children=[
# Initial content
dcc.Graph(id='live-chart', style={"height": "600px"}),
dcc.Graph(id='secondary-charts', style={"height": "500px"}),
html.Div(id='positions-list')
])
# Chart content (without wrapper div to avoid callback issues)
dcc.Graph(id='live-chart', style={"height": "600px"}),
dcc.Graph(id='secondary-charts', style={"height": "500px"}),
html.Div(id='positions-list')
])
def _create_chart_and_controls(self):
@ -2016,26 +2082,20 @@ class RealTimeChart:
try:
# Get candles from tick storage
interval_key = self._get_interval_key(interval_seconds)
df = self.tick_storage.get_candles(interval_key)
candles_list = self.tick_storage.get_candles(interval_key)
if df is None or df.empty:
logger.warning(f"No candle data available for {interval_key}")
return [] # Return empty list if no data
if not candles_list:
logger.warning(f"No candle data available for {interval_key} - trying to load historical data")
# Try to load historical data if we don't have any
self.tick_storage.load_historical_data(self.symbol)
candles_list = self.tick_storage.get_candles(interval_key)
# Convert dataframe to list of dictionaries
candles = []
for idx, row in df.iterrows():
candle = {
'timestamp': idx,
'open': row['open'],
'high': row['high'],
'low': row['low'],
'close': row['close'],
'volume': row['volume']
}
candles.append(candle)
if not candles_list:
logger.error(f"Still no candle data available for {interval_key} after loading historical data")
return []
return candles
logger.info(f"Retrieved {len(candles_list)} candles for {interval_key}")
return candles_list
except Exception as e:
logger.error(f"Error getting candles: {str(e)}")
@ -2197,7 +2257,11 @@ class RealTimeChart:
def run(self, host='localhost', port=8050):
"""Run the Dash app on the specified host and port"""
try:
logger.info(f"Starting Dash app for {self.symbol} on {host}:{port}")
logger.info("="*60)
logger.info(f"🚀 STARTING WEB UI FOR {self.symbol}")
logger.info(f"📱 Web interface available at: http://{host}:{port}/")
logger.info(f"🌐 Open this URL in your browser to view the trading chart")
logger.info("="*60)
self.app.run(debug=False, use_reloader=False, host=host, port=port)
except Exception as e:
logger.error(f"Error running Dash app: {str(e)}")
@ -2253,6 +2317,166 @@ class RealTimeChart:
# Placeholder for adding NN signals if needed in the future
pass
def _update_main_chart(self, interval_seconds):
"""Update the main chart for the specified interval"""
try:
# Convert interval seconds to timeframe key
interval_key = self._get_interval_key(interval_seconds)
# Get candles for this timeframe
if interval_key not in self.tick_storage.candles or not self.tick_storage.candles[interval_key]:
logger.warning(f"No candle data available for {interval_key}")
# Return empty figure with a message
fig = go.Figure()
fig.add_annotation(
text=f"No data available for {interval_key}",
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False,
font=dict(size=20, color="white")
)
fig.update_layout(
template="plotly_dark",
height=600,
title=f"{self.symbol} - {interval_key} Chart",
xaxis_title="Time",
yaxis_title="Price ($)"
)
return fig
# Get candles (limit to last 500 for performance)
candles = self.tick_storage.candles[interval_key][-500:]
if not candles:
# Return empty figure if no candles
fig = go.Figure()
fig.add_annotation(
text=f"No candles available for {interval_key}",
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False,
font=dict(size=20, color="white")
)
fig.update_layout(
template="plotly_dark",
height=600,
title=f"{self.symbol} - {interval_key} Chart"
)
return fig
# Extract OHLC values
timestamps = [candle['timestamp'] for candle in candles]
opens = [candle['open'] for candle in candles]
highs = [candle['high'] for candle in candles]
lows = [candle['low'] for candle in candles]
closes = [candle['close'] for candle in candles]
volumes = [candle['volume'] for candle in candles]
# Create the main figure
fig = go.Figure()
# Add candlestick trace
fig.add_trace(go.Candlestick(
x=timestamps,
open=opens,
high=highs,
low=lows,
close=closes,
name=f"{self.symbol}",
increasing_line_color='rgba(0, 200, 0, 0.8)',
decreasing_line_color='rgba(255, 0, 0, 0.8)',
increasing_fillcolor='rgba(0, 200, 0, 0.3)',
decreasing_fillcolor='rgba(255, 0, 0, 0.3)'
))
# Add trade markers if we have positions
if hasattr(self, 'positions') and self.positions:
# Get recent positions (last 50 to avoid clutter)
recent_positions = self.positions[-50:] if len(self.positions) > 50 else self.positions
for position in recent_positions:
# Add entry marker
fig.add_trace(go.Scatter(
x=[position.entry_timestamp],
y=[position.entry_price],
mode='markers',
marker=dict(
symbol='triangle-up' if position.action == 'BUY' else 'triangle-down',
size=12,
color='green' if position.action == 'BUY' else 'red',
line=dict(width=2, color='white')
),
name=f"{position.action} Entry",
hovertemplate=f"<b>{position.action} Entry</b><br>" +
f"Price: ${position.entry_price:.2f}<br>" +
f"Time: {position.entry_timestamp}<br>" +
f"ID: {position.trade_id}<extra></extra>",
showlegend=False
))
# Add exit marker if position is closed
if not position.is_open and position.exit_price and position.exit_timestamp:
fig.add_trace(go.Scatter(
x=[position.exit_timestamp],
y=[position.exit_price],
mode='markers',
marker=dict(
symbol='triangle-down' if position.action == 'BUY' else 'triangle-up',
size=12,
color='blue',
line=dict(width=2, color='white')
),
name=f"{position.action} Exit",
hovertemplate=f"<b>{position.action} Exit</b><br>" +
f"Price: ${position.exit_price:.2f}<br>" +
f"Time: {position.exit_timestamp}<br>" +
f"PnL: ${position.pnl:.2f}<br>" +
f"ID: {position.trade_id}<extra></extra>",
showlegend=False
))
# Update layout
fig.update_layout(
template="plotly_dark",
height=600,
title=f"{self.symbol} - {interval_key} Chart (Live Trading)",
xaxis_title="Time",
yaxis_title="Price ($)",
showlegend=True,
margin=dict(l=0, r=0, t=40, b=0),
xaxis_rangeslider_visible=False,
hovermode='x unified'
)
# Format Y-axis with appropriate decimal places
fig.update_yaxes(tickformat=".2f")
# Format X-axis
fig.update_xaxes(
rangeslider_visible=False,
type='date'
)
return fig
except Exception as e:
logger.error(f"Error updating main chart: {str(e)}")
import traceback
logger.error(traceback.format_exc())
# Return error figure
fig = go.Figure()
fig.add_annotation(
text=f"Error loading chart: {str(e)}",
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False,
font=dict(size=16, color="red")
)
fig.update_layout(
template="plotly_dark",
height=600,
title=f"{self.symbol} Chart - Error"
)
return fig
class BinanceWebSocket:
"""Binance WebSocket implementation for real-time tick data"""
def __init__(self, symbol: str):

View File

@ -696857,3 +696857,124 @@ ade'}
2025-03-19 00:09:56,964 - INFO - [_internal.py:97] - 127.0.0.1 - - [19/Mar/2025 00:09:56] "POST /_dash-update-component HTTP/1.1" 200 -
2025-03-19 00:09:57,070 - DEBUG - [realtime.py:233] - Retrieved 965 ticks from time range 1742335497069 to None
2025-03-19 00:09:57,071 - DEBUG - [protocol.py:1177] - < PING '1742335799715' [text, 13 bytes]
2025-05-24 01:14:38,311 - INFO - [dataprovider_realtime.py:978] - Detected local timezone: Europe/Kiev (Europe/Kiev)
2025-05-24 01:14:38,654 - INFO - [test_chart_data.py:111] - ============================================================
2025-05-24 01:14:38,655 - INFO - [test_chart_data.py:122] - ----------------------------------------
2025-05-24 01:14:38,656 - INFO - [test_chart_data.py:21] - Testing Binance historical data fetch...
2025-05-24 01:14:38,671 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv
2025-05-24 01:14:39,101 - INFO - [dataprovider_realtime.py:348] - Saved 100 candles to cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv
2025-05-24 01:14:39,101 - INFO - [dataprovider_realtime.py:305] - Fetched 100 candles for ETH/USDT (1m)
2025-05-24 01:14:39,104 - INFO - [test_chart_data.py:31] - Latest price: $2556.22
2025-05-24 01:14:39,104 - INFO - [test_chart_data.py:32] - Date range: 2025-05-23 20:35:00 to 2025-05-23 22:14:00
2025-05-24 01:14:39,106 - INFO - [test_chart_data.py:122] - ----------------------------------------
2025-05-24 01:14:39,106 - INFO - [test_chart_data.py:44] - Testing TickStorage data loading...
2025-05-24 01:14:39,107 - INFO - [dataprovider_realtime.py:1027] - Creating new tick storage for ETH/USDT with timeframes ['1s', '1m', '5m', '1h']
2025-05-24 01:14:39,107 - INFO - [dataprovider_realtime.py:1028] - Cache directory: F:\projects\gogo2\cache\ETHUSDT
2025-05-24 01:14:39,107 - INFO - [dataprovider_realtime.py:1029] - Cache file: F:\projects\gogo2\cache\ETHUSDT\ETHUSDT_ticks.json
2025-05-24 01:14:39,107 - INFO - [dataprovider_realtime.py:1034] - TickStorage: TimescaleDB integration is DISABLED for ETH/USDT
2025-05-24 01:14:39,108 - INFO - [dataprovider_realtime.py:1290] - Starting historical data load for ETH/USDT with limit 100
2025-05-24 01:14:39,108 - INFO - [dataprovider_realtime.py:1298] - Attempting to load from cache...
2025-05-24 01:14:39,115 - ERROR - [dataprovider_realtime.py:1064] - Error loading ticks from cache: Expecting value: line 1 column 52 (char 51)
2025-05-24 01:14:39,115 - INFO - [dataprovider_realtime.py:1303] - No valid cache data found
2025-05-24 01:14:39,116 - INFO - [dataprovider_realtime.py:1327] - TimescaleDB not available or disabled
2025-05-24 01:14:39,116 - INFO - [dataprovider_realtime.py:1331] - Loading data from Binance API...
2025-05-24 01:14:39,116 - INFO - [dataprovider_realtime.py:1340] - Fetching 1m candles for ETH/USDT...
2025-05-24 01:14:39,131 - INFO - [dataprovider_realtime.py:337] - Loaded 100 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv
2025-05-24 01:14:39,583 - INFO - [dataprovider_realtime.py:348] - Saved 100 candles to cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv
2025-05-24 01:14:39,583 - INFO - [dataprovider_realtime.py:305] - Fetched 100 candles for ETH/USDT (1m)
2025-05-24 01:14:39,583 - INFO - [dataprovider_realtime.py:1343] - Loaded 100 1m candles from Binance API
2025-05-24 01:14:39,589 - INFO - [dataprovider_realtime.py:1340] - Fetching 5m candles for ETH/USDT...
2025-05-24 01:14:39,601 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_5m_candles.csv
2025-05-24 01:14:39,602 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (5m)
2025-05-24 01:14:39,602 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 5m candles from Binance API
2025-05-24 01:14:39,642 - INFO - [dataprovider_realtime.py:1340] - Fetching 1h candles for ETH/USDT...
2025-05-24 01:14:39,656 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1h_candles.csv
2025-05-24 01:14:39,656 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1h)
2025-05-24 01:14:39,656 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 1h candles from Binance API
2025-05-24 01:14:39,683 - INFO - [dataprovider_realtime.py:1371] - Successfully loaded 3 timeframes from Binance API
2025-05-24 01:14:39,684 - INFO - [dataprovider_realtime.py:1375] - Loading 1s candles...
2025-05-24 01:14:39,684 - INFO - [dataprovider_realtime.py:333] - Using recent 1s cache (age: 1.0 minutes)
2025-05-24 01:14:39,687 - INFO - [dataprovider_realtime.py:337] - Loaded 300 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1s_candles.csv
2025-05-24 01:14:39,687 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1s)
2025-05-24 01:14:39,687 - INFO - [dataprovider_realtime.py:1380] - Loaded 300 recent 1s candles from Binance API
2025-05-24 01:14:39,695 - INFO - [dataprovider_realtime.py:1466] - Final 1s candle count: 300
2025-05-24 01:14:39,695 - INFO - [dataprovider_realtime.py:1466] - Final 1m candle count: 100
2025-05-24 01:14:39,695 - INFO - [dataprovider_realtime.py:1466] - Final 5m candle count: 1000
2025-05-24 01:14:39,695 - INFO - [dataprovider_realtime.py:1466] - Final 1h candle count: 1000
2025-05-24 01:14:39,696 - INFO - [dataprovider_realtime.py:1469] - Historical data loading completed. Has data: True
2025-05-24 01:14:39,697 - INFO - [test_chart_data.py:59] - 1s: 300 candles
2025-05-24 01:14:39,697 - INFO - [test_chart_data.py:63] - Latest 1s: 2025-05-23 22:13:36 - $2549.36
2025-05-24 01:14:39,697 - INFO - [test_chart_data.py:59] - 1m: 100 candles
2025-05-24 01:14:39,697 - INFO - [test_chart_data.py:63] - Latest 1m: 2025-05-23 22:14:00 - $2556.22
2025-05-24 01:14:39,699 - INFO - [test_chart_data.py:59] - 5m: 1000 candles
2025-05-24 01:14:39,699 - INFO - [test_chart_data.py:63] - Latest 5m: 2025-05-23 22:10:00 - $2549.69
2025-05-24 01:14:39,699 - INFO - [test_chart_data.py:59] - 1h: 1000 candles
2025-05-24 01:14:39,699 - INFO - [test_chart_data.py:63] - Latest 1h: 2025-05-23 22:00:00 - $2549.84
2025-05-24 01:14:39,700 - INFO - [test_chart_data.py:122] - ----------------------------------------
2025-05-24 01:14:39,700 - INFO - [test_chart_data.py:78] - Testing RealTimeChart initialization...
2025-05-24 01:14:39,701 - INFO - [dataprovider_realtime.py:1027] - Creating new tick storage for ETH/USDT with timeframes ['1s', '1m', '5m', '15m', '1h', '4h', '1d']
2025-05-24 01:14:39,701 - INFO - [dataprovider_realtime.py:1028] - Cache directory: F:\projects\gogo2\cache\ETHUSDT
2025-05-24 01:14:39,701 - INFO - [dataprovider_realtime.py:1029] - Cache file: F:\projects\gogo2\cache\ETHUSDT\ETHUSDT_ticks.json
2025-05-24 01:14:39,701 - INFO - [dataprovider_realtime.py:1640] - Loading historical data for ETH/USDT during chart initialization
2025-05-24 01:14:39,702 - INFO - [dataprovider_realtime.py:1290] - Starting historical data load for ETH/USDT with limit 1000
2025-05-24 01:14:39,702 - INFO - [dataprovider_realtime.py:1298] - Attempting to load from cache...
2025-05-24 01:14:39,710 - ERROR - [dataprovider_realtime.py:1064] - Error loading ticks from cache: Expecting value: line 1 column 53 (char 52)
2025-05-24 01:14:39,710 - INFO - [dataprovider_realtime.py:1303] - No valid cache data found
2025-05-24 01:14:39,710 - INFO - [dataprovider_realtime.py:1327] - TimescaleDB not available or disabled
2025-05-24 01:14:39,711 - INFO - [dataprovider_realtime.py:1331] - Loading data from Binance API...
2025-05-24 01:14:39,711 - INFO - [dataprovider_realtime.py:1340] - Fetching 1m candles for ETH/USDT...
2025-05-24 01:14:39,721 - INFO - [dataprovider_realtime.py:337] - Loaded 100 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv
2025-05-24 01:14:40,243 - INFO - [dataprovider_realtime.py:348] - Saved 1000 candles to cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv
2025-05-24 01:14:40,244 - INFO - [dataprovider_realtime.py:305] - Fetched 1000 candles for ETH/USDT (1m)
2025-05-24 01:14:40,244 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 1m candles from Binance API
2025-05-24 01:14:40,271 - INFO - [dataprovider_realtime.py:1340] - Fetching 5m candles for ETH/USDT...
2025-05-24 01:14:40,274 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_5m_candles.csv
2025-05-24 01:14:40,275 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (5m)
2025-05-24 01:14:40,275 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 5m candles from Binance API
2025-05-24 01:14:40,300 - INFO - [dataprovider_realtime.py:1340] - Fetching 15m candles for ETH/USDT...
2025-05-24 01:14:40,321 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_15m_candles.csv
2025-05-24 01:14:40,322 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (15m)
2025-05-24 01:14:40,322 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 15m candles from Binance API
2025-05-24 01:14:40,348 - INFO - [dataprovider_realtime.py:1340] - Fetching 1h candles for ETH/USDT...
2025-05-24 01:14:40,353 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1h_candles.csv
2025-05-24 01:14:40,353 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1h)
2025-05-24 01:14:40,354 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 1h candles from Binance API
2025-05-24 01:14:40,379 - INFO - [dataprovider_realtime.py:1340] - Fetching 4h candles for ETH/USDT...
2025-05-24 01:14:40,383 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_4h_candles.csv
2025-05-24 01:14:40,384 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (4h)
2025-05-24 01:14:40,384 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 4h candles from Binance API
2025-05-24 01:14:40,409 - INFO - [dataprovider_realtime.py:1340] - Fetching 1d candles for ETH/USDT...
2025-05-24 01:14:40,412 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1d_candles.csv
2025-05-24 01:14:40,412 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1d)
2025-05-24 01:14:40,412 - INFO - [dataprovider_realtime.py:1343] - Loaded 1000 1d candles from Binance API
2025-05-24 01:14:40,439 - INFO - [dataprovider_realtime.py:1371] - Successfully loaded 6 timeframes from Binance API
2025-05-24 01:14:40,439 - INFO - [dataprovider_realtime.py:1375] - Loading 1s candles...
2025-05-24 01:14:40,439 - INFO - [dataprovider_realtime.py:333] - Using recent 1s cache (age: 1.1 minutes)
2025-05-24 01:14:40,442 - INFO - [dataprovider_realtime.py:337] - Loaded 300 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1s_candles.csv
2025-05-24 01:14:40,442 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1s)
2025-05-24 01:14:40,443 - INFO - [dataprovider_realtime.py:1380] - Loaded 300 recent 1s candles from Binance API
2025-05-24 01:14:40,450 - INFO - [dataprovider_realtime.py:1466] - Final 1s candle count: 300
2025-05-24 01:14:40,450 - INFO - [dataprovider_realtime.py:1466] - Final 1m candle count: 1000
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1466] - Final 5m candle count: 1000
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1466] - Final 15m candle count: 1000
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1466] - Final 1h candle count: 1000
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1466] - Final 4h candle count: 1000
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1466] - Final 1d candle count: 1000
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1469] - Historical data loading completed. Has data: True
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1644] - Successfully loaded historical data for ETH/USDT
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1648] - 1s: 300 candles
2025-05-24 01:14:40,451 - INFO - [dataprovider_realtime.py:1648] - 1m: 1000 candles
2025-05-24 01:14:40,452 - INFO - [dataprovider_realtime.py:1648] - 5m: 1000 candles
2025-05-24 01:14:40,452 - INFO - [dataprovider_realtime.py:1648] - 15m: 1000 candles
2025-05-24 01:14:40,452 - INFO - [dataprovider_realtime.py:1648] - 1h: 1000 candles
2025-05-24 01:14:40,452 - INFO - [dataprovider_realtime.py:1668] - RealTimeChart initialized: ETH/USDT (1m)
2025-05-24 01:14:40,452 - INFO - [dataprovider_realtime.py:2097] - Retrieved 300 candles for 1s
2025-05-24 01:14:40,453 - INFO - [dataprovider_realtime.py:2097] - Retrieved 1000 candles for 1m
2025-05-24 01:14:40,454 - INFO - [test_chart_data.py:93] - 1s candles: 300
2025-05-24 01:14:40,454 - INFO - [test_chart_data.py:94] - 1m candles: 1000
2025-05-24 01:14:40,454 - INFO - [test_chart_data.py:98] - Latest 1m candle: 2025-05-23 22:14:00 - $2556.00
2025-05-24 01:14:40,455 - INFO - [test_chart_data.py:131] -
============================================================
2025-05-24 01:14:40,456 - INFO - [test_chart_data.py:133] - ============================================================
2025-05-24 01:14:40,459 - INFO - [test_chart_data.py:142] -
Passed: 3/3 tests

153
test_chart_data.py Normal file
View File

@ -0,0 +1,153 @@
#!/usr/bin/env python3
"""
Test script to verify chart data loading functionality
"""
import logging
import sys
import os
# Add the project root to the path
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from dataprovider_realtime import RealTimeChart, TickStorage, BinanceHistoricalData
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def test_binance_data_fetch():
"""Test fetching data from Binance API"""
logger.info("Testing Binance historical data fetch...")
try:
binance_data = BinanceHistoricalData()
# Test fetching 1m data for ETH/USDT
df = binance_data.get_historical_candles("ETH/USDT", 60, 100)
if df is not None and not df.empty:
logger.info(f"✅ Successfully fetched {len(df)} 1m candles")
logger.info(f" Latest price: ${df.iloc[-1]['close']:.2f}")
logger.info(f" Date range: {df.iloc[0]['timestamp']} to {df.iloc[-1]['timestamp']}")
return True
else:
logger.error("❌ Failed to fetch Binance data")
return False
except Exception as e:
logger.error(f"❌ Error fetching Binance data: {str(e)}")
return False
def test_tick_storage():
"""Test TickStorage data loading"""
logger.info("Testing TickStorage data loading...")
try:
# Create tick storage
tick_storage = TickStorage("ETH/USDT", ["1s", "1m", "5m", "1h"])
# Load historical data
success = tick_storage.load_historical_data("ETH/USDT", limit=100)
if success:
logger.info("✅ TickStorage data loading successful")
# Check what we have
for tf in ["1s", "1m", "5m", "1h"]:
candles = tick_storage.get_candles(tf)
logger.info(f" {tf}: {len(candles)} candles")
if candles:
latest = candles[-1]
logger.info(f" Latest {tf}: {latest['timestamp']} - ${latest['close']:.2f}")
return True
else:
logger.error("❌ TickStorage data loading failed")
return False
except Exception as e:
logger.error(f"❌ Error in TickStorage: {str(e)}")
import traceback
logger.error(traceback.format_exc())
return False
def test_chart_initialization():
"""Test RealTimeChart initialization and data loading"""
logger.info("Testing RealTimeChart initialization...")
try:
# Create chart (without app to avoid GUI issues)
chart = RealTimeChart(
app=None,
symbol="ETH/USDT",
standalone=False
)
# Test getting candles
candles_1s = chart.get_candles(1) # 1 second
candles_1m = chart.get_candles(60) # 1 minute
logger.info(f"✅ Chart initialized successfully")
logger.info(f" 1s candles: {len(candles_1s)}")
logger.info(f" 1m candles: {len(candles_1m)}")
if candles_1m:
latest = candles_1m[-1]
logger.info(f" Latest 1m candle: {latest['timestamp']} - ${latest['close']:.2f}")
return len(candles_1s) > 0 or len(candles_1m) > 0
except Exception as e:
logger.error(f"❌ Error in chart initialization: {str(e)}")
import traceback
logger.error(traceback.format_exc())
return False
def main():
"""Run all tests"""
logger.info("🧪 Starting chart data loading tests...")
logger.info("=" * 60)
tests = [
("Binance API fetch", test_binance_data_fetch),
("TickStorage loading", test_tick_storage),
("Chart initialization", test_chart_initialization)
]
results = []
for test_name, test_func in tests:
logger.info(f"\n📋 Running test: {test_name}")
logger.info("-" * 40)
try:
result = test_func()
results.append((test_name, result))
except Exception as e:
logger.error(f"❌ Test {test_name} crashed: {str(e)}")
results.append((test_name, False))
# Print summary
logger.info("\n" + "=" * 60)
logger.info("📊 TEST RESULTS SUMMARY")
logger.info("=" * 60)
passed = 0
for test_name, result in results:
status = "✅ PASS" if result else "❌ FAIL"
logger.info(f"{status}: {test_name}")
if result:
passed += 1
logger.info(f"\nPassed: {passed}/{len(results)} tests")
if passed == len(results):
logger.info("🎉 All tests passed! Chart data loading is working correctly.")
return True
else:
logger.warning(f"⚠️ {len(results) - passed} test(s) failed. Please check the issues above.")
return False
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)

View File

@ -1089,8 +1089,11 @@ async def start_realtime_chart(symbol="ETH/USDT", port=8050, manual_mode=False):
logger.info("Enabling manual trading mode")
logger.warning("Manual trading mode not supported by this simplified chart implementation")
logger.info(f"Started realtime chart for {symbol} on port {port}")
logger.info(f"You can view the chart at http://localhost:{port}/")
logger.info("="*60)
logger.info(f"✅ REALTIME CHART READY FOR {symbol}")
logger.info(f"🔗 ACCESS WEB UI AT: http://localhost:{port}/")
logger.info(f"📊 View live trading data and charts in your browser")
logger.info("="*60)
# Start websocket in the background
websocket_task = asyncio.create_task(chart.start_websocket())