问题描述
解决方案
这是一个基于 BIAS (乖离率) 指标的均值回归策略。
策略原理
BIAS (乖离率) 是测量股价偏离移动平均线大小程度的指标。
- 公式:$BIAS(N) = \frac{收盘价 - N日移动平均价}{N日移动平均价} \times 100%$
- 核心逻辑:
- 当股价严重偏离均线向下(负乖离率过大)时,认为市场超卖,股价有向均线回归的动力,此时买入。
- 当股价严重偏离均线向上(正乖离率过大)时,认为市场超买,股价有回调的风险,此时卖出。
策略代码
以下代码可以直接在聚宽(JoinQuant)的回测环境中运行。
# -*- coding: utf-8 -*-
import jqdata
def initialize(context):
"""
初始化函数,设定基准、手续费、策略参数等
"""
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# --- 策略参数设置 ---
# 操作的标的:这里以平安银行为例,也可以换成ETF如 '510300.XSHG'
g.security = '000001.XSHE'
# 均线周期 N
g.N = 20
# 买入阈值:当 BIAS 低于此值(负数)时买入
g.buy_threshold = -6.0
# 卖出阈值:当 BIAS 高于此值(正数)时卖出
g.sell_threshold = 6.0
# 每天开盘时运行
run_daily(market_open, time='09:30')
def market_open(context):
"""
每日交易逻辑
"""
security = g.security
# 获取过去 N 天的收盘价数据
# 注意:这里取 N 天,包含昨天。我们用昨天收盘价计算 BIAS 信号,今天开盘执行。
# 这样避免了未来函数(即在收盘前不知道当天的最终收盘价)
hist_data = attribute_history(security, g.N, '1d', ['close'])
# 如果数据不足 N 天,不进行计算
if len(hist_data) < g.N:
return
# 1. 计算 N 日移动平均线 (MA)
ma_n = hist_data['close'].mean()
# 2. 获取最近一个交易日(昨天)的收盘价
current_price = hist_data['close'][-1]
# 3. 计算 BIAS 乖离率
# 公式:(收盘价 - 均线) / 均线 * 100
bias_value = (current_price - ma_n) / ma_n * 100
# 记录 BIAS 值,可以在回测图表中查看曲线
record(BIAS=bias_value)
# --- 交易决策 ---
# 获取当前现金和持仓
cash = context.portfolio.available_cash
position = context.portfolio.positions[security].total_amount
# 信号 1: 超卖(BIAS < 买入阈值),且当前无持仓 -> 全仓买入
if bias_value <= g.buy_threshold and position == 0:
# 用所有现金买入
order_value(security, cash)
log.info("BIAS: %.2f%% 触发超卖信号,买入 %s" % (bias_value, security))
# 信号 2: 超买(BIAS > 卖出阈值),且有持仓 -> 清仓卖出
elif bias_value >= g.sell_threshold and position > 0:
# 卖出所有持仓
order_target(security, 0)
log.info("BIAS: %.2f%% 触发超买信号,卖出 %s" % (bias_value, security))
代码关键点解析
-
参数设置 (
g.N,g.buy_threshold,g.sell_threshold):g.N = 20: 使用20日均线(月线)作为基准。g.buy_threshold = -6.0: 当股价低于20日均线6%时,视为超跌,执行买入。g.sell_threshold = 6.0: 当股价高于20日均线6%时,视为超涨,执行卖出。- 注:不同波动率的股票适合不同的阈值,大盘股阈值绝对值可以设小一点(如±4%),小盘股或高波动标的可以设大一点(如±8%)。
-
数据获取 (
attribute_history):- 我们获取了过去
g.N天的数据。 - 计算逻辑使用的是昨天的收盘价和截止到昨天的均线。这是为了在今天开盘(09:30)时能立即下单。如果在盘中实时计算,需要使用分钟级数据或
get_current_data。
- 我们获取了过去
-
交易执行 (
order_value,order_target):- 策略设计为全仓买卖(All-in/All-out),简单直接。
order_value(security, cash): 用当前所有可用资金买入。order_target(security, 0): 将持仓调整为0,即清仓。
优化建议 (Q&A)
Q: 如何让策略更稳健?
A: 单纯的 BIAS 策略在单边下跌趋势中可能会过早抄底导致被套(俗称“接飞刀”)。可以增加一个趋势过滤器,例如:只有当 60日均线向上时,才允许做 BIAS 的超跌反弹。
Q: 可以应用到多只股票吗?
A: 可以。将 g.security 改为一个列表(如 get_index_stocks('000300.XSHG')),然后在 market_open 中使用 for 循环遍历每只股票进行判断即可。
Q: 阈值该如何选择?
A: 建议使用聚宽的研究模块,统计目标股票历史上 BIAS 的分布情况(例如取 5% 和 95% 分位数),以此作为买卖阈值会比凭感觉设定更科学。