209 lines
8.5 KiB
Python
209 lines
8.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Compare Trade Timing Between Strategies
|
||
|
|
=======================================
|
||
|
|
|
||
|
|
This script analyzes the timing differences between the original and incremental
|
||
|
|
strategies to understand why there's still a performance difference despite
|
||
|
|
having similar exit conditions.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import pandas as pd
|
||
|
|
import matplotlib.pyplot as plt
|
||
|
|
import numpy as np
|
||
|
|
from datetime import datetime, timedelta
|
||
|
|
|
||
|
|
def load_and_compare_trades():
|
||
|
|
"""Load and compare trade timing between strategies."""
|
||
|
|
|
||
|
|
print("🔍 COMPARING TRADE TIMING BETWEEN STRATEGIES")
|
||
|
|
print("=" * 80)
|
||
|
|
|
||
|
|
# Load original strategy trades
|
||
|
|
original_file = "../results/trades_15min(15min)_ST3pct.csv"
|
||
|
|
incremental_file = "../results/trades_incremental_15min(15min)_ST3pct.csv"
|
||
|
|
|
||
|
|
print(f"📊 Loading original trades from: {original_file}")
|
||
|
|
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'])
|
||
|
|
|
||
|
|
print(f"📊 Loading incremental trades from: {incremental_file}")
|
||
|
|
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'])
|
||
|
|
|
||
|
|
# Filter to only buy signals for entry timing comparison
|
||
|
|
original_buys = original_df[original_df['type'] == 'BUY'].copy()
|
||
|
|
incremental_buys = incremental_df[incremental_df['type'] == 'BUY'].copy()
|
||
|
|
|
||
|
|
print(f"\n📈 TRADE COUNT COMPARISON:")
|
||
|
|
print(f"Original strategy: {len(original_buys)} buy signals")
|
||
|
|
print(f"Incremental strategy: {len(incremental_buys)} buy signals")
|
||
|
|
print(f"Difference: {len(incremental_buys) - len(original_buys)} more in incremental")
|
||
|
|
|
||
|
|
# Compare first 10 trades
|
||
|
|
print(f"\n🕐 FIRST 10 TRADE TIMINGS:")
|
||
|
|
print("-" * 60)
|
||
|
|
print("Original Strategy:")
|
||
|
|
for i, row in original_buys.head(10).iterrows():
|
||
|
|
print(f" {i//2 + 1:2d}. {row['entry_time']} - ${row['entry_price']:.0f}")
|
||
|
|
|
||
|
|
print("\nIncremental Strategy:")
|
||
|
|
for i, row in incremental_buys.head(10).iterrows():
|
||
|
|
print(f" {i//2 + 1:2d}. {row['entry_time']} - ${row['entry_price']:.0f}")
|
||
|
|
|
||
|
|
# Analyze timing differences
|
||
|
|
analyze_timing_differences(original_buys, incremental_buys)
|
||
|
|
|
||
|
|
# Analyze price differences
|
||
|
|
analyze_price_differences(original_buys, incremental_buys)
|
||
|
|
|
||
|
|
return original_buys, incremental_buys
|
||
|
|
|
||
|
|
def analyze_timing_differences(original_buys, incremental_buys):
|
||
|
|
"""Analyze the timing differences between strategies."""
|
||
|
|
|
||
|
|
print(f"\n🕐 TIMING ANALYSIS:")
|
||
|
|
print("-" * 60)
|
||
|
|
|
||
|
|
# Find the earliest and latest trades
|
||
|
|
orig_start = original_buys['entry_time'].min()
|
||
|
|
orig_end = original_buys['entry_time'].max()
|
||
|
|
inc_start = incremental_buys['entry_time'].min()
|
||
|
|
inc_end = incremental_buys['entry_time'].max()
|
||
|
|
|
||
|
|
print(f"Original strategy:")
|
||
|
|
print(f" First trade: {orig_start}")
|
||
|
|
print(f" Last trade: {orig_end}")
|
||
|
|
print(f" Duration: {orig_end - orig_start}")
|
||
|
|
|
||
|
|
print(f"\nIncremental strategy:")
|
||
|
|
print(f" First trade: {inc_start}")
|
||
|
|
print(f" Last trade: {inc_end}")
|
||
|
|
print(f" Duration: {inc_end - inc_start}")
|
||
|
|
|
||
|
|
# Check if incremental strategy misses early trades
|
||
|
|
time_diff = inc_start - orig_start
|
||
|
|
print(f"\n⏰ TIME DIFFERENCE:")
|
||
|
|
print(f"Incremental starts {time_diff} after original")
|
||
|
|
|
||
|
|
if time_diff > timedelta(hours=1):
|
||
|
|
print("⚠️ SIGNIFICANT DELAY DETECTED!")
|
||
|
|
print("The incremental strategy is missing early profitable trades!")
|
||
|
|
|
||
|
|
# Count how many original trades happened before incremental started
|
||
|
|
early_trades = original_buys[original_buys['entry_time'] < inc_start]
|
||
|
|
print(f"📊 Original trades before incremental started: {len(early_trades)}")
|
||
|
|
|
||
|
|
if len(early_trades) > 0:
|
||
|
|
early_profits = []
|
||
|
|
for i in range(0, len(early_trades) * 2, 2):
|
||
|
|
if i + 1 < len(original_buys.index):
|
||
|
|
profit_pct = original_buys.iloc[i + 1]['profit_pct']
|
||
|
|
early_profits.append(profit_pct)
|
||
|
|
|
||
|
|
if early_profits:
|
||
|
|
avg_early_profit = np.mean(early_profits) * 100
|
||
|
|
total_early_profit = np.sum(early_profits) * 100
|
||
|
|
print(f"📈 Average profit of early trades: {avg_early_profit:.2f}%")
|
||
|
|
print(f"📈 Total profit from early trades: {total_early_profit:.2f}%")
|
||
|
|
|
||
|
|
def analyze_price_differences(original_buys, incremental_buys):
|
||
|
|
"""Analyze price differences at similar times."""
|
||
|
|
|
||
|
|
print(f"\n💰 PRICE ANALYSIS:")
|
||
|
|
print("-" * 60)
|
||
|
|
|
||
|
|
# Find trades that happen on the same day
|
||
|
|
original_buys['date'] = original_buys['entry_time'].dt.date
|
||
|
|
incremental_buys['date'] = incremental_buys['entry_time'].dt.date
|
||
|
|
|
||
|
|
common_dates = set(original_buys['date']) & set(incremental_buys['date'])
|
||
|
|
print(f"📅 Common trading dates: {len(common_dates)}")
|
||
|
|
|
||
|
|
# Compare prices on common dates
|
||
|
|
price_differences = []
|
||
|
|
|
||
|
|
for date in sorted(list(common_dates))[:10]: # First 10 common dates
|
||
|
|
orig_trades = original_buys[original_buys['date'] == date]
|
||
|
|
inc_trades = incremental_buys[incremental_buys['date'] == date]
|
||
|
|
|
||
|
|
if len(orig_trades) > 0 and len(inc_trades) > 0:
|
||
|
|
orig_price = orig_trades.iloc[0]['entry_price']
|
||
|
|
inc_price = inc_trades.iloc[0]['entry_price']
|
||
|
|
price_diff = ((inc_price - orig_price) / orig_price) * 100
|
||
|
|
price_differences.append(price_diff)
|
||
|
|
|
||
|
|
print(f" {date}: Original ${orig_price:.0f}, Incremental ${inc_price:.0f} ({price_diff:+.2f}%)")
|
||
|
|
|
||
|
|
if price_differences:
|
||
|
|
avg_price_diff = np.mean(price_differences)
|
||
|
|
print(f"\n📊 Average price difference: {avg_price_diff:+.2f}%")
|
||
|
|
if avg_price_diff > 1:
|
||
|
|
print("⚠️ Incremental strategy consistently buys at higher prices!")
|
||
|
|
elif avg_price_diff < -1:
|
||
|
|
print("✅ Incremental strategy consistently buys at lower prices!")
|
||
|
|
|
||
|
|
def create_timing_visualization(original_buys, incremental_buys):
|
||
|
|
"""Create a visualization of trade timing differences."""
|
||
|
|
|
||
|
|
print(f"\n📊 CREATING TIMING VISUALIZATION...")
|
||
|
|
|
||
|
|
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 10))
|
||
|
|
|
||
|
|
# Plot 1: Trade timing over time
|
||
|
|
ax1.scatter(original_buys['entry_time'], original_buys['entry_price'],
|
||
|
|
alpha=0.6, label='Original Strategy', color='blue', s=30)
|
||
|
|
ax1.scatter(incremental_buys['entry_time'], incremental_buys['entry_price'],
|
||
|
|
alpha=0.6, label='Incremental Strategy', color='red', s=30)
|
||
|
|
ax1.set_title('Trade Entry Timing Comparison')
|
||
|
|
ax1.set_xlabel('Date')
|
||
|
|
ax1.set_ylabel('Entry Price ($)')
|
||
|
|
ax1.legend()
|
||
|
|
ax1.grid(True, alpha=0.3)
|
||
|
|
|
||
|
|
# Plot 2: Cumulative trade count
|
||
|
|
original_buys_sorted = original_buys.sort_values('entry_time')
|
||
|
|
incremental_buys_sorted = incremental_buys.sort_values('entry_time')
|
||
|
|
|
||
|
|
ax2.plot(original_buys_sorted['entry_time'], range(1, len(original_buys_sorted) + 1),
|
||
|
|
label='Original Strategy', color='blue', linewidth=2)
|
||
|
|
ax2.plot(incremental_buys_sorted['entry_time'], range(1, len(incremental_buys_sorted) + 1),
|
||
|
|
label='Incremental Strategy', color='red', linewidth=2)
|
||
|
|
ax2.set_title('Cumulative Trade Count Over Time')
|
||
|
|
ax2.set_xlabel('Date')
|
||
|
|
ax2.set_ylabel('Cumulative Trades')
|
||
|
|
ax2.legend()
|
||
|
|
ax2.grid(True, alpha=0.3)
|
||
|
|
|
||
|
|
plt.tight_layout()
|
||
|
|
plt.savefig('../results/trade_timing_comparison.png', dpi=300, bbox_inches='tight')
|
||
|
|
print("📊 Timing visualization saved to: ../results/trade_timing_comparison.png")
|
||
|
|
|
||
|
|
def main():
|
||
|
|
"""Main analysis function."""
|
||
|
|
|
||
|
|
try:
|
||
|
|
original_buys, incremental_buys = load_and_compare_trades()
|
||
|
|
create_timing_visualization(original_buys, incremental_buys)
|
||
|
|
|
||
|
|
print(f"\n🎯 SUMMARY:")
|
||
|
|
print("=" * 80)
|
||
|
|
print("Key findings from trade timing analysis:")
|
||
|
|
print("1. Check if incremental strategy starts trading later")
|
||
|
|
print("2. Compare entry prices on same dates")
|
||
|
|
print("3. Identify any systematic timing delays")
|
||
|
|
print("4. Quantify impact of timing differences on performance")
|
||
|
|
|
||
|
|
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)
|