3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 BBI (Bull And Bear Index) 多空指数 的量化交易策略。
BBI 多空指数是一种将不同天数的移动平均线加权平均之后的综合指标,属于均线型指标。它结合了短期、中期和长期均线的优势。
计算公式:
$$ BBI = \frac{MA(3) + MA(6) + MA(12) + MA(24)}{4} $$
交易逻辑:
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
策略初始化函数
"""
# 1. 设置股票池 (这里以 600000.SH 浦发银行为例,可根据需要修改)
ContextInfo.stock_code = '600000.SH'
ContextInfo.set_universe([ContextInfo.stock_code])
# 2. 设置资金账号 (请替换为您真实的资金账号)
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
ContextInfo.set_account(ContextInfo.account_id)
# 3. 设置BBI计算参数 (3日, 6日, 12日, 24日均线)
ContextInfo.ma_periods = [3, 6, 12, 24]
# 4. 设置回测参数 (仅回测有效)
ContextInfo.set_slippage(1, 0.002) # 设置滑点
ContextInfo.set_commission(0, [0.0003, 0.0013, 0.0003, 0.0003, 0.0003, 5]) # 设置手续费
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 获取当前正在处理的股票代码
stock = ContextInfo.stock_code
# 获取当前K线的时间
index = ContextInfo.barpos
timetag = ContextInfo.get_bar_timetag(index)
date_str = timetag_to_datetime(timetag, '%Y-%m-%d %H:%M:%S')
# 1. 获取历史行情数据
# 我们需要足够的数据来计算 MA24,所以至少取 30 根K线
# dividend_type='front' 使用前复权数据,保证信号准确
data_map = ContextInfo.get_market_data_ex(
['close'],
[stock],
period='1d',
count=30,
dividend_type='front'
)
if stock not in data_map:
return
df = data_map[stock]
# 数据长度校验,不足以计算MA24则跳过
if len(df) < 24:
return
# 2. 计算 BBI 指标
# 计算各周期均线
ma3 = df['close'].rolling(window=3).mean()
ma6 = df['close'].rolling(window=6).mean()
ma12 = df['close'].rolling(window=12).mean()
ma24 = df['close'].rolling(window=24).mean()
# 计算 BBI
bbi = (ma3 + ma6 + ma12 + ma24) / 4
# 获取最新一根K线的收盘价和BBI值
current_close = df['close'].iloc[-1]
current_bbi = bbi.iloc[-1]
# 获取前一根K线的收盘价和BBI值 (用于判断交叉)
prev_close = df['close'].iloc[-2]
prev_bbi = bbi.iloc[-2]
# 3. 获取当前持仓
positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
current_holding = 0
for pos in positions:
if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock:
current_holding = pos.m_nVolume
break
# 4. 生成交易信号
# 信号逻辑:
# 金叉:前一根K线收盘价 <= 前BBI,且 当前收盘价 > 当前BBI
# 死叉:前一根K线收盘价 >= 前BBI,且 当前收盘价 < 当前BBI
is_golden_cross = (prev_close <= prev_bbi) and (current_close > current_bbi)
is_death_cross = (prev_close >= prev_bbi) and (current_close < current_bbi)
# 5. 执行交易
# 如果不是最后一根K线(回测中),或者在实盘的最新K线
if ContextInfo.is_last_bar():
print(f"时间: {date_str}, 收盘价: {current_close:.2f}, BBI: {current_bbi:.2f}")
if is_golden_cross:
if current_holding == 0:
print(f"{date_str} 触发买入信号 (价格上穿BBI)")
# 全仓买入 (目标仓位调整为 100%)
order_target_percent(stock, 1.0, ContextInfo, ContextInfo.account_id)
elif is_death_cross:
if current_holding > 0:
print(f"{date_str} 触发卖出信号 (价格下穿BBI)")
# 清仓卖出 (目标仓位调整为 0%)
order_target_percent(stock, 0.0, ContextInfo, ContextInfo.account_id)
初始化 (init):
600000.SH。[3, 6, 12, 24]。YOUR_ACCOUNT_ID 替换为您实际的 QMT 资金账号。数据获取 (handlebar):
get_market_data_ex 获取前复权的日线数据。指标计算:
pandas 的 rolling().mean() 快速计算各周期均线。信号判断:
交易执行:
order_target_percent 函数。1.0 (即 100% 仓位)。0.0 (即 0% 仓位,清仓)。Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 推荐的新版接口,返回的数据结构更清晰(字典包含 DataFrame),且支持更多参数配置(如复权方式、订阅开关等),处理效率更高。
Q: 如何在实盘中避免信号闪烁(Repainting)?
A: 在实盘中,当前 K 线尚未走完时,收盘价是变动的,可能导致 BBI 信号在盘中反复触发。
handlebar 中运行。如果是日线周期,盘中每个 tick 都会计算。如果希望只在收盘确认后交易,可以判断时间是否接近 14:55 或 15:00。ContextInfo.is_new_bar() 逻辑,仅在下一根 K 线开盘的瞬间,根据上一根已完成的 K 线信号进行下单(do_order 配合)。Q: 这个策略适合什么周期?
A: BBI 是一个趋势指标。