diff --git a/NN/utils/__pycache__/data_interface.cpython-312.pyc b/NN/utils/__pycache__/data_interface.cpython-312.pyc
index d70ac63..5c90249 100644
Binary files a/NN/utils/__pycache__/data_interface.cpython-312.pyc and b/NN/utils/__pycache__/data_interface.cpython-312.pyc differ
diff --git a/dataprovider_realtime.py b/dataprovider_realtime.py
index 60fc471..311f494 100644
--- a/dataprovider_realtime.py
+++ b/dataprovider_realtime.py
@@ -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"{position.action} Entry
" +
+ f"Price: ${position.entry_price:.2f}
" +
+ f"Time: {position.entry_timestamp}
" +
+ f"ID: {position.trade_id}",
+ 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"{position.action} Exit
" +
+ f"Price: ${position.exit_price:.2f}
" +
+ f"Time: {position.exit_timestamp}
" +
+ f"PnL: ${position.pnl:.2f}
" +
+ f"ID: {position.trade_id}",
+ 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):
diff --git a/realtime_chart.log b/realtime_chart.log
index 3f26b0e..48ae714 100644
--- a/realtime_chart.log
+++ b/realtime_chart.log
@@ -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
diff --git a/test_chart_data.py b/test_chart_data.py
new file mode 100644
index 0000000..51e3b82
--- /dev/null
+++ b/test_chart_data.py
@@ -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)
\ No newline at end of file
diff --git a/train_rl_with_realtime.py b/train_rl_with_realtime.py
index dadd9ac..8073bf9 100644
--- a/train_rl_with_realtime.py
+++ b/train_rl_with_realtime.py
@@ -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())