3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于布林带(Bollinger Bands)通道突破的量化交易策略。
该代码使用了 ContextInfo.get_market_data_ex 获取数据,并使用 pandas 计算指标。下单函数使用了 order_target_percent,这在回测中非常方便(自动计算股数),实盘中同样适用(需确保账号设置正确)。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
初始化函数,策略启动时调用一次
"""
# --- 策略参数设置 ---
ContextInfo.M = 20 # 布林带周期
ContextInfo.K = 2.0 # 标准差倍数
ContextInfo.account_id = '6000000000' # 请替换为您真实的资金账号
ContextInfo.account_type = 'STOCK' # 账号类型:'STOCK'股票, 'FUTURE'期货
# 设置股票池(此处示例为平安银行,实际使用时可在界面设置或此处修改)
ContextInfo.set_universe(['000001.SZ'])
# 绑定账号(实盘/模拟盘必须)
ContextInfo.set_account(ContextInfo.account_id)
print("策略初始化完成:布林带突破策略 (N={}, K={})".format(ContextInfo.M, ContextInfo.K))
def handlebar(ContextInfo):
"""
K线周期回调函数,每根K线执行一次
"""
# 获取当前正在运行的K线索引
index = ContextInfo.barpos
# 获取当前图表的主图代码(如果是多股回测,建议遍历 ContextInfo.get_universe())
# 这里为了演示清晰,我们只针对当前主图代码或股票池中的第一个代码进行操作
stock_code = ContextInfo.get_universe()[0]
# --- 1. 获取历史行情数据 ---
# 我们需要计算MA20,所以至少需要前20根K线,为了安全起见取 M + 5 根
# subscribe=True 确保实盘时数据自动更新
data_map = ContextInfo.get_market_data_ex(
['close'],
[stock_code],
period=ContextInfo.period,
count=ContextInfo.M + 5,
dividend_type='front', # 前复权
subscribe=True
)
if stock_code not in data_map:
return
df = data_map[stock_code]
# 数据长度不足以计算指标时直接返回
if len(df) < ContextInfo.M:
return
# --- 2. 计算布林带指标 ---
# 计算移动平均线 (中轨)
df['ma'] = df['close'].rolling(window=ContextInfo.M).mean()
# 计算标准差
df['std'] = df['close'].rolling(window=ContextInfo.M).std()
# 计算上轨
df['upper'] = df['ma'] + ContextInfo.K * df['std']
# 计算下轨
df['lower'] = df['ma'] - ContextInfo.K * df['std']
# 获取最新一根K线的数据(iloc[-1])
# 注意:在回测模式下,handlebar是在K线结束时调用的,所以[-1]就是当前K线
# 在实盘模式下,如果希望K线走完再确认信号,应判断 ContextInfo.is_last_bar() 并结合时间逻辑
# 这里采用标准回测逻辑,取最新值
current_close = df['close'].iloc[-1]
current_upper = df['upper'].iloc[-1]
current_lower = df['lower'].iloc[-1]
# 打印调试信息 (可选)
# print(f"代码:{stock_code} 收盘:{current_close:.2f} 上轨:{current_upper:.2f} 下轨:{current_lower:.2f}")
# --- 3. 获取当前持仓 ---
# 使用 get_trade_detail_data 获取持仓对象列表
positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
current_volume = 0
for pos in positions:
if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock_code:
current_volume = pos.m_nVolume
break
# --- 4. 交易逻辑 ---
# 信号1:价格突破上轨 -> 买入
if current_close > current_upper:
# 如果当前没有持仓,则全仓买入
if current_volume == 0:
print(f"{stock_code} 触发买入信号: 价格 {current_close} > 上轨 {current_upper}")
# order_target_percent(代码, 目标仓位比例, ...)
# 1.0 代表调整至 100% 仓位
order_target_percent(stock_code, 1.0, ContextInfo, ContextInfo.account_id)
# 信号2:价格跌破下轨 -> 卖出
elif current_close < current_lower:
# 如果当前有持仓,则清仓
if current_volume > 0:
print(f"{stock_code} 触发卖出信号: 价格 {current_close} < 下轨 {current_lower}")
# 0.0 代表调整至 0% 仓位(即清仓)
order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.account_id)
账号设置:
ContextInfo.account_id = '6000000000' 必须修改为您实际的 QMT 资金账号。数据获取:
get_market_data_ex 接口,这是 QMT 推荐的高效数据接口。dividend_type='front' 设置为前复权,这对于技术指标策略非常重要,避免因分红除权导致的价格跳空触发错误信号。下单函数:
order_target_percent。这个函数非常智能,它会自动计算需要买入多少股才能达到目标仓位(例如 1.0 表示满仓)。order_target_percent 替换为 order_shares(stock_code, 100, ContextInfo, ContextInfo.account_id)。运行模式:
handlebar 会随行情 Tick 推送触发(如果设置为逐Tick运行)或 K线生成时触发。上述代码逻辑是基于 K 线收盘价的,建议在设置中将运行频率设为“K线生成”或在代码中增加 ContextInfo.is_new_bar() 判断以避免盘中闪烁信号导致频繁交易。Q: 如何修改布林带的参数?
A: 在代码的 init 函数中,修改 ContextInfo.M (周期) 和 ContextInfo.K (标准差倍数) 的值即可。
Q: 这个策略可以用于期货吗?
A: 可以,但需要做两处调整:
ContextInfo.account_type 改为 'FUTURE'。order_target_percent 的目标设为负数(如果API支持)或使用 passorder 函数发送开空指令(opType=3)。Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 新版推荐的接口,支持更灵活的参数(如复权、订阅开关),且返回的数据结构更规范(字典包含 DataFrame),处理多股数据时效率更高。