diff --git a/realtime.py b/realtime.py index df41f6b..d179254 100644 --- a/realtime.py +++ b/realtime.py @@ -524,6 +524,68 @@ class ExchangeWebSocket: """Check if the WebSocket is running""" return self.ws.running if self.ws else False +class CandleCache: + def __init__(self, max_candles: int = 2000): + self.candles = { + '1s': deque(maxlen=max_candles), + '1m': deque(maxlen=max_candles), + '1h': deque(maxlen=max_candles), + '1d': deque(maxlen=max_candles) + } + logger.info("Initialized CandleCache with max candles: {}".format(max_candles)) + + def add_candles(self, interval: str, new_candles: pd.DataFrame): + if interval in self.candles and not new_candles.empty: + for _, row in new_candles.iterrows(): + self.candles[interval].append(row) + logger.debug(f"Added {len(new_candles)} candles to {interval} cache") + + def get_recent_candles(self, interval: str, count: int = 500) -> pd.DataFrame: + if interval in self.candles and self.candles[interval]: + recent_candles = list(self.candles[interval])[-count:] + return pd.DataFrame(recent_candles) + return pd.DataFrame() + + def update_cache(self, interval: str, new_candles: pd.DataFrame): + if interval not in self.candles: + logger.warning(f"Invalid interval {interval} for cache update") + return + + if new_candles.empty: + logger.debug(f"No new candles to update {interval} cache") + return + + # Check if timestamp column exists + if 'timestamp' not in new_candles.columns: + logger.warning(f"No timestamp column in new candles for {interval}") + return + + last_cached_time = None + if self.candles[interval]: + try: + # Get the timestamp from the last cached candle + last_cached_candle = self.candles[interval][-1] + if isinstance(last_cached_candle, dict) and 'timestamp' in last_cached_candle: + last_cached_time = last_cached_candle['timestamp'] + logger.debug(f"Last cached timestamp for {interval}: {last_cached_time}") + except (IndexError, KeyError) as e: + logger.error(f"Error accessing timestamp from last cached candle: {e}") + + try: + # Only filter if we have a valid last_cached_time + if last_cached_time is not None: + filtered_candles = new_candles[new_candles['timestamp'] > last_cached_time] + logger.debug(f"Filtered {len(filtered_candles)} new candles for {interval}") + self.add_candles(interval, filtered_candles) + else: + # If no previous candles, add all + logger.debug(f"No previous candles, adding all {len(new_candles)} candles to {interval} cache") + self.add_candles(interval, new_candles) + except Exception as e: + logger.error(f"Error updating cache for {interval}: {str(e)}") + import traceback + logger.error(traceback.format_exc()) + class RealTimeChart: def __init__(self, symbol: str): self.symbol = symbol @@ -536,8 +598,13 @@ class RealTimeChart: '1h': None, '1d': None } + self.candle_cache = CandleCache() # Initialize local candle cache logger.info(f"Initializing RealTimeChart for {symbol}") - + + # We'll populate the cache as data comes in rather than trying to load on startup + # when there might not be any ticks available yet + logger.info(f"Cache will be populated as data becomes available for {symbol}") + # Button style button_style = { 'background-color': '#4CAF50', @@ -794,8 +861,16 @@ class RealTimeChart: # Fetch and cache OHLCV data for different intervals for interval_key in self.ohlcv_cache.keys(): - if self.ohlcv_cache[interval_key] is None: - self.ohlcv_cache[interval_key] = self.tick_storage.get_candles(interval_seconds=self._interval_to_seconds(interval_key)) + try: + new_candles = self.tick_storage.get_candles(interval_seconds=self._interval_to_seconds(interval_key)) + if not new_candles.empty: + # Update the cache with new candles + self.candle_cache.update_cache(interval_key, new_candles) + # Get the updated candles from cache for display + self.ohlcv_cache[interval_key] = self.candle_cache.get_recent_candles(interval_key) + logger.debug(f"Updated cache for {interval_key}, now has {len(self.ohlcv_cache[interval_key])} candles") + except Exception as e: + logger.error(f"Error updating cache for {interval_key}: {str(e)}") # Add OHLCV subcharts for i, (interval_key, ohlcv_df) in enumerate(self.ohlcv_cache.items(), start=3):