#!/usr/bin/env python3 """ Plot original strategy results from trades CSV file. Shows buy/sell signals and portfolio value over time. """ import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.dates as mdates from datetime import datetime import os import sys # Add project root to path sys.path.insert(0, os.path.abspath('..')) def load_and_process_trades(trades_file, initial_usd=10000): """Load trades and calculate portfolio value over time.""" # Load trades data trades_df = pd.read_csv(trades_file) # Convert timestamps trades_df['entry_time'] = pd.to_datetime(trades_df['entry_time']) trades_df['exit_time'] = pd.to_datetime(trades_df['exit_time'], errors='coerce') # Separate buy and sell signals buy_signals = trades_df[trades_df['type'] == 'BUY'].copy() sell_signals = trades_df[trades_df['type'] != 'BUY'].copy() print(f"Loaded {len(buy_signals)} buy signals and {len(sell_signals)} sell signals") # Calculate portfolio value using compounding portfolio_value = initial_usd portfolio_history = [] # Create timeline from all trade times all_times = [] all_times.extend(buy_signals['entry_time'].tolist()) all_times.extend(sell_signals['exit_time'].dropna().tolist()) all_times = sorted(set(all_times)) print(f"Processing {len(all_times)} trade events...") # Track portfolio value at each trade current_value = initial_usd for sell_trade in sell_signals.itertuples(): # Apply the profit/loss from this trade profit_pct = sell_trade.profit_pct current_value *= (1 + profit_pct) portfolio_history.append({ 'timestamp': sell_trade.exit_time, 'portfolio_value': current_value, 'trade_type': 'SELL', 'price': sell_trade.exit_price, 'profit_pct': profit_pct * 100 }) # Convert to DataFrame portfolio_df = pd.DataFrame(portfolio_history) portfolio_df = portfolio_df.sort_values('timestamp').reset_index(drop=True) # Calculate performance metrics final_value = current_value total_return = (final_value - initial_usd) / initial_usd * 100 num_trades = len(sell_signals) winning_trades = len(sell_signals[sell_signals['profit_pct'] > 0]) win_rate = winning_trades / num_trades * 100 if num_trades > 0 else 0 avg_trade = sell_signals['profit_pct'].mean() * 100 if num_trades > 0 else 0 best_trade = sell_signals['profit_pct'].max() * 100 if num_trades > 0 else 0 worst_trade = sell_signals['profit_pct'].min() * 100 if num_trades > 0 else 0 performance = { 'initial_value': initial_usd, 'final_value': final_value, 'total_return': total_return, 'num_trades': num_trades, 'win_rate': win_rate, 'avg_trade': avg_trade, 'best_trade': best_trade, 'worst_trade': worst_trade } return buy_signals, sell_signals, portfolio_df, performance def create_comprehensive_plot(buy_signals, sell_signals, portfolio_df, performance, save_path="original_strategy_analysis.png"): """Create comprehensive plot with signals and portfolio value.""" # Create figure with subplots fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(16, 12), gridspec_kw={'height_ratios': [2, 1]}) # Plot 1: Price chart with buy/sell signals # Get price range for the chart all_prices = [] all_prices.extend(buy_signals['entry_price'].tolist()) all_prices.extend(sell_signals['exit_price'].tolist()) price_min = min(all_prices) price_max = max(all_prices) # Create a price line by connecting buy and sell points price_timeline = [] value_timeline = [] # Combine and sort all signals by time all_signals = [] for _, buy in buy_signals.iterrows(): all_signals.append({ 'time': buy['entry_time'], 'price': buy['entry_price'], 'type': 'BUY' }) for _, sell in sell_signals.iterrows(): all_signals.append({ 'time': sell['exit_time'], 'price': sell['exit_price'], 'type': 'SELL' }) all_signals = sorted(all_signals, key=lambda x: x['time']) # Create price line for signal in all_signals: price_timeline.append(signal['time']) value_timeline.append(signal['price']) # Plot price line if price_timeline: ax1.plot(price_timeline, value_timeline, color='black', linewidth=1.5, alpha=0.7, label='Price Action') # Plot buy signals ax1.scatter(buy_signals['entry_time'], buy_signals['entry_price'], color='green', marker='^', s=80, label=f"Buy Signals ({len(buy_signals)})", zorder=5, alpha=0.9, edgecolors='white', linewidth=1) # Plot sell signals with different colors based on profit/loss profitable_sells = sell_signals[sell_signals['profit_pct'] > 0] losing_sells = sell_signals[sell_signals['profit_pct'] <= 0] if len(profitable_sells) > 0: ax1.scatter(profitable_sells['exit_time'], profitable_sells['exit_price'], color='blue', marker='v', s=80, label=f"Profitable Sells ({len(profitable_sells)})", zorder=5, alpha=0.9, edgecolors='white', linewidth=1) if len(losing_sells) > 0: ax1.scatter(losing_sells['exit_time'], losing_sells['exit_price'], color='red', marker='v', s=80, label=f"Losing Sells ({len(losing_sells)})", zorder=5, alpha=0.9, edgecolors='white', linewidth=1) ax1.set_title('Original Strategy - Trading Signals', fontsize=16, fontweight='bold') ax1.set_ylabel('Price (USD)', fontsize=12) ax1.legend(loc='upper left', fontsize=10) ax1.grid(True, alpha=0.3) # Format y-axis for price ax1.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'${x:,.0f}')) # Plot 2: Portfolio Value Over Time if len(portfolio_df) > 0: ax2.plot(portfolio_df['timestamp'], portfolio_df['portfolio_value'], color='purple', linewidth=2, label='Portfolio Value') # Add horizontal line for initial value ax2.axhline(y=performance['initial_value'], color='gray', linestyle='--', alpha=0.7, label='Initial Value ($10,000)') # Add profit/loss shading initial_value = performance['initial_value'] profit_mask = portfolio_df['portfolio_value'] > initial_value loss_mask = portfolio_df['portfolio_value'] < initial_value if profit_mask.any(): ax2.fill_between(portfolio_df['timestamp'], portfolio_df['portfolio_value'], initial_value, where=profit_mask, color='green', alpha=0.2, label='Profit Zone') if loss_mask.any(): ax2.fill_between(portfolio_df['timestamp'], portfolio_df['portfolio_value'], initial_value, where=loss_mask, color='red', alpha=0.2, label='Loss Zone') ax2.set_title('Portfolio Value Over Time', fontsize=14, fontweight='bold') ax2.set_ylabel('Portfolio Value (USD)', fontsize=12) ax2.set_xlabel('Date', fontsize=12) ax2.legend(loc='upper left', fontsize=10) ax2.grid(True, alpha=0.3) # Format y-axis for portfolio value ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'${x:,.0f}')) # Format x-axis for both plots for ax in [ax1, ax2]: ax.xaxis.set_major_locator(mdates.MonthLocator()) ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m')) plt.setp(ax.xaxis.get_majorticklabels(), rotation=45) # Add performance text box perf_text = f""" PERFORMANCE SUMMARY {'='*30} Initial Value: ${performance['initial_value']:,.0f} Final Value: ${performance['final_value']:,.0f} Total Return: {performance['total_return']:+.1f}% Trading Statistics: • Number of Trades: {performance['num_trades']} • Win Rate: {performance['win_rate']:.1f}% • Average Trade: {performance['avg_trade']:+.2f}% • Best Trade: {performance['best_trade']:+.1f}% • Worst Trade: {performance['worst_trade']:+.1f}% Period: {buy_signals['entry_time'].min().strftime('%Y-%m-%d')} to {sell_signals['exit_time'].max().strftime('%Y-%m-%d')} """ # Add text box to the plot ax2.text(1.02, 0.98, perf_text, transform=ax2.transAxes, fontsize=10, verticalalignment='top', fontfamily='monospace', bbox=dict(boxstyle="round,pad=0.5", facecolor="lightgray", alpha=0.9)) # Adjust layout and save plt.tight_layout() plt.subplots_adjust(right=0.75) # Make room for text box plt.savefig(save_path, dpi=300, bbox_inches='tight') plt.show() print(f"Plot saved to: {save_path}") def main(): """Main function to run the analysis.""" print("🚀 Starting Original Strategy Analysis") print("=" * 50) # File paths trades_file = "../results/trades_15min(15min)_ST3pct.csv" output_file = "../results/original_strategy_analysis.png" if not os.path.exists(trades_file): print(f"❌ Error: Trades file not found: {trades_file}") return try: # Load and process trades buy_signals, sell_signals, portfolio_df, performance = load_and_process_trades(trades_file) # Print performance summary print(f"\n📊 PERFORMANCE SUMMARY:") print(f"Initial Value: ${performance['initial_value']:,.0f}") print(f"Final Value: ${performance['final_value']:,.0f}") print(f"Total Return: {performance['total_return']:+.1f}%") print(f"Number of Trades: {performance['num_trades']}") print(f"Win Rate: {performance['win_rate']:.1f}%") print(f"Average Trade: {performance['avg_trade']:+.2f}%") # Create plot create_comprehensive_plot(buy_signals, sell_signals, portfolio_df, performance, output_file) print(f"\n✅ Analysis completed successfully!") except Exception as e: print(f"❌ Error during analysis: {e}") import traceback traceback.print_exc() if __name__ == "__main__": main()