Backtesting Engine Reference
The backtesting engine provides a comprehensive framework for testing trading strategies against historical data with realistic market conditions.
Overview
The backtesting engine delivers:
Strategy Testing: Comprehensive framework for testing trading strategies against historical data
Realistic Conditions: Transaction costs, slippage, and portfolio management constraints
Performance Analytics: Detailed metrics including Sharpe ratio, max drawdown, and alpha/beta
Custom Strategies: Extensible architecture for implementing custom trading algorithms
API Integration: RESTful endpoints for programmatic strategy execution
Models Reference
Core Models
Strategy Types
Built-in Strategy Types
- STRATEGY_TYPES
Available strategy types:
buy_hold- Buy and hold strategymoving_average- Moving average crossover strategyrsi- RSI mean reversion strategycustom- Custom user-defined strategy
Buy & Hold Strategy
Simple buy and hold implementation:
from personal_finance.backtesting.services import create_strategy
from personal_finance.backtesting.models import Backtest
from personal_finance.backtesting.services import BacktestEngine
from personal_finance.assets.models import Asset
from datetime import date
# Create strategy
strategy = create_strategy(
user=user,
name="S&P 500 Buy & Hold",
strategy_type="buy_hold",
parameters={},
asset_symbols=["SPY"],
initial_capital=100000.0,
max_position_size=1.0
)
# Execute backtest
benchmark = Asset.objects.get(symbol="SPY")
backtest = Backtest.objects.create(
strategy=strategy,
name="2-Year Buy & Hold Test",
start_date=date(2022, 1, 1),
end_date=date(2024, 1, 1),
benchmark_asset=benchmark
)
engine = BacktestEngine()
result = engine.run_backtest(backtest)
Moving Average Strategy
Moving average crossover strategy:
# Moving average parameters
ma_strategy = create_strategy(
user=user,
name="AAPL Moving Average Strategy",
strategy_type="moving_average",
parameters={
"short_window": 20, # 20-day MA
"long_window": 50, # 50-day MA
},
asset_symbols=["AAPL"],
initial_capital=50000.0,
max_position_size=0.5
)
# Include transaction costs
backtest = Backtest.objects.create(
strategy=ma_strategy,
name="AAPL MA Crossover",
start_date=date(2023, 1, 1),
end_date=date(2024, 1, 1),
transaction_costs=0.001, # 0.1%
slippage=0.0005 # 0.05%
)
RSI Strategy
RSI mean reversion with risk management:
rsi_strategy = create_strategy(
user=user,
name="Multi-Asset RSI Strategy",
strategy_type="rsi",
parameters={
"rsi_period": 14,
"oversold_threshold": 30,
"overbought_threshold": 70
},
asset_symbols=["AAPL", "MSFT", "GOOGL", "AMZN"],
initial_capital=100000.0,
max_position_size=0.25, # Max 25% per position
stop_loss_percentage=0.05, # 5% stop loss
take_profit_percentage=0.15 # 15% take profit
)
Custom Strategy Implementation
BaseStrategy Interface
Custom Strategy Example
from personal_finance.backtesting.services import BaseStrategy
from personal_finance.backtesting.models import Trade
from decimal import Decimal
class MeanReversionStrategy(BaseStrategy):
\"\"\"Custom mean reversion strategy based on price deviations.\"\"\"
def generate_signals(self, current_date, portfolio):
\"\"\"Generate trading signals based on price deviations.\"\"\"
trades = []
lookback_period = self.get_parameter('lookback_period', 20)
deviation_threshold = self.get_parameter('deviation_threshold', 2.0)
for asset in self.strategy.asset_universe.all():
if asset.symbol not in self.price_data.columns:
continue
# Calculate mean and standard deviation
asset_prices = self.price_data[asset.symbol].dropna()
recent_prices = asset_prices.tail(lookback_period)
if len(recent_prices) < lookback_period:
continue
mean_price = recent_prices.mean()
std_price = recent_prices.std()
current_price = asset_prices.loc[current_date]
deviation = (current_price - mean_price) / std_price
current_position = portfolio.get_position(asset.symbol)
max_position_value = portfolio.total_value * self.strategy.max_position_size
# Buy signal: price significantly below mean
if (deviation < -deviation_threshold and
current_position.quantity == 0):
quantity = max_position_value / Decimal(str(current_price))
trades.append(Trade(
asset=asset,
quantity=quantity,
trade_type='buy',
signal_strength=abs(Decimal(str(deviation))),
reason=f'Mean reversion buy: {deviation:.2f} std below mean'
))
# Sell signal: price significantly above mean
elif (deviation > deviation_threshold and
current_position.quantity > 0):
trades.append(Trade(
asset=asset,
quantity=current_position.quantity,
trade_type='sell',
signal_strength=Decimal(str(deviation)),
reason=f'Mean reversion sell: {deviation:.2f} std above mean'
))
return trades
# Register custom strategy
from personal_finance.backtesting.services import STRATEGY_REGISTRY
STRATEGY_REGISTRY['mean_reversion'] = MeanReversionStrategy
REST API Reference
Strategy Management
Backtest Execution
Quick Backtest
Management Commands
# Create and run buy & hold strategy
python manage.py run_backtest \\
--create-strategy buy_hold \\
--user admin \\
--assets SPY QQQ IWM \\
--period 3y \\
--initial-capital 100000 \\
--benchmark SPY
- --create-strategy <type>
Create strategy of specified type (buy_hold, moving_average, rsi)
- --user <username>
Run backtest for specified user
- --assets <symbols>
Space-separated list of asset symbols
- --period <period>
Time period (1y, 2y, 3y, or specific dates)
- --initial-capital <amount>
Initial capital amount
- --benchmark <symbol>
Benchmark asset symbol
- --dry-run
Preview without executing
Performance Analysis
Metrics Reference
Analysis Functions
def analyze_backtest(backtest_id):
\"\"\"Comprehensive backtest analysis.\"\"\"
from personal_finance.backtesting.models import Backtest
backtest = Backtest.objects.get(id=backtest_id)
result = backtest.result
print(f\"\\n=== Backtest Analysis: {backtest.name} ===\")
print(f\"Strategy: {backtest.strategy.name}\")
print(f\"Period: {backtest.start_date} to {backtest.end_date}\")
print(f\"Duration: {backtest.duration_days} days\")
print(f\"\\n--- Performance Metrics ---\")
print(f\"Total Return: {result.total_return:.2f}%\")
print(f\"Annualized Return: {result.annualized_return:.2f}%\")
print(f\"Volatility: {result.volatility:.2f}%\")
print(f\"Sharpe Ratio: {result.sharpe_ratio:.2f}\")
print(f\"Max Drawdown: {result.max_drawdown:.2f}%\")
if result.benchmark_return:
print(f\"\\n--- Benchmark Comparison ---\")
print(f\"Benchmark Return: {result.benchmark_return:.2f}%\")
print(f\"Alpha: {result.alpha:.2f}%\")
print(f\"Beta: {result.beta:.2f}\")
Parameter Optimization
Batch Testing
def run_parameter_sweep():
\"\"\"Run multiple backtests with different parameters.\"\"\"
from itertools import product
# Parameter ranges
short_windows = [10, 15, 20]
long_windows = [30, 45, 60]
assets_groups = [[\"SPY\"], [\"QQQ\"], [\"SPY\", \"QQQ\"]]
results = []
for short_window, long_window, assets in product(short_windows, long_windows, assets_groups):
if short_window >= long_window:
continue
# Create and run backtest
strategy = create_strategy(
user=user,
name=f\"MA_{short_window}_{long_window}_{'_'.join(assets)}\",
strategy_type=\"moving_average\",
parameters={
\"short_window\": short_window,
\"long_window\": long_window
},
asset_symbols=assets,
initial_capital=100000.0
)
backtest = Backtest.objects.create(
strategy=strategy,
name=f\"Parameter Sweep {short_window}/{long_window}\",
start_date=date(2022, 1, 1),
end_date=date(2024, 1, 1)
)
try:
result = engine.run_backtest(backtest)
results.append({
'short_window': short_window,
'long_window': long_window,
'assets': assets,
'total_return': float(result.total_return),
'sharpe_ratio': float(result.sharpe_ratio),
'max_drawdown': float(result.max_drawdown)
})
except Exception as e:
print(f\"Failed: {short_window}/{long_window} - {str(e)}\")
# Find best performing strategy
best_result = max(results, key=lambda x: x['sharpe_ratio'] or -999)
print(f\"Best Strategy: MA {best_result['short_window']}/{best_result['long_window']}\")
print(f\"Assets: {best_result['assets']}\")
print(f\"Sharpe Ratio: {best_result['sharpe_ratio']:.2f}\")
Error Handling
Data Validation
def validate_backtest_data(backtest):
\"\"\"Validate that backtest has sufficient data.\"\"\"
from personal_finance.assets.models import PriceHistory
missing_data = []
for asset in backtest.strategy.asset_universe.all():
price_count = PriceHistory.objects.filter(
asset=asset,
date__gte=backtest.start_date,
date__lte=backtest.end_date
).count()
expected_days = (backtest.end_date - backtest.start_date).days
if price_count < expected_days * 0.8: # Allow for weekends/holidays
missing_data.append(asset.symbol)
if missing_data:
print(f\"Warning: Insufficient data for: {missing_data}\")
return len(missing_data) == 0
Debug Failed Backtests
def debug_backtest_failure(backtest_id):
\"\"\"Debug a failed backtest.\"\"\"
backtest = Backtest.objects.get(id=backtest_id)
print(f\"Backtest: {backtest.name}\")
print(f\"Status: {backtest.status}\")
print(f\"Error: {backtest.error_message}\")
# Check strategy configuration
strategy = backtest.strategy
print(f\"\\nStrategy: {strategy.name}\")
print(f\"Type: {strategy.strategy_type}\")
print(f\"Assets: {list(strategy.asset_universe.values_list('symbol', flat=True))}\")
print(f\"Parameters: {strategy.parameters}\")
# Validate data availability
validate_backtest_data(backtest)
Performance Optimization
Database Optimization
# Use select_related and prefetch_related
backtests = Backtest.objects.select_related(
'strategy', 'benchmark_asset'
).prefetch_related(
'strategy__asset_universe'
)
# Batch create operations
from django.db import transaction
@transaction.atomic
def batch_create_snapshots(snapshots_data):
\"\"\"Batch create portfolio snapshots.\"\"\"
snapshots = [
BacktestPortfolioSnapshot(**data)
for data in snapshots_data
]
BacktestPortfolioSnapshot.objects.bulk_create(snapshots)
Memory Management
# Process large datasets with iterator
for backtest in Backtest.objects.filter(status='pending').iterator():
process_backtest(backtest)
# Limit date ranges for testing
short_backtest = Backtest.objects.create(
strategy=strategy,
name=\"Quick Test\",
start_date=date(2024, 1, 1),
end_date=date(2024, 2, 1) # One month for quick testing
)
See Also
REST API Endpoints Reference - Complete API reference
Analytics Module - Portfolio analytics integration
../development/testing - Testing strategies and backtests