基于Python的策略开发与回测:双均线策略(附可视化代码)
基于Python的策略开发与回测:双均线策略(附可视化代码)
·
基于Python的策略开发与回测:双均线策略(附可视化代码)
1. 策略理论与市场逻辑
核心原理:
双均线策略基于移动平均线(Moving Average, MA)的滞后性特征,通过短期均线(MA50)和长期均线(MA200)的交叉点捕捉趋势变化:
- 金叉(Golden Cross):当短期均线从下方上穿长期均线,表明短期动能增强,可能开启上升趋势。
- 死叉(Death Cross):当短期均线从上方下穿长期均线,表明趋势可能反转,触发卖出信号。
数学公式:
- 简单移动平均线(SMA):
SMA n = 1 n ∑ i = 0 n − 1 P t − i \text{SMA}_n = \frac{1}{n} \sum_{i=0}^{n-1} P_{t-i} SMAn=n1i=0∑n−1Pt−i
其中 P P P 为收盘价, n n n 为窗口周期。 - 指数移动平均线(EMA):
EMA n = α ⋅ P t + ( 1 − α ) ⋅ EMA t − 1 , α = 2 n + 1 \text{EMA}_n = \alpha \cdot P_t + (1-\alpha) \cdot \text{EMA}_{t-1}, \quad \alpha = \frac{2}{n+1} EMAn=α⋅Pt+(1−α)⋅EMAt−1,α=n+12
参数选择依据:
- 趋势敏感性平衡:
- MA50(短期):快速响应价格变化,但易受噪声干扰
- MA200(长期):过滤短期波动,但信号滞后明显
- 市场周期适配:
- 股票市场常用50/200日均线(对应季度/年度趋势)
- 加密货币市场可能缩短至20/50日(高波动性)
2. 策略优化与进阶技巧
参数自适应优化
# 根据波动率动态调整均线周期
def dynamic_window(volatility, base_window=50, volatility_threshold=0.3):
"""
volatility: 近期波动率(如20日标准差)
base_window: 基础窗口(如50日)
volatility_threshold: 波动率阈值
"""
if volatility > volatility_threshold:
return int(base_window * 0.7) # 高波动缩短窗口
else:
return base_window
复合信号过滤
- 结合动量指标:仅在RSI(相对强弱指标)处于合理区间时接受信号
data['RSI'] = talib.RSI(data['Close'], timeperiod=14) valid_buy = (data['MA50'] > data['MA200']) & (data['RSI'] < 70) valid_sell = (data['MA50'] < data['MA200']) & (data['RSI'] > 30)
- 成交量确认:金叉/死叉时要求成交量高于20日均量
data['Volume_MA20'] = data['Volume'].rolling(20).mean() valid_signal = data['Volume'] > data['Volume_MA20']
3. 风险控制方案
-
动态止损机制:
- 跟踪止损:价格从最高点回撤5%时平仓
data['Peak'] = data['Close'].cummax() data['Trailing_Stop'] = data['Peak'] * 0.95
- 波动率止损:基于ATR(平均真实波幅)设定止损距离
data['ATR'] = talib.ATR(data['High'], data['Low'], data['Close'], 14) data['Vol_Stop'] = data['Close'] - 3 * data['ATR']
- 跟踪止损:价格从最高点回撤5%时平仓
-
仓位管理:
- 凯利公式:根据胜率和盈亏比计算最优仓位
f = p ⋅ ( b + 1 ) − 1 b f = \frac{p \cdot (b+1) -1}{b} f=bp⋅(b+1)−1
其中 p p p 为胜率, b b b 为平均盈利/平均亏损
- 凯利公式:根据胜率和盈亏比计算最优仓位
-
回撤期冻结:当连续5次交易亏损时,暂停策略并发出警报
4. 可视化代码
1. 策略原理与可视化代码
步骤1:生成模拟价格数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import norm
# 生成随机游走价格序列(1000天)
np.random.seed(42)
days = 1000
returns = norm.rvs(loc=0.0005, scale=0.02, size=days) # 带漂移项的布朗运动
price = np.cumprod(1 + returns) * 100 # 初始价格100元
# 构建时间序列数据框
dates = pd.date_range(start='2020-01-01', periods=days)
data = pd.DataFrame({'Close': price}, index=dates)
步骤2:计算均线并绘制趋势图
# 计算双均线
data['MA50'] = data['Close'].rolling(50, min_periods=1).mean()
data['MA200'] = data['Close'].rolling(200, min_periods=1).mean()
# 创建画布
plt.figure(figsize=(12, 6))
# 绘制价格与均线
plt.plot(data['Close'], label='Price', color='#1f77b4', alpha=0.7, linewidth=1.5)
plt.plot(data['MA50'], label='MA50', linestyle='--', color='#ff7f0e', linewidth=2)
plt.plot(data['MA200'], label='MA200', linestyle='--', color='#2ca02c', linewidth=2)
# 标注金叉/死叉
cross_points = data[data['MA50'].gt(data['MA200']) != data['MA50'].shift(1).gt(data['MA200'].shift(1))]
for idx, row in cross_points.iterrows():
if row['MA50'] > row['MA200']:
plt.scatter(idx, row['Close'], color='green', marker='^', s=100, zorder=3)
else:
plt.scatter(idx, row['Close'], color='red', marker='v', s=100, zorder=3)
# 图表装饰
plt.title('Dual Moving Average Crossover Strategy\n(Golden Cross/Death Cross Signals)', pad=20)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Price', fontsize=12)
plt.legend(loc='upper left')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
生成图像说明:
- 蓝色曲线为模拟价格走势
- 橙色虚线为50日均线,绿色虚线为200日均线
- 绿色▲标记金叉买入信号,红色▼标记死叉卖出信号
2. 参数优化可视化
# 生成参数网格数据
fast_windows = [30, 50, 70]
slow_windows = [150, 200, 250]
sharpe_matrix = np.array([
[1.32, 1.28, 1.15],
[1.45, 1.37, 1.22],
[1.27, 1.19, 1.08]
])
# 创建热力图
plt.figure(figsize=(10, 6))
heatmap = plt.imshow(sharpe_matrix, cmap='RdYlGn')
# 坐标轴设置
plt.xticks(np.arange(len(slow_windows)), labels=slow_windows)
plt.yticks(np.arange(len(fast_windows)), labels=fast_windows)
plt.xlabel('Slow Window Size', fontsize=12)
plt.ylabel('Fast Window Size', fontsize=12)
plt.title('Parameter Optimization Heatmap\n(Sharpe Ratio Comparison)', pad=15)
# 添加数值标签
for i in range(len(fast_windows)):
for j in range(len(slow_windows)):
text = plt.text(j, i, f'{sharpe_matrix[i, j]:.2f}',
ha="center", va="center", color="black")
# 颜色条
cbar = plt.colorbar(heatmap)
cbar.set_label('Sharpe Ratio', rotation=270, labelpad=20)
plt.tight_layout()
plt.show()
生成图像说明:
- X轴为慢速均线周期,Y轴为快速均线周期
- 颜色越绿表示夏普比率越高,红色表示较低
- 单元格数值显示具体夏普比率
3. 回测结果可视化
# 生成模拟净值曲线
np.random.seed(42)
strategy_returns = np.random.normal(loc=0.0008, scale=0.015, size=days)
benchmark_returns = np.random.normal(loc=0.0005, scale=0.012, size=days)
strategy_net = np.cumprod(1 + strategy_returns) * 100
benchmark_net = np.cumprod(1 + benchmark_returns) * 100
# 绘制净值对比图
plt.figure(figsize=(12, 6))
plt.plot(dates, strategy_net, label='Strategy', color='#2ca02c', linewidth=2)
plt.plot(dates, benchmark_net, label='Benchmark', color='#1f77b4', linestyle='--', linewidth=2)
# 最大回撤标注
max_drawdown = (strategy_net - np.maximum.accumulate(strategy_net)).min()
plt.fill_between(dates, strategy_net, np.maximum.accumulate(strategy_net),
color='red', alpha=0.3, label=f'Max Drawdown: {max_drawdown:.1%}')
# 图表装饰
plt.title('Strategy vs Benchmark Performance', pad=15)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Net Value', fontsize=12)
plt.legend(loc='upper left')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
生成图像说明:
- 实线为策略净值曲线,虚线为基准净值曲线
- 红色阴影区域表示策略最大回撤区间
- Y轴标准化为100起始净值
操作说明:
- 按顺序执行代码块
- 每个plt.show()会弹出独立图像窗口
- 右键图像选择"Save image as…"可保存本地图片
- 调整figsize参数控制图像尺寸
更多推荐
所有评论(0)