trading-algo/compare_strategies.py
Gal Podlipnik 69462cf3e0 first
2025-07-17 02:30:21 +02:00

270 lines
9.1 KiB
Python

#!/usr/bin/env python3
"""
Strategy Comparison Script
Runs both strategies and compares their performance.
"""
import sys
# Add src directory to path for imports
sys.path.append('src')
sys.path.append('config')
from src.logger_setup import setup_logging
from src.data_handler import DataHandler
from src.strategy_factory import get_strategy
import logging
def run_strategy_comparison():
"""Compare both strategies side by side"""
setup_logging()
logger = logging.getLogger(__name__)
print("=" * 80)
print("STRATEGY COMPARISON - CONSERVATIVE vs ENHANCED")
print("=" * 80)
try:
# Get data once for both strategies
data_handler = DataHandler()
bars = data_handler.get_historical_data(days=180)
if bars.empty:
print("❌ No historical data available")
return
# Calculate technical indicators
bars = data_handler.calculate_technical_indicators(bars)
strategies = ['conservative', 'enhanced']
results = {}
for strategy_type in strategies:
print(f"\n📊 Running {strategy_type.upper()} strategy...")
try:
# Create strategy
strategy = get_strategy(strategy_type)
# Generate signals
strategy_bars = bars.copy()
strategy_bars = strategy.generate_signals(strategy_bars)
# Run simulation
results[strategy_type] = run_strategy_simulation(strategy_bars, strategy)
print(f"{strategy.name} completed")
except Exception as e:
print(f"❌ Error running {strategy_type} strategy: {e}")
continue
# Display comparison
display_strategy_comparison(results)
except Exception as e:
logger.error(f"Error in strategy comparison: {e}")
print(f"❌ Comparison failed: {e}")
def run_strategy_simulation(bars, strategy):
"""Run simulation for a strategy"""
# Position tracking
position = 0
entry_price = None
highest_price_since_entry = None
bars_since_entry = 0
trades = []
bars['position'] = 0
for i in range(1, len(bars)):
current_price = bars['close'].iloc[i]
if bars['buy_signal'].iloc[i] and position == 0:
# Entry conditions
if strategy.get_entry_conditions(bars, i):
position = 1
entry_price = current_price
highest_price_since_entry = current_price
bars_since_entry = 0
elif position == 1:
bars_since_entry += 1
if current_price > highest_price_since_entry:
highest_price_since_entry = current_price
# Exit conditions
should_exit, exit_reason = strategy.should_exit_position(
current_price=current_price,
entry_price=entry_price,
highest_price=highest_price_since_entry,
bars_since_entry=bars_since_entry,
sell_signal=bars['sell_signal'].iloc[i],
ema_trend=bars['ema_trend'].iloc[i]
)
if should_exit:
# Record trade
profit_pct = (current_price / entry_price - 1)
trades.append({
'entry_price': entry_price,
'exit_price': current_price,
'profit_pct': profit_pct,
'bars_held': bars_since_entry,
'exit_reason': exit_reason
})
position = 0
entry_price = None
highest_price_since_entry = None
bars_since_entry = 0
bars.iloc[i, bars.columns.get_loc('position')] = position
# Calculate returns
bars['market_return'] = bars['close'].pct_change()
bars['strategy_return'] = bars['position'].shift(1) * bars['market_return']
# Apply costs
trade_cost = 0.0005
bars['position_change'] = bars['position'].diff().abs()
bars['costs'] = bars['position_change'] * trade_cost
bars['strategy_return'] = bars['strategy_return'] - bars['costs']
# Cumulative returns
bars['cum_strategy'] = (1 + bars['strategy_return']).cumprod() - 1
bars['cum_market'] = (1 + bars['market_return']).cumprod() - 1
# Calculate metrics
total_return = bars['cum_strategy'].iloc[-1] * 100
market_return = bars['cum_market'].iloc[-1] * 100
if len(trades) > 0:
import numpy as np
trade_returns = [t['profit_pct'] for t in trades]
trade_returns = np.array(trade_returns)
win_rate = (trade_returns > 0).mean() * 100
avg_win = trade_returns[trade_returns > 0].mean() * 100 if (trade_returns > 0).any() else 0
avg_loss = trade_returns[trade_returns < 0].mean() * 100 if (trade_returns < 0).any() else 0
max_win = trade_returns.max() * 100
max_loss = trade_returns.min() * 100
total_wins = trade_returns[trade_returns > 0].sum()
total_losses = abs(trade_returns[trade_returns < 0].sum())
profit_factor = total_wins / total_losses if total_losses > 0 else float('inf')
else:
win_rate = avg_win = avg_loss = max_win = max_loss = profit_factor = 0
# Max drawdown
running_max = bars['cum_strategy'].cummax()
drawdown = (bars['cum_strategy'] - running_max)
max_drawdown = drawdown.min() * 100
# Sharpe ratio
if bars['strategy_return'].std() > 0:
import numpy as np
sharpe = bars['strategy_return'].mean() / bars['strategy_return'].std() * np.sqrt(365 * 24)
else:
sharpe = 0
return {
'total_return': total_return,
'market_return': market_return,
'outperformance': total_return - market_return,
'sharpe_ratio': sharpe,
'max_drawdown': max_drawdown,
'total_trades': len(trades),
'win_rate': win_rate,
'profit_factor': profit_factor,
'avg_win': avg_win,
'avg_loss': avg_loss,
'max_win': max_win,
'max_loss': max_loss,
'time_in_market': (bars['position'] > 0).mean() * 100,
'trades': trades
}
def display_strategy_comparison(results):
"""Display side-by-side comparison"""
if len(results) < 2:
print("❌ Need at least 2 strategies to compare")
return
print("\n" + "=" * 100)
print("STRATEGY COMPARISON RESULTS")
print("=" * 100)
# Header
print(f"{'Metric':<25} {'Conservative':<20} {'Enhanced':<20} {'Difference':<15}")
print("-" * 100)
conservative = results.get('conservative', {})
enhanced = results.get('enhanced', {})
metrics = [
('Total Return', 'total_return', '%'),
('Market Return', 'market_return', '%'),
('Outperformance', 'outperformance', '%'),
('Sharpe Ratio', 'sharpe_ratio', ''),
('Max Drawdown', 'max_drawdown', '%'),
('Total Trades', 'total_trades', ''),
('Win Rate', 'win_rate', '%'),
('Profit Factor', 'profit_factor', ''),
('Avg Win', 'avg_win', '%'),
('Avg Loss', 'avg_loss', '%'),
('Max Win', 'max_win', '%'),
('Max Loss', 'max_loss', '%'),
('Time in Market', 'time_in_market', '%'),
]
for display_name, key, unit in metrics:
cons_val = conservative.get(key, 0)
enh_val = enhanced.get(key, 0)
diff = enh_val - cons_val
if unit == '%':
cons_str = f"{cons_val:>8.2f}%"
enh_str = f"{enh_val:>8.2f}%"
diff_str = f"{diff:>+8.2f}%"
else:
cons_str = f"{cons_val:>8.2f}"
enh_str = f"{enh_val:>8.2f}"
diff_str = f"{diff:>+8.2f}"
print(f"{display_name:<25} {cons_str:<20} {enh_str:<20} {diff_str:<15}")
print("=" * 100)
# Summary
print("\n📋 SUMMARY:")
if enhanced.get('total_return', 0) > conservative.get('total_return', 0):
winner = "Enhanced"
return_diff = enhanced.get('total_return', 0) - conservative.get('total_return', 0)
else:
winner = "Conservative"
return_diff = conservative.get('total_return', 0) - enhanced.get('total_return', 0)
print(f"🏆 Best performing strategy: {winner} (+{return_diff:.2f}% return)")
# Risk comparison
cons_risk = abs(conservative.get('max_drawdown', 0))
enh_risk = abs(enhanced.get('max_drawdown', 0))
if cons_risk < enh_risk:
print(f"🛡️ Lower risk strategy: Conservative ({cons_risk:.2f}% max drawdown)")
else:
print(f"🛡️ Lower risk strategy: Enhanced ({enh_risk:.2f}% max drawdown)")
print("\n💡 RECOMMENDATIONS:")
print("• Conservative: Better for letting big winners run, more relaxed exits")
print("• Enhanced: Better risk control, tighter stops for early losses")
print("• Choose based on your risk tolerance and market conditions")
if __name__ == "__main__":
run_strategy_comparison()