问题描述
请为我编写一个布林带策略,当价格跌破布林带下轨时买入,突破上轨时卖出。
解决方案
这是一个基于QMT平台的布林带(Bollinger Bands)均值回归策略。
策略逻辑
- 指标计算:
- 中轨 (MB):过去
N根K线的收盘价移动平均线(SMA)。 - 上轨 (UP):中轨 +
K倍的标准差。 - 下轨 (DN):中轨 -
K倍的标准差。
- 中轨 (MB):过去
- 交易信号:
- 买入:当当前收盘价 跌破 布林带下轨时,认为价格超卖,执行买入(满仓)。
- 卖出:当当前收盘价 突破 布林带上轨时,认为价格超买,执行卖出(空仓)。
策略代码
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
初始化函数,设定策略参数和账号
"""
# --- 策略参数设置 ---
ContextInfo.M = 20 # 布林带周期 (默认20)
ContextInfo.K = 2.0 # 标准差倍数 (默认2)
# --- 账号设置 ---
# 请务必将下方的 'YOUR_ACCOUNT_ID' 替换为您真实的资金账号
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
ContextInfo.account_type = 'STOCK' # 账号类型:'STOCK'股票, 'FUTURE'期货
# 绑定账号
ContextInfo.set_account(ContextInfo.account_id)
print("布林带策略初始化完成")
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 获取当前主图的股票代码和市场
# 格式如 '600000.SH'
stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
# 获取当前周期 (如 '1d', '15m' 等)
period = ContextInfo.period
# 获取历史行情数据
# 我们需要计算M周期的均线,所以至少取 M + 5 根K线以确保数据充足
count = ContextInfo.M + 5
# 获取收盘价数据
# get_market_data 返回的是 pandas DataFrame 或 Series
data = ContextInfo.get_market_data(
['close'],
stock_code=[stock_code],
count=count,
period=period,
dividend_type='front' # 使用前复权数据
)
# 检查数据是否获取成功
if data is None or len(data) < ContextInfo.M:
return
# 提取收盘价序列 (Series)
# 注意:get_market_data 返回的 DataFrame 索引是时间,列是字段
# 如果是单只股票,直接取该股票的数据
close_prices = data
if isinstance(data, pd.DataFrame):
# 如果返回的是DataFrame,通常结构是 index=time, columns=stock_list (当只取close时)
# 或者 index=time, columns=['close'] (取决于调用方式,这里做个兼容处理)
if stock_code in data.columns:
close_prices = data[stock_code]
elif 'close' in data.columns:
close_prices = data['close']
# --- 计算布林带 ---
# 1. 计算中轨 (移动平均线)
rolling_mean = close_prices.rolling(window=ContextInfo.M).mean()
# 2. 计算标准差
rolling_std = close_prices.rolling(window=ContextInfo.M).std()
# 3. 计算上轨和下轨
upper_band = rolling_mean + ContextInfo.K * rolling_std
lower_band = rolling_mean - ContextInfo.K * rolling_std
# 获取最新一根K线的数据值
curr_close = close_prices.iloc[-1]
curr_upper = upper_band.iloc[-1]
curr_lower = lower_band.iloc[-1]
# 打印调试信息 (可选)
# print(f"代码:{stock_code} 收盘:{curr_close:.2f} 上轨:{curr_upper:.2f} 下轨:{curr_lower:.2f}")
# --- 交易逻辑 ---
# 信号1:价格跌破下轨 -> 买入
if curr_close < curr_lower:
# 使用 order_target_percent 调整仓位到 100% (全仓买入)
# 这种方式会自动判断当前是否持有,如果未持有则买入,已持有则不动
order_target_percent(stock_code, 1.0, "FIX", curr_close, ContextInfo, ContextInfo.account_id)
# 如果是回测模式,打印日志
if ContextInfo.do_back_test:
print(f"【买入信号】{stock_code} 价格跌破下轨 ({curr_close} < {curr_lower}),执行买入")
# 信号2:价格突破上轨 -> 卖出
elif curr_close > curr_upper:
# 使用 order_target_percent 调整仓位到 0% (清仓卖出)
order_target_percent(stock_code, 0.0, "FIX", curr_close, ContextInfo, ContextInfo.account_id)
if ContextInfo.do_back_test:
print(f"【卖出信号】{stock_code} 价格突破上轨 ({curr_close} > {curr_upper}),执行卖出")
使用说明与注意事项
- 账号配置:
- 代码中的
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'必须修改为您实际的资金账号(如果是回测,请在策略编辑器的“回测参数”中设置初始资金,代码中可以保留默认或设置虚拟账号)。
- 代码中的
- 运行模式:
- 回测:请确保您已下载了对应品种和周期的历史数据(通过“数据管理”下载)。
- 实盘/模拟:
handlebar函数会在每一根K线结束或每一个Tick到来时触发。代码中使用了order_target_percent,这个函数非常适合这种策略,因为它会自动计算需要买卖的数量来达到目标仓位(例如从0%变到100%会自动买入,从100%变到100%则不操作),避免了重复下单。
- 下单价格:
- 示例中使用了
"FIX"(指定价) 和curr_close(当前价) 进行下单。在实盘中,为了保证成交,您可能希望将其改为"LATEST"(最新价) 或"MARKET"(市价)。
- 示例中使用了
- 数据依赖:
- 策略依赖
pandas计算均线和标准差,QMT内置环境已包含此库。
- 策略依赖
- 复权方式:
- 代码中设置了
dividend_type='front'(前复权),这对于技术指标策略非常重要,可以避免因分红配股导致的价格跳空触发错误信号。
- 代码中设置了