回测与风险管理
回测和风险管理是量化投资中最重要的两个环节——一个验证策略是否有效,一个确保策略不会让你爆仓。
为什么需要回测?
回测就是用历史数据模拟策略的交易过程,验证策略的表现。
不经过回测就实盘 = 拿真金白银赌博。
好的回测需要验证:
- 策略在历史上各种市场环境中表现如何?
- 最大亏损是多少?你能承受吗?
- 策略在最近几年是否失效?
通用回测框架
import pandas as pd
import numpy as np
def backtest_strategy(df, initial_capital=100000, commission=0.0003):
"""
通用策略回测框架
参数:
df: 包含 close 和 signal 列的 DataFrame
signal: 持仓信号 (0=空仓, 1=持有)
initial_capital: 初始资金
commission: 手续费率
"""
df = df.copy()
capital = initial_capital
position = 0 # 持股数量
trades = [] # 交易记录
portfolio_values = [] # 每日市值
for i in range(1, len(df)):
date = df.index[i]
price = df['close'].iloc[i]
signal = df['signal'].iloc[i]
prev_signal = df['signal'].iloc[i - 1]
# 买入信号:从空仓变持仓
if signal == 1 and prev_signal == 0 and position == 0:
shares = int(capital * (1 - commission) // price)
if shares > 0:
cost = shares * price * (1 + commission)
capital -= cost
position = shares
trades.append({
'date': date, 'type': 'BUY',
'price': price, 'shares': shares, 'cost': cost
})
# 卖出信号:从持仓变空仓
elif signal == 0 and prev_signal == 1 and position > 0:
revenue = position * price * (1 - commission)
capital += revenue
trades.append({
'date': date, 'type': 'SELL',
'price': price, 'shares': position, 'revenue': revenue
})
position = 0
# 记录每日市值
total_value = capital + position * price
portfolio_values.append({'date': date, 'value': total_value})
# 最后强平
if position > 0:
last_price = df['close'].iloc[-1]
capital += position * last_price
# 生成回测报告
portfolio = pd.DataFrame(portfolio_values).set_index('date')
final_value = capital
return {
'portfolio': portfolio,
'trades': pd.DataFrame(trades),
'final_capital': final_value,
'total_return': (final_value - initial_capital) / initial_capital
}
回测绩效指标
def calculate_performance_metrics(portfolio_df, risk_free_rate=0.02):
"""
计算策略绩效指标
"""
df = portfolio_df.copy()
# 日收益率
df['daily_return'] = df['value'].pct_change()
# 1. 累计收益率
total_return = df['value'].iloc[-1] / df['value'].iloc[0] - 1
# 2. 年化收益率
n_days = len(df)
annual_return = (1 + total_return) ** (252 / n_days) - 1
# 3. 年化波动率
annual_volatility = df['daily_return'].std() * np.sqrt(252)
# 4. 夏普比率
excess_returns = df['daily_return'] - risk_free_rate / 252
sharpe_ratio = np.sqrt(252) * excess_returns.mean() / df['daily_return'].std()
# 5. 最大回撤
cummax = df['value'].cummax()
drawdown = (df['value'] - cummax) / cummax
max_drawdown = drawdown.min()
# 6. 卡尔玛比率(收益/最大回撤)
calmar_ratio = annual_return / abs(max_drawdown) if max_drawdown != 0 else np.inf
# 7. 胜率
win_rate = (df['daily_return'] > 0).sum() / df['daily_return'].dropna().shape[0]
print("=" * 50)
print("策略绩效报告")
print("=" * 50)
print(f"累计收益率: {total_return*100:>8.2f}%")
print(f"年化收益率: {annual_return*100:>8.2f}%")
print(f"年化波动率: {annual_volatility*100:>8.2f}%")
print(f"夏普比率: {sharpe_ratio:>8.2f}")
print(f"最大回撤: {max_drawdown*100:>8.2f}%")
print(f"卡尔玛比率: {calmar_ratio:>8.2f}")
print(f"胜率: {win_rate*100:>8.2f}%")
print("=" * 50)
return {
'total_return': total_return,
'annual_return': annual_return,
'annual_volatility': annual_volatility,
'sharpe_ratio': sharpe_ratio,
'max_drawdown': max_drawdown,
'calmar_ratio': calmar_ratio,
'win_rate': win_rate
}