🚀 AI 一键生成 qmt 策略代码

QMT 策略编程:基于 BIAS 乖离率的均值回归模型

qmt | 发布时间: 2025/12/22
以下内容由 EasyQuant 生成。

问题描述

请帮我写一个 BIAS 乖离率策略

解决方案

这是一个基于 QMT 平台的 BIAS(乖离率) 量化交易策略。

策略逻辑说明

BIAS (乖离率) 是测量股价偏离移动平均线程度的指标。

  • 计算公式:$BIAS = (收盘价 - N日移动平均价) / N日移动平均价 \times 100%$
  • 交易逻辑
    • 买入信号(超卖):当 BIAS 低于设定的下限(例如 -6%),说明股价短期跌幅过大,偏离均线过远,可能出现反弹,执行买入。
    • 卖出信号(超买):当 BIAS 高于设定的上限(例如 +6%),说明股价短期涨幅过大,偏离均线过远,可能出现回调,执行卖出。

策略代码实现

以下是完整的 Python 策略代码,您可以直接复制到 QMT 的策略编辑器中。

# -*- coding: gbk -*-
import pandas as pd
import numpy as np

def init(ContextInfo):
    """
    初始化函数,设定策略参数和账户
    """
    # 1. 策略参数设置
    ContextInfo.N = 6               # 计算均线的周期 (如:6日均线)
    ContextInfo.buy_threshold = -6  # 买入阈值:BIAS < -6%
    ContextInfo.sell_threshold = 6  # 卖出阈值:BIAS > 6%
    
    # 2. 设定交易标的 (示例:浦发银行)
    # 实盘或回测时,也可以通过界面右侧的“股票池”设置,这里代码强制设定方便演示
    ContextInfo.stock_list = ['600000.SH'] 
    ContextInfo.set_universe(ContextInfo.stock_list)
    
    # 3. 设定资金账号 (请修改为您自己的资金账号)
    # 注意:回测模式下,这里可以填任意字符串;实盘模式下必须填写真实账号
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 4. 设定回测细节 (仅回测有效)
    ContextInfo.set_slippage(1, 0.0) # 设置滑点
    ContextInfo.set_commission(0, [0.0003, 0.0003, 0.0003, 0.0003, 0, 5]) # 设置手续费

def handlebar(ContextInfo):
    """
    K线逐根运行函数
    """
    # 获取当前正在处理的 K 线索引
    index = ContextInfo.barpos
    
    # 获取当前图表的周期 (例如 '1d')
    period = ContextInfo.period
    
    # 遍历股票池中的每一只股票
    for stock in ContextInfo.stock_list:
        
        # 1. 获取历史行情数据
        # 我们需要 N 个数据来计算均线,但为了稳健,多取一点数据
        # count = ContextInfo.N + 2
        # 使用 get_market_data_ex 获取数据,这是更推荐的新接口
        # 注意:dividend_type='front' 使用前复权数据,避免分红造成指标失真
        data_dict = ContextInfo.get_market_data_ex(
            ['close'], 
            [stock], 
            period=period, 
            count=ContextInfo.N + 5, 
            dividend_type='front', 
            subscribe=True
        )
        
        if stock not in data_dict:
            continue
            
        df = data_dict[stock]
        
        # 如果数据长度不足以计算 N 日均线,则跳过
        if len(df) < ContextInfo.N:
            continue
            
        # 2. 计算指标
        # 获取最近的收盘价序列
        close_prices = df['close']
        
        # 获取当前最新收盘价 (Series的最后一个值)
        current_close = close_prices.iloc[-1]
        
        # 计算 N 日移动平均线 (取最后 N 个数据求平均)
        # 注意:这里计算的是包含当前K线的 MA
        ma_n = close_prices.iloc[-ContextInfo.N:].mean()
        
        # 计算 BIAS 乖离率
        # 公式:(收盘价 - 均线) / 均线 * 100
        bias = (current_close - ma_n) / ma_n * 100
        
        # 打印日志方便调试 (仅在回测或实盘日志窗口显示)
        # print(f"代码: {stock}, 时间: {df.index[-1]}, 收盘: {current_close:.2f}, MA{ContextInfo.N}: {ma_n:.2f}, BIAS: {bias:.2f}%")
        
        # 3. 获取当前持仓信息
        # 使用 get_position 获取该股票的持仓数量
        # 注意:回测模式下 QMT 会自动维护持仓;实盘需确保账号同步
        position = ContextInfo.get_position(stock, ContextInfo.account_id)
        current_holdings = position.m_nVolume if position else 0
        
        # 4. 交易逻辑判断
        
        # --- 信号 1: 买入 (BIAS 低于下限) ---
        if bias < ContextInfo.buy_threshold:
            # 如果当前没有持仓,则全仓买入 (目标仓位调整为 100%)
            # 这里使用 order_target_percent 方便管理仓位
            if current_holdings == 0:
                print(f"买入信号触发: {stock}, BIAS: {bias:.2f}% < {ContextInfo.buy_threshold}%")
                order_target_percent(stock, 1.0, ContextInfo, ContextInfo.account_id)
        
        # --- 信号 2: 卖出 (BIAS 高于上限) ---
        elif bias > ContextInfo.sell_threshold:
            # 如果当前有持仓,则清仓卖出 (目标仓位调整为 0%)
            if current_holdings > 0:
                print(f"卖出信号触发: {stock}, BIAS: {bias:.2f}% > {ContextInfo.sell_threshold}%")
                order_target_percent(stock, 0.0, ContextInfo, ContextInfo.account_id)

# 辅助函数:获取持仓 (兼容回测和实盘)
def get_position(stock_code, account_id):
    # QMT 的 ContextInfo.get_position 有时返回对象,有时需通过 get_trade_detail_data 获取
    # 这里直接使用 ContextInfo.get_position 即可,它是 QMT 封装好的便捷方法
    pass 

代码关键点解析

  1. # -*- coding: gbk -*-:

    • 这是 QMT Python 策略文件的必须头,因为 QMT 底层使用 GBK 编码,不加这行中文注释会报错。
  2. 数据获取 (get_market_data_ex):

    • 使用了 dividend_type='front'(前复权)。计算技术指标(如均线、BIAS)时,必须使用复权数据,否则股票分红除权会导致价格跳空,产生错误的 BIAS 信号。
    • count 设置为 N + 5 是为了确保有足够的数据计算均线,防止边界数据缺失。
  3. 指标计算:

    • 利用 pandasilocmean() 函数快速计算移动平均线。
    • 严格按照 BIAS 公式计算百分比。
  4. 交易执行 (order_target_percent):

    • order_target_percent(stock, 1.0, ...): 表示将该股票的仓位调整至总资产的 100%(全仓买入)。
    • order_target_percent(stock, 0.0, ...): 表示将该股票的仓位调整至 0%(清仓卖出)。
    • 使用目标仓位函数比直接使用 passorder 更简单,因为它会自动计算需要买卖的股数,并处理买卖方向。

如何在 QMT 中运行

  1. 打开 QMT 客户端,进入【模型研究】或【策略交易】界面。
  2. 新建一个 Python 策略。
  3. 将上述代码完整复制进去。
  4. 修改账号:将 ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 中的 'YOUR_ACCOUNT_ID' 替换为您真实的资金账号(如果是回测,保持默认或随意填写即可)。
  5. 设置标的:代码中默认是 600000.SH,您可以在 init 函数中修改 ContextInfo.stock_list,或者在界面右侧的属性栏中选择运行的股票。
  6. 点击【编译】,确保无误后点击【回测】查看历史表现,或在实盘模式下点击【运行】。

常见问题 (Q&A)

Q: 为什么我的 BIAS 计算结果和看盘软件不一样?
A: 可能有两个原因:

  1. 复权方式不同:代码中使用了前复权 (front),请检查看盘软件是否也是前复权。
  2. 均线算法:代码中使用的是简单移动平均 (SMA),有些软件可能使用指数移动平均 (EMA)。

Q: 如何修改为多只股票同时运行?
A: 代码中的 ContextInfo.stock_list 是一个列表。您可以填入多个代码,例如 ['600000.SH', '000001.SZ']handlebar 函数中的 for stock in ContextInfo.stock_list: 循环会自动处理列表中的每一只股票。注意资金分配,如果多只股票同时触发买入,order_target_percent(stock, 1.0) 会尝试全仓买入每一只,导致资金不足,建议改为 1.0 / len(ContextInfo.stock_list)

Q: 实盘交易需要注意什么?
A: 实盘时,handlebar 会随行情 Tick 实时刷新。为了避免信号闪烁(即盘中价格波动导致信号一会有一会无),建议在逻辑中加入 if not ContextInfo.is_last_bar(): return 来只在历史K线上回测,或者在实盘逻辑中判断当前时间是否临近收盘(如 14:55 后)再执行信号。