问题描述
解决方案
这是一个基于布林带(Bollinger Bands)指标的均值回归交易策略。
策略原理
布林带由三条轨道线组成:
- 中轨:N日移动平均线(通常为20日)。
- 上轨:中轨 + K倍标准差(通常K=2)。
- 下轨:中轨 - K倍标准差。
交易逻辑:
- 买入信号:当股价跌破下轨时,认为股价被低估(超卖),进行买入。
- 卖出信号:当股价突破上轨时,认为股价被高估(超买),进行卖出平仓。
PTrade 策略代码
import numpy as np
import pandas as pd
def initialize(context):
"""
初始化函数,设置策略参数和股票池
"""
# 设置要操作的股票,这里以恒生电子为例
g.security = '600570.SS'
# 设置股票池
set_universe(g.security)
# 布林带参数设置
g.n = 20 # 计算均值的周期
g.k = 2 # 标准差的倍数
# 设置手续费(股票万三,最低5元)
set_commission(commission_ratio=0.0003, min_commission=5.0, type='STOCK')
# 设置滑点(0.1%)
set_slippage(slippage=0.001)
def handle_data(context, data):
"""
盘中运行函数,每日或每分钟执行一次
"""
security = g.security
# 获取过去 g.n 天的收盘价数据
# include=True 表示包含当前周期的收盘价(回测模式下为当日收盘价)
# 注意:为了计算准确的标准差,建议获取的数据长度等于周期 N
hist_data = get_history(g.n, frequency='1d', field='close', security_list=security, include=True)
# 确保数据长度足够,若不足则不进行计算
if len(hist_data) < g.n:
log.info("历史数据不足,跳过计算")
return
# 提取收盘价序列
close_prices = hist_data['close']
# --- 计算布林带指标 ---
# 1. 计算中轨(N日移动平均线)
mid_line = close_prices.mean()
# 2. 计算标准差
# ddof=1 表示样本标准差,ddof=0 表示总体标准差,通常金融计算使用样本标准差
std_dev = close_prices.std(ddof=1)
# 3. 计算上轨和下轨
upper_band = mid_line + g.k * std_dev
lower_band = mid_line - g.k * std_dev
# 获取当前最新价格
current_price = data[security]['close']
# 获取当前持仓数量
position = get_position(security).amount
# 获取当前可用现金
cash = context.portfolio.cash
# --- 交易逻辑 ---
# 信号1:价格跌破下轨,且当前无持仓 -> 买入
if current_price < lower_band and position == 0:
# 全仓买入
order_value(security, cash)
log.info("价格跌破下轨,买入 %s,价格:%.2f,下轨:%.2f" % (security, current_price, lower_band))
# 信号2:价格突破上轨,且有持仓 -> 卖出
elif current_price > upper_band and position > 0:
# 清空仓位
order_target(security, 0)
log.info("价格突破上轨,卖出 %s,价格:%.2f,上轨:%.2f" % (security, current_price, upper_band))
代码解析
initialize:- 定义了全局变量
g.n(周期20) 和g.k(倍数2)。 - 使用
set_commission和set_slippage设置交易成本,使回测更接近真实情况。
- 定义了全局变量
- 数据获取:
- 使用
get_history获取过去20天的收盘价。include=True确保计算包含当天的最新数据。
- 使用
- 指标计算:
- 利用
pandas的.mean()和.std()方法手动计算布林带,不依赖外部复杂的指标库,保证在PTrade环境中的兼容性。
- 利用
- 交易逻辑:
- 买入: 当
current_price < lower_band且空仓时,使用order_value全仓买入。 - 卖出: 当
current_price > upper_band且持有股票时,使用order_target将仓位调整为0(即清仓)。
- 买入: 当
Q&A
Q1: 如何修改布林带的周期参数?
A1: 在 initialize 函数中,修改 g.n = 20 中的数字即可。例如改为 g.n = 30 即为30日布林带。
Q2: 这个策略可以用于分钟级别回测吗?
A2: 可以。只需在回测设置中将频率选为“分钟”,并将 get_history 中的 frequency='1d' 改为 frequency='1m' (或其他分钟周期如 '5m', '30m')。
Q3: 为什么使用 get_history 而不是 talib 库?
A3: 虽然PTrade支持部分三方库,但直接使用 get_history 配合 pandas 计算逻辑更加透明,且不依赖外部库的版本,代码移植性和稳定性更高。
Q4: 策略中的 include=True 是什么意思?
A4: 在 get_history 中,include=True 表示获取的数据包含当前正在进行的这一根K线的数据。对于日线策略,这意味着使用当天的收盘价(回测时)或最新价(实盘时)来参与均线计算,这对于捕捉即时信号很重要。