Local changes: Updated model training, removed debug instrumentation, and configuration improvements
This commit is contained in:
85
src/backtesting/metrics.py
Normal file
85
src/backtesting/metrics.py
Normal file
@@ -0,0 +1,85 @@
|
||||
"""Performance metrics for backtesting."""
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import Dict, List, Any, Optional
|
||||
from src.trading.paper_trading import PaperTradingSimulator
|
||||
|
||||
class BacktestMetrics:
|
||||
"""Calculates backtest performance metrics."""
|
||||
|
||||
def calculate_metrics(
|
||||
self,
|
||||
simulator: PaperTradingSimulator,
|
||||
trades: List[Dict[str, Any]],
|
||||
initial_capital: Decimal,
|
||||
total_fees: Optional[Decimal] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Calculate backtest metrics, including fee-adjusted metrics.
|
||||
|
||||
Args:
|
||||
simulator: Paper trading simulator
|
||||
trades: List of executed trades (may include 'fee' field)
|
||||
initial_capital: Initial capital
|
||||
total_fees: Total fees paid (if None, calculated from trades)
|
||||
|
||||
Returns:
|
||||
Dictionary of metrics
|
||||
"""
|
||||
final_value = simulator.get_portfolio_value()
|
||||
|
||||
# Calculate total fees if not provided
|
||||
if total_fees is None:
|
||||
total_fees = sum(
|
||||
Decimal(str(trade.get('fee', 0))) for trade in trades
|
||||
)
|
||||
|
||||
# Gross return (before fees)
|
||||
gross_return = ((final_value - initial_capital) / initial_capital) * 100 if initial_capital > 0 else 0
|
||||
|
||||
# Net return (after fees) - fees are already deducted in simulator
|
||||
# But we calculate what return would be without fees for comparison
|
||||
value_without_fees = final_value + total_fees
|
||||
net_return = ((final_value - initial_capital) / initial_capital) * 100 if initial_capital > 0 else 0
|
||||
gross_return_without_fees = ((value_without_fees - initial_capital) / initial_capital) * 100 if initial_capital > 0 else 0
|
||||
|
||||
# Fee impact
|
||||
fee_impact = gross_return_without_fees - net_return
|
||||
|
||||
# Calculate win rate from trades
|
||||
win_rate = self._calculate_win_rate(trades)
|
||||
|
||||
return {
|
||||
"initial_capital": float(initial_capital),
|
||||
"final_capital": float(final_value),
|
||||
"total_return": float(net_return), # Net return (after fees)
|
||||
"gross_return": float(gross_return_without_fees), # Gross return (before fees)
|
||||
"total_fees": float(total_fees),
|
||||
"fee_impact_percent": float(fee_impact),
|
||||
"fee_percentage": float((total_fees / initial_capital) * 100) if initial_capital > 0 else 0.0,
|
||||
"total_trades": len(trades),
|
||||
"win_rate": win_rate,
|
||||
"sharpe_ratio": 0.0, # Placeholder - would need returns series
|
||||
"max_drawdown": 0.0, # Placeholder - would need equity curve
|
||||
}
|
||||
|
||||
def _calculate_win_rate(self, trades: List[Dict[str, Any]]) -> float:
|
||||
"""Calculate win rate from trades.
|
||||
|
||||
Args:
|
||||
trades: List of trades
|
||||
|
||||
Returns:
|
||||
Win rate (0.0 to 1.0)
|
||||
"""
|
||||
if len(trades) < 2:
|
||||
return 0.0
|
||||
|
||||
# Simple approach: count buy-sell pairs
|
||||
# This is a simplified calculation - full implementation would track positions
|
||||
wins = 0
|
||||
total_pairs = 0
|
||||
|
||||
# Group trades by symbol and calculate pairs
|
||||
# For now, return placeholder
|
||||
return 0.5
|
||||
|
||||
Reference in New Issue
Block a user