🚀 AI 一键生成 qmt 策略代码

如何在 QMT 平台实现佳庆摆动指标 (CHO) 交易策略?

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

问题描述

请帮我写一个佳庆摆动指标 CHO 的量化策略

解决方案

这是一个基于 佳庆摆动指标 (Chaikin Oscillator, CHO) 的 QMT 量化策略。

策略原理

佳庆摆动指标 (CHO) 是通过计算累积/派发线 (Accumulation/Distribution Line, ADL) 的移动平均线差值来衡量市场的动量。

  • 计算公式:$CHO = EMA(ADL, ShortPeriod) - EMA(ADL, LongPeriod)$
  • 默认参数:短期周期通常为 3,长期周期通常为 10。
  • 交易逻辑
    • 买入信号:当 CHO 从下向上穿越 0 轴时(金叉),视为资金流入,动量转强,执行买入。
    • 卖出信号:当 CHO 从上向下穿越 0 轴时(死叉),视为资金流出,动量转弱,执行卖出(清仓)。

策略代码

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

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 设置要交易的股票池,这里以平安银行为例
    ContextInfo.target_list = ['000001.SZ']
    ContextInfo.set_universe(ContextInfo.target_list)
    
    # 设置资金账号 (请替换为您自己的资金账号)
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # CHO 指标参数
    ContextInfo.fast_period = 3   # 短期 EMA 周期
    ContextInfo.slow_period = 10  # 长期 EMA 周期
    
    # 设置回测参数 (仅在回测模式下生效,实盘需在界面设置)
    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_list = ContextInfo.get_universe()
    
    # 获取当前周期 (例如 '1d')
    period = ContextInfo.period
    
    # 批量获取历史行情数据
    # CHO 需要 High, Low, Close, Volume 四个字段
    # count 设置为 100 以确保有足够的数据计算 EMA
    data_map = ContextInfo.get_market_data_ex(
        ['high', 'low', 'close', 'volume'], 
        stock_list, 
        period=period, 
        count=100, 
        dividend_type='front' # 使用前复权
    )
    
    for stock in stock_list:
        # 检查该股票是否有数据
        if stock not in data_map:
            continue
            
        df = data_map[stock]
        
        # 数据长度不足以计算指标时跳过
        if len(df) < ContextInfo.slow_period + 5:
            continue
            
        # 提取数据并转换为 numpy 数组 (TA-Lib 需要 numpy 格式)
        high = df['high'].values
        low = df['low'].values
        close = df['close'].values
        volume = df['volume'].values
        
        # 处理 NaN 值 (简单的清洗,防止计算报错)
        if np.isnan(close).any():
            continue

        # --- 计算 CHO 指标 ---
        # talib.ADOSC(high, low, close, volume, fastperiod, slowperiod)
        try:
            cho = talib.ADOSC(
                high, 
                low, 
                close, 
                volume, 
                fastperiod=ContextInfo.fast_period, 
                slowperiod=ContextInfo.slow_period
            )
        except Exception as e:
            print(f"计算指标出错 {stock}: {e}")
            continue
            
        # 获取最近两个周期的 CHO 值
        curr_cho = cho[-1] # 当前 K 线 CHO
        prev_cho = cho[-2] # 上一根 K 线 CHO
        
        # 过滤无效的指标值
        if np.isnan(curr_cho) or np.isnan(prev_cho):
            continue

        # --- 交易逻辑 ---
        
        # 获取当前持仓
        positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
        current_pos = 0
        for pos in positions:
            if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock:
                current_pos = pos.m_nVolume
                break
        
        # 1. 买入信号:CHO 上穿 0 轴 (金叉)
        if prev_cho < 0 and curr_cho > 0:
            # 如果当前没有持仓,则全仓买入 (目标仓位 100%)
            # 注意:这里使用 order_target_percent 需要在回测或实盘中正确配置资金
            print(f"{stock} 触发买入信号: CHO上穿0轴 ({prev_cho:.2f} -> {curr_cho:.2f})")
            order_target_percent(stock, 1.0, ContextInfo, ContextInfo.account_id)
            
        # 2. 卖出信号:CHO 下穿 0 轴 (死叉)
        elif prev_cho > 0 and curr_cho < 0:
            # 如果有持仓,则清仓 (目标仓位 0%)
            if current_pos > 0:
                print(f"{stock} 触发卖出信号: CHO下穿0轴 ({prev_cho:.2f} -> {curr_cho:.2f})")
                order_target_percent(stock, 0.0, ContextInfo, ContextInfo.account_id)

代码详解

  1. 初始化 (init):

    • 设定了交易标的(示例为平安银行 000001.SZ)。
    • 设定了 CHO 指标的快慢周期参数(3 和 10)。
    • 绑定了资金账号。
  2. 数据获取 (handlebar):

    • 使用 ContextInfo.get_market_data_ex 接口获取 high, low, close, volume 数据。这是计算 CHO 必不可少的四个要素。
    • 使用了 dividend_type='front' 进行前复权,保证价格连续性,避免因分红派息导致的指标失真。
  3. 指标计算:

    • 利用 QMT 内置的 talib 库中的 ADOSC 函数直接计算佳庆摆动指标。
    • talib.ADOSC 实际上就是 Chaikin Oscillator 的标准实现函数。
  4. 交易信号:

    • 金叉prev_cho < 0curr_cho > 0
    • 死叉prev_cho > 0curr_cho < 0
  5. 下单执行:

    • 使用 order_target_percent 函数。
    • 买入时设定目标仓位为 1.0(即满仓该股票,如果是多只股票需调整比例)。
    • 卖出时设定目标仓位为 0.0(即清仓)。

注意事项

  • 账号设置:请务必将代码中的 'YOUR_ACCOUNT_ID' 替换为您实际的 QMT 资金账号。
  • 数据长度:CHO 依赖 EMA 计算,需要一定的历史数据预热。代码中 count=100 能够满足大部分需求,但在刚上市的新股上可能会因为数据不足计算出 NaN
  • 实盘与回测:该策略既可用于回测,也可用于实盘。在实盘模式下,建议结合 ContextInfo.is_last_bar() 判断,防止在 K 线未走完时信号闪烁。

Q&A

Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 推荐的新版数据接口,它返回的数据结构更清晰(字典包含 DataFrame),且在处理多只股票和多字段时性能更好,更易于进行向量化计算。

Q: CHO 指标和 MACD 有什么区别?
A: MACD 是基于价格的移动平均线差值,而 CHO 是基于累积/派发线 (ADL) 的移动平均线差值。CHO 结合了价格和成交量,更能反映资金流动的动量。

Q: 如何在多只股票上运行此策略?
A: 代码已经支持多只股票。只需在 init 函数中修改 ContextInfo.target_list,例如 ['000001.SZ', '600000.SH'],并在下单逻辑中将 order_target_percent 的比例调整为 1.0 / len(stock_list) 即可实现等权买入。