#!/usr/bin/env python3 """ Analyze Aligned Trades in Detail ================================ This script performs a detailed analysis of the aligned trades to understand why there's still a large performance difference between the strategies. """ import pandas as pd import numpy as np import matplotlib.pyplot as plt from datetime import datetime def load_aligned_trades(): """Load the aligned trade files.""" print("šŸ“Š LOADING ALIGNED TRADES") print("=" * 60) original_file = "../results/trades_original_aligned.csv" incremental_file = "../results/trades_incremental_aligned.csv" original_df = pd.read_csv(original_file) original_df['entry_time'] = pd.to_datetime(original_df['entry_time']) original_df['exit_time'] = pd.to_datetime(original_df['exit_time']) incremental_df = pd.read_csv(incremental_file) incremental_df['entry_time'] = pd.to_datetime(incremental_df['entry_time']) incremental_df['exit_time'] = pd.to_datetime(incremental_df['exit_time']) print(f"Aligned original trades: {len(original_df)}") print(f"Incremental trades: {len(incremental_df)}") return original_df, incremental_df def analyze_trade_timing_differences(original_df, incremental_df): """Analyze timing differences between aligned trades.""" print(f"\nšŸ• ANALYZING TRADE TIMING DIFFERENCES") print("=" * 60) # Get buy signals orig_buys = original_df[original_df['type'] == 'BUY'].copy() inc_buys = incremental_df[incremental_df['type'] == 'BUY'].copy() print(f"Original buy signals: {len(orig_buys)}") print(f"Incremental buy signals: {len(inc_buys)}") # Compare first 10 trades print(f"\nšŸ“‹ FIRST 10 ALIGNED TRADES:") print("-" * 80) print("Original Strategy:") for i, (idx, trade) in enumerate(orig_buys.head(10).iterrows()): print(f" {i+1:2d}. {trade['entry_time']} - ${trade['entry_price']:8.0f}") print("\nIncremental Strategy:") for i, (idx, trade) in enumerate(inc_buys.head(10).iterrows()): print(f" {i+1:2d}. {trade['entry_time']} - ${trade['entry_price']:8.0f}") # Find timing differences print(f"\nā° TIMING ANALYSIS:") print("-" * 60) # Group by date to find same-day trades orig_buys['date'] = orig_buys['entry_time'].dt.date inc_buys['date'] = inc_buys['entry_time'].dt.date common_dates = set(orig_buys['date']) & set(inc_buys['date']) print(f"Common trading dates: {len(common_dates)}") timing_diffs = [] price_diffs = [] for date in sorted(list(common_dates))[:10]: orig_day_trades = orig_buys[orig_buys['date'] == date] inc_day_trades = inc_buys[inc_buys['date'] == date] if len(orig_day_trades) > 0 and len(inc_day_trades) > 0: orig_time = orig_day_trades.iloc[0]['entry_time'] inc_time = inc_day_trades.iloc[0]['entry_time'] orig_price = orig_day_trades.iloc[0]['entry_price'] inc_price = inc_day_trades.iloc[0]['entry_price'] time_diff = (inc_time - orig_time).total_seconds() / 60 # minutes price_diff = ((inc_price - orig_price) / orig_price) * 100 timing_diffs.append(time_diff) price_diffs.append(price_diff) print(f" {date}: Original {orig_time.strftime('%H:%M')} (${orig_price:.0f}), " f"Incremental {inc_time.strftime('%H:%M')} (${inc_price:.0f}), " f"Diff: {time_diff:+.0f}min, {price_diff:+.2f}%") if timing_diffs: avg_time_diff = np.mean(timing_diffs) avg_price_diff = np.mean(price_diffs) print(f"\nAverage timing difference: {avg_time_diff:+.1f} minutes") print(f"Average price difference: {avg_price_diff:+.2f}%") def analyze_profit_distributions(original_df, incremental_df): """Analyze profit distributions between strategies.""" print(f"\nšŸ’° ANALYZING PROFIT DISTRIBUTIONS") print("=" * 60) # Get sell signals (exits) orig_exits = original_df[original_df['type'].str.contains('EXIT|EOD', na=False)].copy() inc_exits = incremental_df[incremental_df['type'].str.contains('EXIT|EOD', na=False)].copy() orig_profits = orig_exits['profit_pct'].values * 100 inc_profits = inc_exits['profit_pct'].values * 100 print(f"Original strategy trades: {len(orig_profits)}") print(f" Winning trades: {len(orig_profits[orig_profits > 0])} ({len(orig_profits[orig_profits > 0])/len(orig_profits)*100:.1f}%)") print(f" Average profit: {np.mean(orig_profits):.2f}%") print(f" Best trade: {np.max(orig_profits):.2f}%") print(f" Worst trade: {np.min(orig_profits):.2f}%") print(f" Std deviation: {np.std(orig_profits):.2f}%") print(f"\nIncremental strategy trades: {len(inc_profits)}") print(f" Winning trades: {len(inc_profits[inc_profits > 0])} ({len(inc_profits[inc_profits > 0])/len(inc_profits)*100:.1f}%)") print(f" Average profit: {np.mean(inc_profits):.2f}%") print(f" Best trade: {np.max(inc_profits):.2f}%") print(f" Worst trade: {np.min(inc_profits):.2f}%") print(f" Std deviation: {np.std(inc_profits):.2f}%") # Analyze profit ranges print(f"\nšŸ“Š PROFIT RANGE ANALYSIS:") print("-" * 60) ranges = [(-100, -5), (-5, -1), (-1, 0), (0, 1), (1, 5), (5, 100)] range_names = ["< -5%", "-5% to -1%", "-1% to 0%", "0% to 1%", "1% to 5%", "> 5%"] for i, (low, high) in enumerate(ranges): orig_count = len(orig_profits[(orig_profits >= low) & (orig_profits < high)]) inc_count = len(inc_profits[(inc_profits >= low) & (inc_profits < high)]) orig_pct = (orig_count / len(orig_profits)) * 100 if len(orig_profits) > 0 else 0 inc_pct = (inc_count / len(inc_profits)) * 100 if len(inc_profits) > 0 else 0 print(f" {range_names[i]:>10}: Original {orig_count:3d} ({orig_pct:4.1f}%), " f"Incremental {inc_count:3d} ({inc_pct:4.1f}%)") return orig_profits, inc_profits def analyze_trade_duration(original_df, incremental_df): """Analyze trade duration differences.""" print(f"\nā±ļø ANALYZING TRADE DURATION") print("=" * 60) # Get complete trades (buy + sell pairs) orig_buys = original_df[original_df['type'] == 'BUY'].copy() orig_exits = original_df[original_df['type'].str.contains('EXIT|EOD', na=False)].copy() inc_buys = incremental_df[incremental_df['type'] == 'BUY'].copy() inc_exits = incremental_df[incremental_df['type'].str.contains('EXIT|EOD', na=False)].copy() # Calculate durations orig_durations = [] inc_durations = [] for i, buy in orig_buys.iterrows(): exits = orig_exits[orig_exits['entry_time'] == buy['entry_time']] if len(exits) > 0: duration = (exits.iloc[0]['exit_time'] - buy['entry_time']).total_seconds() / 3600 # hours orig_durations.append(duration) for i, buy in inc_buys.iterrows(): exits = inc_exits[inc_exits['entry_time'] == buy['entry_time']] if len(exits) > 0: duration = (exits.iloc[0]['exit_time'] - buy['entry_time']).total_seconds() / 3600 # hours inc_durations.append(duration) print(f"Original strategy:") print(f" Average duration: {np.mean(orig_durations):.1f} hours") print(f" Median duration: {np.median(orig_durations):.1f} hours") print(f" Min duration: {np.min(orig_durations):.1f} hours") print(f" Max duration: {np.max(orig_durations):.1f} hours") print(f"\nIncremental strategy:") print(f" Average duration: {np.mean(inc_durations):.1f} hours") print(f" Median duration: {np.median(inc_durations):.1f} hours") print(f" Min duration: {np.min(inc_durations):.1f} hours") print(f" Max duration: {np.max(inc_durations):.1f} hours") return orig_durations, inc_durations def create_detailed_comparison_plots(original_df, incremental_df, orig_profits, inc_profits): """Create detailed comparison plots.""" print(f"\nšŸ“Š CREATING DETAILED COMPARISON PLOTS") print("=" * 60) fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12)) # Plot 1: Profit distribution comparison ax1.hist(orig_profits, bins=30, alpha=0.7, label='Original', color='blue', density=True) ax1.hist(inc_profits, bins=30, alpha=0.7, label='Incremental', color='red', density=True) ax1.set_title('Profit Distribution Comparison') ax1.set_xlabel('Profit (%)') ax1.set_ylabel('Density') ax1.legend() ax1.grid(True, alpha=0.3) # Plot 2: Cumulative profit over time orig_exits = original_df[original_df['type'].str.contains('EXIT|EOD', na=False)].copy() inc_exits = incremental_df[incremental_df['type'].str.contains('EXIT|EOD', na=False)].copy() orig_cumulative = np.cumsum(orig_exits['profit_pct'].values) * 100 inc_cumulative = np.cumsum(inc_exits['profit_pct'].values) * 100 ax2.plot(range(len(orig_cumulative)), orig_cumulative, label='Original', color='blue', linewidth=2) ax2.plot(range(len(inc_cumulative)), inc_cumulative, label='Incremental', color='red', linewidth=2) ax2.set_title('Cumulative Profit Over Trades') ax2.set_xlabel('Trade Number') ax2.set_ylabel('Cumulative Profit (%)') ax2.legend() ax2.grid(True, alpha=0.3) # Plot 3: Trade timing scatter orig_buys = original_df[original_df['type'] == 'BUY'] inc_buys = incremental_df[incremental_df['type'] == 'BUY'] ax3.scatter(orig_buys['entry_time'], orig_buys['entry_price'], alpha=0.6, label='Original', color='blue', s=20) ax3.scatter(inc_buys['entry_time'], inc_buys['entry_price'], alpha=0.6, label='Incremental', color='red', s=20) ax3.set_title('Trade Entry Timing') ax3.set_xlabel('Date') ax3.set_ylabel('Entry Price ($)') ax3.legend() ax3.grid(True, alpha=0.3) # Plot 4: Profit vs trade number ax4.scatter(range(len(orig_profits)), orig_profits, alpha=0.6, label='Original', color='blue', s=20) ax4.scatter(range(len(inc_profits)), inc_profits, alpha=0.6, label='Incremental', color='red', s=20) ax4.set_title('Individual Trade Profits') ax4.set_xlabel('Trade Number') ax4.set_ylabel('Profit (%)') ax4.legend() ax4.grid(True, alpha=0.3) ax4.axhline(y=0, color='black', linestyle='--', alpha=0.5) plt.tight_layout() plt.savefig('../results/detailed_aligned_analysis.png', dpi=300, bbox_inches='tight') print("Detailed analysis plot saved: ../results/detailed_aligned_analysis.png") def main(): """Main analysis function.""" print("šŸ” DETAILED ANALYSIS OF ALIGNED TRADES") print("=" * 80) try: # Load aligned trades original_df, incremental_df = load_aligned_trades() # Analyze timing differences analyze_trade_timing_differences(original_df, incremental_df) # Analyze profit distributions orig_profits, inc_profits = analyze_profit_distributions(original_df, incremental_df) # Analyze trade duration analyze_trade_duration(original_df, incremental_df) # Create detailed plots create_detailed_comparison_plots(original_df, incremental_df, orig_profits, inc_profits) print(f"\nšŸŽÆ KEY FINDINGS:") print("=" * 80) print("1. Check if strategies are trading at different times within the same day") print("2. Compare profit distributions to see if one strategy has better trades") print("3. Analyze trade duration differences") print("4. Look for systematic differences in entry/exit timing") return True except Exception as e: print(f"\nāŒ Error during analysis: {e}") import traceback traceback.print_exc() return False if __name__ == "__main__": success = main() exit(0 if success else 1)