问题描述
解决方案
这是一个基于 阿隆指标(Aroon Indicator) 的 QMT 量化交易策略。
策略原理
阿隆指标由 Aroon Up(上线) 和 Aroon Down(下线) 两条线组成,用于判断趋势的强弱和方向:
- Aroon Up: 反映价格创新高的能力。
- Aroon Down: 反映价格创新低的能力。
交易逻辑:
- 趋势开始(买入信号):当
Aroon Up上穿Aroon Down时,表明上升趋势可能开始,执行买入。 - 趋势结束/反转(卖出信号):当
Aroon Down上穿Aroon Up时,表明上升趋势结束或下降趋势开始,执行卖出(清仓)。
策略代码
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
import talib
def init(ContextInfo):
"""
初始化函数,设定参数和账户
"""
# 设定资金账号 (请替换为您自己的资金账号)
ContextInfo.accid = '6666666666'
ContextInfo.set_account(ContextInfo.accid)
# 设定标的股票 (例如:平安银行)
ContextInfo.stock_code = '000001.SZ'
# 设定阿隆指标的周期 (通常为14或25)
ContextInfo.period = 25
# 设定回测/运行的股票池
ContextInfo.set_universe([ContextInfo.stock_code])
print("策略初始化完成,标的:{}, 阿隆周期:{}".format(ContextInfo.stock_code, ContextInfo.period))
def handlebar(ContextInfo):
"""
K线逐根运行函数
"""
# 获取当前正在处理的K线索引
index = ContextInfo.barpos
# 获取当前图表的时间
realtime = ContextInfo.get_bar_timetag(index)
# 设定获取历史数据的数量 (需要比计算周期多一些,以确保指标能计算出来)
count = ContextInfo.period + 50
# 获取行情数据 (使用 get_market_data_ex 接口)
#我们需要 High 和 Low 价格来计算 Aroon
data_map = ContextInfo.get_market_data_ex(
['high', 'low', 'close'],
[ContextInfo.stock_code],
period=ContextInfo.period, # 这里period参数指的是K线周期,如'1d',但在ContextInfo对象里period属性通常存的是'1d'
count=count,
dividend_type='front', # 前复权
subscribe=True
)
# 提取该标的的数据 DataFrame
if ContextInfo.stock_code not in data_map:
return
df = data_map[ContextInfo.stock_code]
# 确保数据量足够计算指标
if len(df) < ContextInfo.period + 1:
return
# 将数据转换为 numpy 数组供 talib 使用
high_prices = df['high'].values
low_prices = df['low'].values
# 使用 TA-Lib 计算 Aroon 指标
# aroon_down, aroon_up = talib.AROON(high, low, timeperiod=14)
try:
aroon_down, aroon_up = talib.AROON(high_prices, low_prices, timeperiod=ContextInfo.period)
except Exception as e:
print("指标计算错误:", e)
return
# 获取最新的指标值 (当前K线) 和 上一根K线的值
# -1 代表当前最新值,-2 代表上一根K线的值
curr_up = aroon_up[-1]
curr_down = aroon_down[-1]
prev_up = aroon_up[-2]
prev_down = aroon_down[-2]
# 获取当前持仓
positions = get_trade_detail_data(ContextInfo.accid, 'stock', 'position')
current_holding = 0
for pos in positions:
if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == ContextInfo.stock_code:
current_holding = pos.m_nVolume
break
# --- 交易逻辑 ---
# 1. 买入信号:Aroon Up 上穿 Aroon Down (金叉)
# 逻辑:当前 Up > Down 且 上一刻 Up <= Down
if curr_up > curr_down and prev_up <= prev_down:
if current_holding == 0:
print(f"[{timetag_to_datetime(realtime, '%Y-%m-%d %H:%M:%S')}] 趋势开始:Aroon Up上穿Down,买入")
# 全仓买入 (这里演示用 order_target_value,也可以用 order_value)
# 假设总资金的一定比例,这里简单演示买入固定金额或全仓
# 注意:实盘请做好资金管理
order_target_percent(ContextInfo.stock_code, 0.95, "fix", df['close'].iloc[-1], ContextInfo, ContextInfo.accid)
# 2. 卖出信号:Aroon Down 上穿 Aroon Up (死叉)
# 逻辑:当前 Down > Up 且 上一刻 Down <= Up
elif curr_down > curr_up and prev_down <= prev_up:
if current_holding > 0:
print(f"[{timetag_to_datetime(realtime, '%Y-%m-%d %H:%M:%S')}] 趋势结束:Aroon Down上穿Up,卖出")
# 清仓
order_target_percent(ContextInfo.stock_code, 0, "fix", df['close'].iloc[-1], ContextInfo, ContextInfo.accid)
# --- (可选) 绘图 ---
# 在回测界面的副图画出指标,方便观察
ContextInfo.paint('Aroon_Up', curr_up, -1, 0, 'red')
ContextInfo.paint('Aroon_Down', curr_down, -1, 0, 'green')
代码要点解析
-
数据获取 (
get_market_data_ex):- 我们使用了
get_market_data_ex接口,这是 QMT 推荐的高效数据接口。 - 获取了
high(最高价) 和low(最低价),这是计算 Aroon 指标必须的参数。 count设置为ContextInfo.period + 50,确保有足够的历史数据来“预热”指标计算。
- 我们使用了
-
指标计算 (
talib.AROON):- QMT 内置了
talib库,我们直接调用talib.AROON函数。 - 它返回两个数组:
aroon_down和aroon_up。 - 取值范围在 0 到 100 之间。
- QMT 内置了
-
信号判断:
- 金叉 (买入):
curr_up > curr_down且prev_up <= prev_down。这意味着 Up 线刚刚从下方穿过了 Down 线,通常被视为上升趋势的开始。 - 死叉 (卖出):
curr_down > curr_up且prev_down <= prev_up。这意味着 Down 线占据主导,上升趋势结束或下跌趋势开始。
- 金叉 (买入):
-
交易执行 (
order_target_percent):- 使用
order_target_percent可以方便地进行仓位管理。 0.95代表调整仓位至总资产的 95%(留 5% 现金防止手续费不足)。0代表清仓。
- 使用
如何在 QMT 中使用
- 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
- 新建一个 Python 策略。
- 将上述代码复制粘贴进去。
- 修改账号:将
ContextInfo.accid = '6666666666'中的数字改为您实际的资金账号。 - 回测:点击“回测”,选择标的(如 000001.SZ)和周期(如日线),即可看到策略表现。
- 实盘:如果用于实盘,请确保在【交易】界面已登录账号,并将策略运行模式切换为“实盘”。
常见问题 Q&A
Q: 为什么 Aroon 指标有时候会产生很多假信号?
A: 在震荡市中,Up 和 Down 线可能会频繁交叉。为了过滤假信号,可以增加一个阈值条件,例如:只有当 Aroon Up > 70 且 Aroon Down < 30 时才视为强趋势买入。
Q: 如何修改指标的灵敏度?
A: 修改 init 函数中的 ContextInfo.period。周期越短(如 14),指标越灵敏,但假信号越多;周期越长(如 50),趋势确认越稳健,但信号会有滞后。
Q: get_market_data_ex 获取不到数据怎么办?
A: 请确保在 QMT 客户端的【数据管理】中已经下载了对应标的和周期的历史数据。如果没有下载,回测时可能会取不到数据。