基于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=0n1Pti
    其中 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α)EMAt1,α=n+12

参数选择依据

  1. 趋势敏感性平衡
    • MA50(短期):快速响应价格变化,但易受噪声干扰
    • MA200(长期):过滤短期波动,但信号滞后明显
  2. 市场周期适配
    • 股票市场常用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. 风险控制方案

  1. 动态止损机制

    • 跟踪止损:价格从最高点回撤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']  
      
  2. 仓位管理

    • 凯利公式:根据胜率和盈亏比计算最优仓位
      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 为平均盈利/平均亏损
  3. 回撤期冻结:当连续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起始净值

操作说明

  1. 按顺序执行代码块
  2. 每个plt.show()会弹出独立图像窗口
  3. 右键图像选择"Save image as…"可保存本地图片
  4. 调整figsize参数控制图像尺寸
Logo

更多推荐