#!/usr/bin/env python3 """ Test Bar Alignment Between TimeframeAggregator and Pandas Resampling ==================================================================== This script tests whether the TimeframeAggregator creates the same bar boundaries as pandas resampling to identify the timing issue. """ import pandas as pd import numpy as np from datetime import datetime, timedelta import sys import os # Add the parent directory to the path to import cycles modules sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from cycles.IncStrategies.base import TimeframeAggregator def create_test_data(): """Create test minute-level data.""" # Create 2 hours of minute data starting at 2025-01-01 10:00:00 start_time = pd.Timestamp('2025-01-01 10:00:00') timestamps = [start_time + timedelta(minutes=i) for i in range(120)] data = [] for i, ts in enumerate(timestamps): data.append({ 'timestamp': ts, 'open': 100.0 + i * 0.1, 'high': 100.5 + i * 0.1, 'low': 99.5 + i * 0.1, 'close': 100.2 + i * 0.1, 'volume': 1000.0 }) return data def test_pandas_resampling(data): """Test how pandas resampling creates 15-minute bars.""" print("šŸ” TESTING PANDAS RESAMPLING") print("=" * 60) # Convert to DataFrame df = pd.DataFrame(data) df.set_index('timestamp', inplace=True) # Resample to 15-minute bars agg_rules = { 'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last', 'volume': 'sum' } resampled = df.resample('15min').agg(agg_rules) resampled = resampled.dropna() print(f"Original data points: {len(df)}") print(f"15-minute bars: {len(resampled)}") print(f"\nFirst 10 bars:") for i, (timestamp, row) in enumerate(resampled.head(10).iterrows()): print(f" {i+1:2d}. {timestamp} - Open: {row['open']:.1f}, Close: {row['close']:.1f}") return resampled def test_timeframe_aggregator(data): """Test how TimeframeAggregator creates 15-minute bars.""" print(f"\nšŸ” TESTING TIMEFRAME AGGREGATOR") print("=" * 60) aggregator = TimeframeAggregator(timeframe_minutes=15) completed_bars = [] for point in data: ohlcv_data = { 'open': point['open'], 'high': point['high'], 'low': point['low'], 'close': point['close'], 'volume': point['volume'] } completed_bar = aggregator.update(point['timestamp'], ohlcv_data) if completed_bar is not None: completed_bars.append(completed_bar) print(f"Completed bars: {len(completed_bars)}") print(f"\nFirst 10 bars:") for i, bar in enumerate(completed_bars[:10]): print(f" {i+1:2d}. {bar['timestamp']} - Open: {bar['open']:.1f}, Close: {bar['close']:.1f}") return completed_bars def compare_alignments(pandas_bars, aggregator_bars): """Compare the bar alignments between pandas and aggregator.""" print(f"\nšŸ“Š COMPARING BAR ALIGNMENTS") print("=" * 60) print(f"Pandas bars: {len(pandas_bars)}") print(f"Aggregator bars: {len(aggregator_bars)}") # Compare timestamps print(f"\nTimestamp comparison:") min_len = min(len(pandas_bars), len(aggregator_bars)) for i in range(min(10, min_len)): pandas_ts = pandas_bars.index[i] aggregator_ts = aggregator_bars[i]['timestamp'] time_diff = (aggregator_ts - pandas_ts).total_seconds() / 60 # minutes print(f" {i+1:2d}. Pandas: {pandas_ts}, Aggregator: {aggregator_ts}, Diff: {time_diff:+.0f}min") # Calculate average difference time_diffs = [] for i in range(min_len): pandas_ts = pandas_bars.index[i] aggregator_ts = aggregator_bars[i]['timestamp'] time_diff = (aggregator_ts - pandas_ts).total_seconds() / 60 time_diffs.append(time_diff) if time_diffs: avg_diff = np.mean(time_diffs) print(f"\nAverage timing difference: {avg_diff:+.1f} minutes") if abs(avg_diff) < 0.1: print("āœ… Bar alignments match!") else: print("āŒ Bar alignments differ!") print("This explains the 15-minute delay in the incremental strategy.") def test_specific_timestamps(): """Test specific timestamps that appear in the actual trading data.""" print(f"\nšŸŽÆ TESTING SPECIFIC TIMESTAMPS FROM TRADING DATA") print("=" * 60) # Test timestamps from the actual trading data test_timestamps = [ '2025-01-03 11:15:00', # Original strategy '2025-01-03 11:30:00', # Incremental strategy '2025-01-04 18:00:00', # Original strategy '2025-01-04 18:15:00', # Incremental strategy ] aggregator = TimeframeAggregator(timeframe_minutes=15) for ts_str in test_timestamps: ts = pd.Timestamp(ts_str) # Test what bar this timestamp belongs to ohlcv_data = {'open': 100, 'high': 101, 'low': 99, 'close': 100.5, 'volume': 1000} # Get the bar start time using the aggregator's method bar_start = aggregator._get_bar_start_time(ts) # Test pandas resampling for the same timestamp temp_df = pd.DataFrame([ohlcv_data], index=[ts]) resampled = temp_df.resample('15min').first() pandas_bar_start = resampled.index[0] if len(resampled) > 0 else None print(f"Timestamp: {ts}") print(f" Aggregator bar start: {bar_start}") print(f" Pandas bar start: {pandas_bar_start}") print(f" Difference: {(bar_start - pandas_bar_start).total_seconds() / 60:.0f} minutes") print() def main(): """Main test function.""" print("šŸš€ TESTING BAR ALIGNMENT BETWEEN STRATEGIES") print("=" * 80) try: # Create test data data = create_test_data() # Test pandas resampling pandas_bars = test_pandas_resampling(data) # Test TimeframeAggregator aggregator_bars = test_timeframe_aggregator(data) # Compare alignments compare_alignments(pandas_bars, aggregator_bars) # Test specific timestamps test_specific_timestamps() return True except Exception as e: print(f"\nāŒ Error during testing: {e}") import traceback traceback.print_exc() return False if __name__ == "__main__": success = main() exit(0 if success else 1)