问题描述
解决方案
这是一个基于威廉指标(Williams %R)的 QMT 量化交易策略。
策略逻辑
- 指标定义:威廉指标(%R)用于判断市场的超买超卖状态,取值范围为 -100 到 0。
- 买入条件:当 %R 低于 -80 时,视为超卖状态,看涨,执行买入。
- 卖出条件:当 %R 高于 -20 时,视为超买状态,看跌,执行卖出(清仓)。
- 资金管理:买入时满仓(目标仓位 100%),卖出时空仓(目标仓位 0%)。
策略代码
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
import talib
def init(ContextInfo):
"""
初始化函数,策略启动时执行一次
"""
# 1. 设置策略参数
ContextInfo.N = 14 # 威廉指标周期,通常为14
ContextInfo.buy_threshold = -80 # 买入阈值
ContextInfo.sell_threshold = -20 # 卖出阈值
# 2. 设置股票池(示例使用浦发银行,实盘请在界面设置或此处修改)
ContextInfo.stock_code = '600000.SH'
ContextInfo.set_universe([ContextInfo.stock_code])
# 3. 设置资金账号 (请替换为您真实的资金账号)
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
ContextInfo.account_type = 'STOCK' # 账号类型:STOCK股票,FUTURE期货
ContextInfo.set_account(ContextInfo.account_id)
print("策略初始化完成,监控标的: {}, 周期: {}".format(ContextInfo.stock_code, ContextInfo.N))
def handlebar(ContextInfo):
"""
K线处理函数,每根K线执行一次
"""
# 获取当前正在处理的K线对应的股票代码
# 如果是回测模式,ContextInfo.stockcode 会自动随主图变化
# 如果是实盘,建议明确指定代码
stock_code = ContextInfo.stock_code
# 1. 获取历史行情数据
# 我们需要 High, Low, Close 价格来计算威廉指标
# 获取数量 count 需要比 N 大,以确保有足够数据计算指标
count = ContextInfo.N + 5
# 使用 get_market_data_ex 获取数据 (推荐使用 ex 接口)
# period='1d' 表示日线,也可以改成 '1m', '5m' 等
data_map = ContextInfo.get_market_data_ex(
['high', 'low', 'close'],
[stock_code],
period='1d',
count=count,
dividend_type='front' # 前复权
)
# 数据校验:如果没取到数据,直接返回
if stock_code not in data_map or data_map[stock_code].empty:
return
df = data_map[stock_code]
# 确保数据长度足够
if len(df) < ContextInfo.N:
return
# 2. 计算威廉指标 (Williams %R)
# 转换数据为 numpy 数组,talib 需要 float 类型
high_prices = df['high'].values.astype(float)
low_prices = df['low'].values.astype(float)
close_prices = df['close'].values.astype(float)
# 调用 talib 库计算 WILLR
# 公式: %R = (Highest High - Close) / (Highest High - Lowest Low) * -100
wr_values = talib.WILLR(high_prices, low_prices, close_prices, timeperiod=ContextInfo.N)
# 获取最新的 WR 值 (数组最后一个)
current_wr = wr_values[-1]
# 打印当前指标值 (方便调试)
# print(f"时间: {df.index[-1]}, WR: {current_wr:.2f}")
# 3. 交易逻辑判断
# 获取当前持仓
positions = ContextInfo.get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
current_holding = 0
for pos in positions:
if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock_code:
current_holding = pos.m_nVolume
break
# 信号判断
# 只有在 K 线走完或者是最新一根 K 线时才进行交易判断
if not np.isnan(current_wr):
# --- 买入信号:WR < -80 (超卖) ---
if current_wr < ContextInfo.buy_threshold:
# 如果当前没有持仓,则买入
# 这里使用 order_target_percent 调整仓位到 100% (即满仓买入)
# 注意:实盘中请根据风控需求调整比例,例如 0.1 (10%)
if current_holding == 0:
print(f"触发买入信号: WR={current_wr:.2f} < {ContextInfo.buy_threshold}")
order_target_percent(stock_code, 1.0, ContextInfo, ContextInfo.account_id)
# --- 卖出信号:WR > -20 (超买) ---
elif current_wr > ContextInfo.sell_threshold:
# 如果有持仓,则卖出
# 调整仓位到 0% (即清仓)
if current_holding > 0:
print(f"触发卖出信号: WR={current_wr:.2f} > {ContextInfo.sell_threshold}")
order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.account_id)
代码关键点说明
-
# -*- coding: gbk -*-:- QMT 的 Python 编辑器默认使用 GBK 编码,这行代码必须放在第一行,否则中文注释会导致报错。
-
数据获取 (
get_market_data_ex):- 我们使用了
get_market_data_ex接口,这是 QMT 推荐的新版数据接口。 dividend_type='front'设置为前复权,这对于技术指标计算非常重要,可以避免分红派息导致的价格跳空影响指标准确性。
- 我们使用了
-
指标计算 (
talib.WILLR):- QMT 内置了
talib库,直接调用WILLR函数计算威廉指标,效率最高且准确。 - 输入数据必须转换为
float类型的numpy数组。
- QMT 内置了
-
交易函数 (
order_target_percent):order_target_percent(stock_code, target_percent, ...)是一个非常方便的函数。- 设置为
1.0代表买入直到该股票占账户总资产的 100%(满仓)。 - 设置为
0.0代表卖出直到持仓为 0(清仓)。 - 注意:在实盘中,建议将
1.0改为较小的比例(如0.1或0.2)以控制风险。
-
账号设置:
- 代码中的
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'需要替换为您实际的资金账号,否则无法下单。
- 代码中的
Q&A
Q: 为什么威廉指标是负数?
A: 威廉指标的公式设计决定了其值域为 0 到 -100。0 代表收盘价处于过去 N 天的最高价(超买),-100 代表收盘价处于过去 N 天的最低价(超卖)。
Q: 如何在回测中查看效果?
A: 在 QMT 界面点击“模型回测”,设置好回测区间、基准和费率,然后点击“开始回测”。代码中的 print 语句会在日志中输出买卖信号。
Q: 这个策略可以直接实盘吗?
A: 代码逻辑是完整的,但实盘前请务必:
- 填写真实的资金账号。
- 确保 QMT 客户端已登录交易账号。
- 将
order_target_percent的比例调整为合理的仓位控制(不要直接满仓)。 - 在“模型交易”界面将策略运行模式设置为“实盘”。