diff --git a/dataprovider_realtime.py b/dataprovider_realtime.py index 311f494..0665031 100644 --- a/dataprovider_realtime.py +++ b/dataprovider_realtime.py @@ -1038,8 +1038,23 @@ class TickStorage: try: # Only save the latest 5000 ticks to avoid giant files ticks_to_save = self.ticks[-5000:] if len(self.ticks) > 5000 else self.ticks + + # Convert pandas Timestamps to ISO strings for JSON serialization + serializable_ticks = [] + for tick in ticks_to_save: + serializable_tick = tick.copy() + if isinstance(tick['timestamp'], pd.Timestamp): + serializable_tick['timestamp'] = tick['timestamp'].isoformat() + elif hasattr(tick['timestamp'], 'isoformat'): + serializable_tick['timestamp'] = tick['timestamp'].isoformat() + else: + # Keep as is if it's already a string or number + serializable_tick['timestamp'] = tick['timestamp'] + serializable_ticks.append(serializable_tick) + with open(self.cache_path, 'w') as f: - json.dump(ticks_to_save, f) + json.dump(serializable_ticks, f) + logger.debug(f"Saved {len(serializable_ticks)} ticks to cache") except Exception as e: logger.error(f"Error saving ticks to cache: {e}") @@ -1057,7 +1072,22 @@ class TickStorage: cached_ticks = json.load(f) if cached_ticks: - self.ticks = cached_ticks + # Convert ISO strings back to pandas Timestamps + processed_ticks = [] + for tick in cached_ticks: + processed_tick = tick.copy() + if isinstance(tick['timestamp'], str): + try: + processed_tick['timestamp'] = pd.Timestamp(tick['timestamp']) + except: + # If parsing fails, use current time + processed_tick['timestamp'] = pd.Timestamp.now() + else: + # Convert to pandas Timestamp if it's a number (milliseconds) + processed_tick['timestamp'] = pd.Timestamp(tick['timestamp'], unit='ms') + processed_ticks.append(processed_tick) + + self.ticks = processed_ticks logger.info(f"Loaded {len(cached_ticks)} ticks from cache") return True except Exception as e: @@ -1088,11 +1118,20 @@ class TickStorage: else: logger.error("Invalid tick: must provide either a tick dict or price") return + + # Ensure timestamp is a pandas Timestamp + if not isinstance(timestamp, pd.Timestamp): + if isinstance(timestamp, (int, float)): + # Assume it's milliseconds + timestamp = pd.Timestamp(timestamp, unit='ms') + else: + # Try to parse as string or datetime + timestamp = pd.Timestamp(timestamp) - # Create tick object + # Create tick object with consistent pandas Timestamp tick_obj = { - 'price': price, - 'quantity': volume if volume is not None else 0, + 'price': float(price), + 'quantity': float(volume) if volume is not None else 0.0, 'timestamp': timestamp } @@ -1473,7 +1512,13 @@ class TickStorage: """Try to save ticks to cache periodically""" # Only save to cache every 100 ticks to avoid excessive disk I/O if len(self.ticks) % 100 == 0: - self._save_to_cache() + try: + self._save_to_cache() + except Exception as e: + # Don't spam logs with cache errors, just log once every 1000 ticks + if len(self.ticks) % 1000 == 0: + logger.warning(f"Cache save failed at {len(self.ticks)} ticks: {str(e)}") + pass # Continue even if cache fails class Position: """Represents a trading position""" diff --git a/realtime_chart.log b/realtime_chart.log index 48ae714..0c110ed 100644 --- a/realtime_chart.log +++ b/realtime_chart.log @@ -696978,3 +696978,150 @@ ade'} 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 +2025-05-24 01:21:06,330 - INFO - [dataprovider_realtime.py:978] - Detected local timezone: Europe/Kiev (Europe/Kiev) +2025-05-24 01:21:06,770 - INFO - [test_chart_data.py:111] - ============================================================ +2025-05-24 01:21:06,772 - INFO - [test_chart_data.py:122] - ---------------------------------------- +2025-05-24 01:21:06,772 - INFO - [test_chart_data.py:21] - Testing Binance historical data fetch... +2025-05-24 01:21:06,788 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv +2025-05-24 01:21:08,497 - INFO - [dataprovider_realtime.py:348] - Saved 100 candles to cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv +2025-05-24 01:21:08,497 - INFO - [dataprovider_realtime.py:305] - Fetched 100 candles for ETH/USDT (1m) +2025-05-24 01:21:08,497 - INFO - [test_chart_data.py:31] - Latest price: $2553.99 +2025-05-24 01:21:08,497 - INFO - [test_chart_data.py:32] - Date range: 2025-05-23 20:42:00 to 2025-05-23 22:21:00 +2025-05-24 01:21:08,500 - INFO - [test_chart_data.py:122] - ---------------------------------------- +2025-05-24 01:21:08,500 - INFO - [test_chart_data.py:44] - Testing TickStorage data loading... +2025-05-24 01:21:08,500 - INFO - [dataprovider_realtime.py:1027] - Creating new tick storage for ETH/USDT with timeframes ['1s', '1m', '5m', '1h'] +2025-05-24 01:21:08,500 - INFO - [dataprovider_realtime.py:1028] - Cache directory: F:\projects\gogo2\cache\ETHUSDT +2025-05-24 01:21:08,500 - INFO - [dataprovider_realtime.py:1029] - Cache file: F:\projects\gogo2\cache\ETHUSDT\ETHUSDT_ticks.json +2025-05-24 01:21:08,500 - INFO - [dataprovider_realtime.py:1034] - TickStorage: TimescaleDB integration is DISABLED for ETH/USDT +2025-05-24 01:21:08,500 - INFO - [dataprovider_realtime.py:1329] - Starting historical data load for ETH/USDT with limit 100 +2025-05-24 01:21:08,500 - INFO - [dataprovider_realtime.py:1337] - Attempting to load from cache... +2025-05-24 01:21:08,508 - ERROR - [dataprovider_realtime.py:1094] - Error loading ticks from cache: Expecting value: line 1 column 53 (char 52) +2025-05-24 01:21:08,509 - INFO - [dataprovider_realtime.py:1342] - No valid cache data found +2025-05-24 01:21:08,509 - INFO - [dataprovider_realtime.py:1366] - TimescaleDB not available or disabled +2025-05-24 01:21:08,509 - INFO - [dataprovider_realtime.py:1370] - Loading data from Binance API... +2025-05-24 01:21:08,509 - INFO - [dataprovider_realtime.py:1379] - Fetching 1m candles for ETH/USDT... +2025-05-24 01:21:08,519 - INFO - [dataprovider_realtime.py:337] - Loaded 100 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv +2025-05-24 01:21:09,696 - INFO - [dataprovider_realtime.py:348] - Saved 100 candles to cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv +2025-05-24 01:21:09,696 - INFO - [dataprovider_realtime.py:305] - Fetched 100 candles for ETH/USDT (1m) +2025-05-24 01:21:09,696 - INFO - [dataprovider_realtime.py:1382] - Loaded 100 1m candles from Binance API +2025-05-24 01:21:09,696 - INFO - [dataprovider_realtime.py:1379] - Fetching 5m candles for ETH/USDT... +2025-05-24 01:21:09,713 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_5m_candles.csv +2025-05-24 01:21:09,713 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (5m) +2025-05-24 01:21:09,714 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 5m candles from Binance API +2025-05-24 01:21:09,739 - INFO - [dataprovider_realtime.py:1379] - Fetching 1h candles for ETH/USDT... +2025-05-24 01:21:09,750 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1h_candles.csv +2025-05-24 01:21:09,750 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1h) +2025-05-24 01:21:09,750 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 1h candles from Binance API +2025-05-24 01:21:09,769 - INFO - [dataprovider_realtime.py:1410] - Successfully loaded 3 timeframes from Binance API +2025-05-24 01:21:09,776 - INFO - [dataprovider_realtime.py:1414] - Loading 1s candles... +2025-05-24 01:21:09,776 - INFO - [dataprovider_realtime.py:333] - Using recent 1s cache (age: 7.5 minutes) +2025-05-24 01:21:09,776 - INFO - [dataprovider_realtime.py:337] - Loaded 300 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1s_candles.csv +2025-05-24 01:21:09,779 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1s) +2025-05-24 01:21:09,780 - INFO - [dataprovider_realtime.py:1419] - Loaded 300 recent 1s candles from Binance API +2025-05-24 01:21:09,787 - INFO - [dataprovider_realtime.py:1505] - Final 1s candle count: 300 +2025-05-24 01:21:09,787 - INFO - [dataprovider_realtime.py:1505] - Final 1m candle count: 100 +2025-05-24 01:21:09,787 - INFO - [dataprovider_realtime.py:1505] - Final 5m candle count: 1000 +2025-05-24 01:21:09,787 - INFO - [dataprovider_realtime.py:1505] - Final 1h candle count: 1000 +2025-05-24 01:21:09,787 - INFO - [dataprovider_realtime.py:1508] - Historical data loading completed. Has data: True +2025-05-24 01:21:09,789 - INFO - [test_chart_data.py:59] - 1s: 300 candles +2025-05-24 01:21:09,789 - INFO - [test_chart_data.py:63] - Latest 1s: 2025-05-23 22:13:36 - $2549.36 +2025-05-24 01:21:09,789 - INFO - [test_chart_data.py:59] - 1m: 100 candles +2025-05-24 01:21:09,790 - INFO - [test_chart_data.py:63] - Latest 1m: 2025-05-23 22:21:00 - $2554.89 +2025-05-24 01:21:09,790 - INFO - [test_chart_data.py:59] - 5m: 1000 candles +2025-05-24 01:21:09,790 - INFO - [test_chart_data.py:63] - Latest 5m: 2025-05-23 22:15:00 - $2550.60 +2025-05-24 01:21:09,790 - INFO - [test_chart_data.py:59] - 1h: 1000 candles +2025-05-24 01:21:09,790 - INFO - [test_chart_data.py:63] - Latest 1h: 2025-05-23 22:00:00 - $2550.79 +2025-05-24 01:21:09,792 - INFO - [test_chart_data.py:122] - ---------------------------------------- +2025-05-24 01:21:09,792 - INFO - [test_chart_data.py:78] - Testing RealTimeChart initialization... +2025-05-24 01:21:09,792 - 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:21:09,793 - INFO - [dataprovider_realtime.py:1028] - Cache directory: F:\projects\gogo2\cache\ETHUSDT +2025-05-24 01:21:09,793 - INFO - [dataprovider_realtime.py:1029] - Cache file: F:\projects\gogo2\cache\ETHUSDT\ETHUSDT_ticks.json +2025-05-24 01:21:09,793 - INFO - [dataprovider_realtime.py:1685] - Loading historical data for ETH/USDT during chart initialization +2025-05-24 01:21:09,793 - INFO - [dataprovider_realtime.py:1329] - Starting historical data load for ETH/USDT with limit 1000 +2025-05-24 01:21:09,793 - INFO - [dataprovider_realtime.py:1337] - Attempting to load from cache... +2025-05-24 01:21:09,794 - ERROR - [dataprovider_realtime.py:1094] - Error loading ticks from cache: Expecting value: line 1 column 53 (char 52) +2025-05-24 01:21:09,794 - INFO - [dataprovider_realtime.py:1342] - No valid cache data found +2025-05-24 01:21:09,794 - INFO - [dataprovider_realtime.py:1366] - TimescaleDB not available or disabled +2025-05-24 01:21:09,794 - INFO - [dataprovider_realtime.py:1370] - Loading data from Binance API... +2025-05-24 01:21:09,794 - INFO - [dataprovider_realtime.py:1379] - Fetching 1m candles for ETH/USDT... +2025-05-24 01:21:09,806 - INFO - [dataprovider_realtime.py:337] - Loaded 100 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv +2025-05-24 01:21:12,389 - INFO - [dataprovider_realtime.py:348] - Saved 1000 candles to cache: F:\projects\gogo2\cache\ETHUSDT_1m_candles.csv +2025-05-24 01:21:12,389 - INFO - [dataprovider_realtime.py:305] - Fetched 1000 candles for ETH/USDT (1m) +2025-05-24 01:21:12,389 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 1m candles from Binance API +2025-05-24 01:21:12,415 - INFO - [dataprovider_realtime.py:1379] - Fetching 5m candles for ETH/USDT... +2025-05-24 01:21:12,420 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_5m_candles.csv +2025-05-24 01:21:12,420 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (5m) +2025-05-24 01:21:12,420 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 5m candles from Binance API +2025-05-24 01:21:12,445 - INFO - [dataprovider_realtime.py:1379] - Fetching 15m candles for ETH/USDT... +2025-05-24 01:21:12,457 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_15m_candles.csv +2025-05-24 01:21:12,457 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (15m) +2025-05-24 01:21:12,463 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 15m candles from Binance API +2025-05-24 01:21:12,487 - INFO - [dataprovider_realtime.py:1379] - Fetching 1h candles for ETH/USDT... +2025-05-24 01:21:12,492 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1h_candles.csv +2025-05-24 01:21:12,492 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1h) +2025-05-24 01:21:12,492 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 1h candles from Binance API +2025-05-24 01:21:12,519 - INFO - [dataprovider_realtime.py:1379] - Fetching 4h candles for ETH/USDT... +2025-05-24 01:21:12,524 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_4h_candles.csv +2025-05-24 01:21:12,524 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (4h) +2025-05-24 01:21:12,524 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 4h candles from Binance API +2025-05-24 01:21:12,550 - INFO - [dataprovider_realtime.py:1379] - Fetching 1d candles for ETH/USDT... +2025-05-24 01:21:12,552 - INFO - [dataprovider_realtime.py:337] - Loaded 1000 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1d_candles.csv +2025-05-24 01:21:12,552 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1d) +2025-05-24 01:21:12,552 - INFO - [dataprovider_realtime.py:1382] - Loaded 1000 1d candles from Binance API +2025-05-24 01:21:12,584 - INFO - [dataprovider_realtime.py:1410] - Successfully loaded 6 timeframes from Binance API +2025-05-24 01:21:12,584 - INFO - [dataprovider_realtime.py:1414] - Loading 1s candles... +2025-05-24 01:21:12,584 - INFO - [dataprovider_realtime.py:333] - Using recent 1s cache (age: 7.6 minutes) +2025-05-24 01:21:12,587 - INFO - [dataprovider_realtime.py:337] - Loaded 300 candles from cache: F:\projects\gogo2\cache\ETHUSDT_1s_candles.csv +2025-05-24 01:21:12,587 - INFO - [dataprovider_realtime.py:265] - Using cached historical data for ETH/USDT (1s) +2025-05-24 01:21:12,587 - INFO - [dataprovider_realtime.py:1419] - Loaded 300 recent 1s candles from Binance API +2025-05-24 01:21:12,595 - INFO - [dataprovider_realtime.py:1505] - Final 1s candle count: 300 +2025-05-24 01:21:12,595 - INFO - [dataprovider_realtime.py:1505] - Final 1m candle count: 1000 +2025-05-24 01:21:12,595 - INFO - [dataprovider_realtime.py:1505] - Final 5m candle count: 1000 +2025-05-24 01:21:12,595 - INFO - [dataprovider_realtime.py:1505] - Final 15m candle count: 1000 +2025-05-24 01:21:12,595 - INFO - [dataprovider_realtime.py:1505] - Final 1h candle count: 1000 +2025-05-24 01:21:12,595 - INFO - [dataprovider_realtime.py:1505] - Final 4h candle count: 1000 +2025-05-24 01:21:12,595 - INFO - [dataprovider_realtime.py:1505] - Final 1d candle count: 1000 +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1508] - Historical data loading completed. Has data: True +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1689] - Successfully loaded historical data for ETH/USDT +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1693] - 1s: 300 candles +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1693] - 1m: 1000 candles +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1693] - 5m: 1000 candles +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1693] - 15m: 1000 candles +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1693] - 1h: 1000 candles +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:1713] - RealTimeChart initialized: ETH/USDT (1m) +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:2142] - Retrieved 300 candles for 1s +2025-05-24 01:21:12,598 - INFO - [dataprovider_realtime.py:2142] - Retrieved 1000 candles for 1m +2025-05-24 01:21:12,600 - INFO - [test_chart_data.py:93] - 1s candles: 300 +2025-05-24 01:21:12,600 - INFO - [test_chart_data.py:94] - 1m candles: 1000 +2025-05-24 01:21:12,600 - INFO - [test_chart_data.py:98] - Latest 1m candle: 2025-05-23 22:21:00 - $2554.32 +2025-05-24 01:21:12,602 - INFO - [test_chart_data.py:131] - +============================================================ +2025-05-24 01:21:12,604 - INFO - [test_chart_data.py:133] - ============================================================ +2025-05-24 01:21:12,608 - INFO - [test_chart_data.py:142] - +Passed: 3/3 tests +2025-05-24 01:21:54,373 - INFO - [dataprovider_realtime.py:978] - Detected local timezone: Europe/Kiev (Europe/Kiev) +2025-05-24 01:21:54,650 - INFO - [test_tick_cache.py:116] - ================================================== +2025-05-24 01:21:54,650 - INFO - [test_tick_cache.py:23] - Testing tick caching with timestamp serialization... +2025-05-24 01:21:54,650 - INFO - [dataprovider_realtime.py:1027] - Creating new tick storage for TEST/SYMBOL with timeframes ['1s', '1m'] +2025-05-24 01:21:54,650 - INFO - [dataprovider_realtime.py:1028] - Cache directory: F:\projects\gogo2\cache\TESTSYMBOL +2025-05-24 01:21:54,651 - INFO - [dataprovider_realtime.py:1029] - Cache file: F:\projects\gogo2\cache\TESTSYMBOL\TESTSYMBOL_ticks.json +2025-05-24 01:21:54,651 - INFO - [dataprovider_realtime.py:1034] - TickStorage: TimescaleDB integration is DISABLED for TEST/SYMBOL +2025-05-24 01:21:54,651 - INFO - [test_tick_cache.py:55] - Adding tick 1: price=$100.0, timestamp type= +2025-05-24 01:21:54,652 - INFO - [test_tick_cache.py:55] - Adding tick 2: price=$101.0, timestamp type= +2025-05-24 01:21:54,652 - INFO - [test_tick_cache.py:55] - Adding tick 3: price=$102.0, timestamp type= +2025-05-24 01:21:54,652 - INFO - [test_tick_cache.py:58] - Total ticks in storage: 3 +2025-05-24 01:21:54,653 - INFO - [test_tick_cache.py:62] - Saved ticks to cache +2025-05-24 01:21:54,662 - INFO - [test_tick_cache.py:72] - Cache contains 3 ticks +2025-05-24 01:21:54,662 - INFO - [test_tick_cache.py:77] - First tick in cache: {'price': 100.0, 'quantity': 1.0, 'timestamp': '2025-05-24T01:21:54.651200'} +2025-05-24 01:21:54,662 - INFO - [test_tick_cache.py:78] - Timestamp type in cache: +2025-05-24 01:21:54,662 - INFO - [test_tick_cache.py:84] - Creating new TickStorage instance to test loading... +2025-05-24 01:21:54,662 - INFO - [dataprovider_realtime.py:1027] - Creating new tick storage for TEST/SYMBOL with timeframes ['1s', '1m'] +2025-05-24 01:21:54,662 - INFO - [dataprovider_realtime.py:1028] - Cache directory: F:\projects\gogo2\cache\TESTSYMBOL +2025-05-24 01:21:54,663 - INFO - [dataprovider_realtime.py:1029] - Cache file: F:\projects\gogo2\cache\TESTSYMBOL\TESTSYMBOL_ticks.json +2025-05-24 01:21:54,663 - INFO - [dataprovider_realtime.py:1034] - TickStorage: TimescaleDB integration is DISABLED for TEST/SYMBOL +2025-05-24 01:21:54,663 - INFO - [dataprovider_realtime.py:1091] - Loaded 3 ticks from cache +2025-05-24 01:21:54,666 - INFO - [test_tick_cache.py:95] - Loaded tick 1: price=$100.0, timestamp=2025-05-24 01:21:54.651200, type= +2025-05-24 01:21:54,666 - INFO - [test_tick_cache.py:95] - Loaded tick 2: price=$101.0, timestamp=2025-05-24 01:21:54.651200, type= +2025-05-24 01:21:54,666 - INFO - [test_tick_cache.py:95] - Loaded tick 3: price=$102.0, timestamp=2025-05-23 22:21:54.651000, type= +2025-05-24 01:21:54,667 - INFO - [test_tick_cache.py:120] - +================================================== diff --git a/test_tick_cache.py b/test_tick_cache.py new file mode 100644 index 0000000..a752ddb --- /dev/null +++ b/test_tick_cache.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +""" +Test script to verify tick caching with timestamp serialization +""" + +import logging +import sys +import os +import pandas as pd +from datetime import datetime + +# Add the project root to the path +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from dataprovider_realtime import TickStorage + +# Set up logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def test_tick_caching(): + """Test tick caching with pandas Timestamps""" + logger.info("Testing tick caching with timestamp serialization...") + + try: + # Create tick storage + tick_storage = TickStorage("TEST/SYMBOL", ["1s", "1m"]) + + # Clear any existing cache + if os.path.exists(tick_storage.cache_path): + os.remove(tick_storage.cache_path) + logger.info("Cleared existing cache file") + + # Add some test ticks with different timestamp formats + test_ticks = [ + { + 'price': 100.0, + 'quantity': 1.0, + 'timestamp': pd.Timestamp.now() + }, + { + 'price': 101.0, + 'quantity': 1.5, + 'timestamp': datetime.now() + }, + { + 'price': 102.0, + 'quantity': 2.0, + 'timestamp': int(datetime.now().timestamp() * 1000) # milliseconds + } + ] + + # Add ticks + for i, tick in enumerate(test_ticks): + logger.info(f"Adding tick {i+1}: price=${tick['price']}, timestamp type={type(tick['timestamp'])}") + tick_storage.add_tick(tick) + + logger.info(f"Total ticks in storage: {len(tick_storage.ticks)}") + + # Force save to cache + tick_storage._save_to_cache() + logger.info("Saved ticks to cache") + + # Verify cache file exists + if os.path.exists(tick_storage.cache_path): + logger.info(f"✅ Cache file created: {tick_storage.cache_path}") + + # Check file content + with open(tick_storage.cache_path, 'r') as f: + import json + cache_content = json.load(f) + logger.info(f"Cache contains {len(cache_content)} ticks") + + # Show first tick to verify format + if cache_content: + first_tick = cache_content[0] + logger.info(f"First tick in cache: {first_tick}") + logger.info(f"Timestamp type in cache: {type(first_tick['timestamp'])}") + else: + logger.error("❌ Cache file was not created") + return False + + # Create new tick storage instance to test loading + logger.info("Creating new TickStorage instance to test loading...") + new_tick_storage = TickStorage("TEST/SYMBOL", ["1s", "1m"]) + + # Load from cache + cache_loaded = new_tick_storage._load_from_cache() + + if cache_loaded: + logger.info(f"✅ Successfully loaded {len(new_tick_storage.ticks)} ticks from cache") + + # Verify timestamps are properly converted back to pandas Timestamps + for i, tick in enumerate(new_tick_storage.ticks): + logger.info(f"Loaded tick {i+1}: price=${tick['price']}, timestamp={tick['timestamp']}, type={type(tick['timestamp'])}") + + if not isinstance(tick['timestamp'], pd.Timestamp): + logger.error(f"❌ Timestamp not properly converted back to pandas.Timestamp: {type(tick['timestamp'])}") + return False + + logger.info("✅ All timestamps properly converted back to pandas.Timestamp") + return True + else: + logger.error("❌ Failed to load ticks from cache") + return False + + except Exception as e: + logger.error(f"❌ Error in tick caching test: {str(e)}") + import traceback + logger.error(traceback.format_exc()) + return False + +def main(): + """Run the test""" + logger.info("🧪 Starting tick caching test...") + logger.info("=" * 50) + + success = test_tick_caching() + + logger.info("\n" + "=" * 50) + if success: + logger.info("🎉 Tick caching test PASSED!") + else: + logger.error("❌ Tick caching test FAILED!") + + return success + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) \ No newline at end of file