3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 漩涡指标 (Vortex Indicator, VI) 的聚宽 (JoinQuant) 交易策略脚本。
漩涡指标 (VI) 由两条线组成:$VI^+$ (正向漩涡) 和 $VI^-$ (负向漩涡)。
交易信号:
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
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')
# 设定全局变量
# 设定要操作的标的,这里以平安银行为例
g.security = '000001.XSHE'
# 漩涡指标的周期参数,通常为14
g.n = 14
# 每天开盘时运行策略
run_daily(market_open, time='09:30')
def calculate_vortex(security, n):
"""
计算漩涡指标 (VI)
返回: VI_plus, VI_minus
"""
# 获取历史数据,需要 n+1 天的数据来计算 n 个周期的变动
# fields: 最高价, 最低价, 收盘价
df = attribute_history(security, n + 1, '1d', ['high', 'low', 'close'])
if len(df) < n + 1:
return None, None
# 提取数据
high = df['high']
low = df['low']
close = df['close']
# 计算真实波幅 (True Range, TR)
# TR = Max(High-Low, Abs(High-PrevClose), Abs(Low-PrevClose))
tr1 = high - low
tr2 = abs(high - close.shift(1))
tr3 = abs(low - close.shift(1))
# 拼接成DataFrame取最大值,axis=1表示按行取最大值
tr_df = pd.concat([tr1, tr2, tr3], axis=1)
true_range = tr_df.max(axis=1)
# 计算正向和负向移动 (VM+, VM-)
# VM+ = Abs(CurrentHigh - PrevLow)
# VM- = Abs(CurrentLow - PrevHigh)
vm_plus = abs(high - low.shift(1))
vm_minus = abs(low - high.shift(1))
# 去除第一行(因为shift导致第一行为NaN)
true_range = true_range.iloc[1:]
vm_plus = vm_plus.iloc[1:]
vm_minus = vm_minus.iloc[1:]
# 计算周期内的总和
sum_tr = true_range.sum()
sum_vm_plus = vm_plus.sum()
sum_vm_minus = vm_minus.sum()
# 避免除以0的错误
if sum_tr == 0:
return 0, 0
# 计算 VI+ 和 VI-
vi_plus = sum_vm_plus / sum_tr
vi_minus = sum_vm_minus / sum_tr
return vi_plus, vi_minus
def market_open(context):
"""
每日交易逻辑
"""
security = g.security
# 计算当前的 VI 指标
vi_plus, vi_minus = calculate_vortex(security, g.n)
if vi_plus is None or vi_minus is None:
log.info("数据不足,跳过计算")
return
# 获取当前持仓
curr_position = context.portfolio.positions[security].total_amount
# 获取当前可用资金
cash = context.portfolio.available_cash
# 记录指标值方便回测查看
record(VI_Plus=vi_plus, VI_Minus=vi_minus)
# 交易逻辑
# 1. 买入信号: VI+ 上穿 VI- (即 VI+ > VI-) 且当前无持仓
if vi_plus > vi_minus and curr_position == 0:
# 全仓买入
order_value(security, cash)
log.info("买入信号触发: VI+ ({:.4f}) > VI- ({:.4f}), 买入 {}".format(vi_plus, vi_minus, security))
# 2. 卖出信号: VI- 上穿 VI+ (即 VI+ < VI-) 且当前有持仓
elif vi_plus < vi_minus and curr_position > 0:
# 清仓卖出
order_target(security, 0)
log.info("卖出信号触发: VI+ ({:.4f}) < VI- ({:.4f}), 卖出 {}".format(vi_plus, vi_minus, security))
attribute_history 获取过去 N+1 天的最高价、最低价和收盘价。多取一天是因为计算变动量(VM)和真实波幅(TR)需要用到前一日的数据(shift(1))。record() 函数,在回测图表中绘制 VI+ 和 VI- 的曲线,便于观察交叉点。Q: 如何修改策略操作的股票?
A: 在 initialize 函数中,修改 g.security = '000001.XSHE' 这一行,将代码替换为您想要回测的股票代码即可。
Q: 如何修改漩涡指标的周期?
A: 默认周期为 14 天。您可以在 initialize 函数中修改 g.n = 14,例如改为 g.n = 21 以适应更长周期的趋势判断。
Q: 这个策略可以用于多只股票吗?
A: 当前代码是针对单只股票设计的。如果需要操作多只股票,需要将 g.security 改为股票列表(如 g.stocks = ['000001.XSHE', '600519.XSHG']),并在 market_open 函数中使用 for 循环遍历列表,对每只股票分别计算指标和下单。
Q: 为什么计算 TR 时要用 shift(1)?
A: 漩涡指标的计算公式中,部分逻辑(如 VM+ 和 VM-)依赖于“昨日”的价格(昨日最低价或昨日最高价)。在 Pandas 中,shift(1) 用于获取上一行的数据,从而实现当前行与前一行数据的运算。