Cycles/test/analyze_aligned_trades.py

289 lines
12 KiB
Python

#!/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)