#!/usr/bin/env python3 """ Simple alignment test with synthetic data to clearly show timeframe alignment. """ import pandas as pd import matplotlib.pyplot as plt import matplotlib.dates as mdates from matplotlib.patches import Rectangle import sys import os # Add the project root to Python path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from IncrementalTrader.utils import aggregate_minute_data_to_timeframe, parse_timeframe_to_minutes def create_simple_test_data(): """Create simple test data for clear visualization.""" start_time = pd.Timestamp('2024-01-01 09:00:00') minute_data = [] # Create exactly 60 minutes of data (4 complete 15-min bars) for i in range(60): timestamp = start_time + pd.Timedelta(minutes=i) # Create a simple price pattern that's easy to follow base_price = 100.0 minute_in_hour = i % 60 price_trend = base_price + (minute_in_hour * 0.1) # Gradual uptrend minute_data.append({ 'timestamp': timestamp, 'open': price_trend, 'high': price_trend + 0.2, 'low': price_trend - 0.2, 'close': price_trend + 0.1, 'volume': 1000 }) return minute_data def plot_timeframe_bars(ax, data, timeframe, color, alpha=0.7, show_labels=True): """Plot timeframe bars with clear boundaries.""" if not data: return timeframe_minutes = parse_timeframe_to_minutes(timeframe) for i, bar in enumerate(data): timestamp = bar['timestamp'] open_price = bar['open'] high_price = bar['high'] low_price = bar['low'] close_price = bar['close'] # Calculate bar boundaries (end timestamp mode) bar_start = timestamp - pd.Timedelta(minutes=timeframe_minutes) bar_end = timestamp # Draw the bar as a rectangle spanning the full time period body_height = abs(close_price - open_price) body_bottom = min(open_price, close_price) # Bar body rect = Rectangle((bar_start, body_bottom), bar_end - bar_start, body_height, facecolor=color, edgecolor='black', alpha=alpha, linewidth=1) ax.add_patch(rect) # High-low wick at center bar_center = bar_start + (bar_end - bar_start) / 2 ax.plot([bar_center, bar_center], [low_price, high_price], color='black', linewidth=2, alpha=alpha) # Add labels if requested if show_labels: ax.text(bar_center, high_price + 0.1, f"{timeframe}\n#{i+1}", ha='center', va='bottom', fontsize=8, fontweight='bold') def create_alignment_visualization(): """Create a clear visualization of timeframe alignment.""" print("šŸŽÆ Creating Timeframe Alignment Visualization") print("=" * 50) # Create test data minute_data = create_simple_test_data() print(f"šŸ“Š Created {len(minute_data)} minute data points") print(f"šŸ“… Range: {minute_data[0]['timestamp']} to {minute_data[-1]['timestamp']}") # Aggregate to different timeframes timeframes = ["5min", "15min", "30min", "1h"] colors = ['red', 'green', 'blue', 'purple'] alphas = [0.8, 0.6, 0.4, 0.2] aggregated_data = {} for tf in timeframes: aggregated_data[tf] = aggregate_minute_data_to_timeframe(minute_data, tf, "end") print(f" {tf}: {len(aggregated_data[tf])} bars") # Create visualization fig, ax = plt.subplots(1, 1, figsize=(16, 10)) fig.suptitle('Timeframe Alignment Visualization\n(Smaller timeframes should fit inside larger ones)', fontsize=16, fontweight='bold') # Plot timeframes from largest to smallest (background to foreground) for i, tf in enumerate(reversed(timeframes)): color = colors[timeframes.index(tf)] alpha = alphas[timeframes.index(tf)] show_labels = (tf in ["5min", "15min"]) # Only label smaller timeframes for clarity plot_timeframe_bars(ax, aggregated_data[tf], tf, color, alpha, show_labels) # Format the plot ax.set_ylabel('Price (USD)', fontsize=12) ax.set_xlabel('Time', fontsize=12) ax.grid(True, alpha=0.3) # Format x-axis ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) ax.xaxis.set_major_locator(mdates.MinuteLocator(interval=15)) plt.setp(ax.xaxis.get_majorticklabels(), rotation=45) # Add legend legend_elements = [] for i, tf in enumerate(timeframes): legend_elements.append(plt.Rectangle((0,0),1,1, facecolor=colors[i], alpha=alphas[i], label=f"{tf} ({len(aggregated_data[tf])} bars)")) ax.legend(handles=legend_elements, loc='upper left', fontsize=10) # Add explanation explanation = ("Each bar spans its full time period.\n" "5min bars should fit exactly inside 15min bars.\n" "15min bars should fit exactly inside 30min and 1h bars.") ax.text(0.02, 0.98, explanation, transform=ax.transAxes, verticalalignment='top', fontsize=10, bbox=dict(boxstyle='round', facecolor='lightyellow', alpha=0.9)) plt.tight_layout() # Print alignment verification print(f"\nšŸ” Alignment Verification:") bars_5m = aggregated_data["5min"] bars_15m = aggregated_data["15min"] for i, bar_15m in enumerate(bars_15m): print(f"\n15min bar {i+1}: {bar_15m['timestamp']}") bar_15m_start = bar_15m['timestamp'] - pd.Timedelta(minutes=15) contained_5m = [] for bar_5m in bars_5m: bar_5m_start = bar_5m['timestamp'] - pd.Timedelta(minutes=5) bar_5m_end = bar_5m['timestamp'] # Check if 5min bar is contained within 15min bar if bar_15m_start <= bar_5m_start and bar_5m_end <= bar_15m['timestamp']: contained_5m.append(bar_5m) print(f" Contains {len(contained_5m)} x 5min bars:") for j, bar_5m in enumerate(contained_5m): print(f" {j+1}. {bar_5m['timestamp']}") return fig def main(): """Main function.""" print("šŸš€ Simple Timeframe Alignment Test") print("=" * 40) try: fig = create_alignment_visualization() plt.show() print("\nāœ… Alignment test completed!") print("šŸ“Š In the chart, you should see:") print(" - Each 15min bar contains exactly 3 x 5min bars") print(" - Each 30min bar contains exactly 6 x 5min bars") print(" - Each 1h bar contains exactly 12 x 5min bars") print(" - All bars are properly aligned with no gaps or overlaps") return True except Exception as e: print(f"āŒ Error: {e}") import traceback traceback.print_exc() return False if __name__ == "__main__": success = main() sys.exit(0 if success else 1)