问题描述
解决方案
这是一个基于抛物线转向指标(SAR, Stop and Reverse)的量化交易策略。
策略原理
SAR指标(Parabolic SAR)是一种趋势跟踪指标。
- 买入信号:当股价向上突破SAR曲线时,认为趋势转多,执行买入。
- 卖出信号:当股价向下突破SAR曲线时,认为趋势转空,执行卖出(清仓)。
- 参数设置:通常加速因子(Acceleration Factor, AF)初始值为0.02,每次递增0.02,最大值为0.2。
策略实现
以下是完整的策略代码,可以直接在聚宽(JoinQuant)的回测环境中运行。
# -*- coding: utf-8 -*-
# 导入聚宽函数库
import jqdata
import talib
import numpy as np
def initialize(context):
"""
初始化函数,设定基准、股票池、费用等
"""
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定要操作的股票,这里以平安银行为例
g.security = '000001.XSHE'
# SAR指标参数
g.sar_acceleration = 0.02 # 加速因子初始值
g.sar_maximum = 0.2 # 加速因子最大值
# 设定手续费:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 每天开盘时运行
run_daily(market_open, time='09:30')
def market_open(context):
"""
每日开盘运行的策略逻辑
"""
security = g.security
# 获取过去100天的最高价、最低价、收盘价数据
# SAR计算需要High和Low,Close用于判断信号
# 获取较长的数据以确保SAR指标计算稳定
data = attribute_history(security, 100, '1d', ['high', 'low', 'close'], skip_paused=True)
# 如果数据不足(例如新股),则跳过
if len(data) < 50:
return
# 将数据转换为numpy数组,talib需要float类型的numpy数组
high_prices = data['high'].values
low_prices = data['low'].values
close_prices = data['close'].values
# 使用talib库计算SAR
# real = SAR(high, low, acceleration=0, maximum=0)
try:
sar_values = talib.SAR(high_prices, low_prices,
acceleration=g.sar_acceleration,
maximum=g.sar_maximum)
except Exception as e:
log.error("计算SAR指标出错: %s" % e)
return
# 获取最新的SAR值和收盘价(这里的“最新”指的是前一交易日的收盘数据,用于指导今日交易)
current_sar = sar_values[-1]
current_close = close_prices[-1]
# 获取之前的SAR值和收盘价,用于判断交叉
prev_sar = sar_values[-2]
prev_close = close_prices[-2]
# 获取当前账户资金和持仓
cash = context.portfolio.available_cash
position = context.portfolio.positions[security]
# 交易逻辑
# 1. 买入信号:收盘价站上SAR曲线 (金叉)
# 为了避免频繁震荡,这里判断前一天在下方,最新一天在上方,或者持续在上方
if current_close > current_sar:
# 如果当前没有持仓,则全仓买入
if position.closeable_amount == 0:
log.info("买入信号触发:收盘价(%.2f) > SAR(%.2f)" % (current_close, current_sar))
order_value(security, cash)
# 2. 卖出信号:收盘价跌破SAR曲线 (死叉)
elif current_close < current_sar:
# 如果当前有持仓,则清仓卖出
if position.closeable_amount > 0:
log.info("卖出信号触发:收盘价(%.2f) < SAR(%.2f)" % (current_close, current_sar))
order_target(security, 0)
# 记录数据以便在回测图中查看
record(Price=current_close, SAR=current_sar)
常见问答 (Q&A)
Q1: 为什么代码中使用了 talib 库?
A1: talib (Technical Analysis Library) 是量化领域最常用的技术分析库,计算效率高且标准。聚宽平台内置了该库,可以直接调用 talib.SAR 来计算指标,避免手动编写公式可能出现的错误。
Q2: attribute_history 获取的是什么时间的数据?
A2: 在 run_daily 设置为 09:30 运行时,attribute_history 获取的是截止到前一个交易日收盘的数据。这是为了避免使用当天的未来数据(即在收盘前就预知了收盘价)。策略逻辑是基于昨日收盘价与SAR的关系来决定今日开盘的操作。
Q3: 如何调整SAR指标的灵敏度?
A3: 可以通过修改 initialize 函数中的 g.sar_acceleration (加速因子) 和 g.sar_maximum (最大值) 来调整。
- 增大加速因子(如0.03):SAR曲线会更紧贴价格,灵敏度提高,但可能导致频繁交易(假信号增加)。
- 减小加速因子(如0.01):SAR曲线会更平滑,对趋势反应较慢,但能过滤掉部分震荡。
Q4: 这个策略适合什么市场环境?
A4: SAR是典型的趋势跟踪指标,在单边趋势行情(持续上涨或下跌)中表现较好,能吃到大部分波段。但在横盘震荡行情中,价格会频繁穿梭于SAR曲线上下,导致策略频繁止损,产生磨损成本。建议结合其他指标(如ADX)来过滤震荡行情。