🚀 AI 一键生成 qmt 策略代码

如何利用商品路径指标 (CCI) 构建一个反转交易策略?(附 Python 源码)

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

问题描述

请帮我写一个基于 CCI 指标的交易策略,当 CCI 指标下穿 -100 时买入,上穿 +100 时卖出。

解决方案

这是一个基于 QMT (QuantTrader) 平台的 Python 策略代码。

该策略实现了你描述的逻辑:

  1. 计算 CCI 指标(默认周期 N=14)。
  2. 买入信号:当 CCI 指标下穿 -100 时(前一根 K 线 > -100,当前 K 线 < -100),执行买入(示例为调整仓位到 100%)。
  3. 卖出信号:当 CCI 指标上穿 +100 时(前一根 K 线 < 100,当前 K 线 > 100),执行卖出(示例为清仓)。

QMT 策略代码

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

def init(ContextInfo):
    """
    初始化函数,设定策略参数和账户
    """
    # 1. 设置要操作的股票池 (这里以浦发银行为例,可自行修改)
    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. CCI 指标参数
    ContextInfo.cci_n = 14  # CCI 计算周期
    
    # 4. 策略运行参数
    ContextInfo.period = '1d'  # 运行周期,如 '1d', '15m'

def get_cci(high, low, close, n=14):
    """
    计算 CCI 指标的辅助函数
    """
    tp = (high + low + close) / 3
    ma = tp.rolling(window=n).mean()
    
    # 计算平均绝对偏差 (Mean Deviation)
    # pandas 没有直接的 rolling_mad,需要用 apply 实现
    def mean_deviation(x):
        return np.mean(np.abs(x - np.mean(x)))
    
    md = tp.rolling(window=n).apply(mean_deviation, raw=True)
    
    cci = (tp - ma) / (0.015 * md)
    return cci

def handlebar(ContextInfo):
    """
    K线处理函数,每根K线执行一次
    """
    # 获取当前正在处理的股票
    stock = ContextInfo.stock_code
    
    # 获取历史行情数据
    # 多取一些数据以确保计算指标时前面没有 NaN
    count = ContextInfo.cci_n + 20 
    
    # 使用 get_market_data_ex 获取数据 (推荐使用此接口)
    # 返回格式: {stock_code: DataFrame}
    data_map = ContextInfo.get_market_data_ex(
        ['high', 'low', 'close'], 
        [stock], 
        period=ContextInfo.period, 
        count=count, 
        dividend_type='front' # 前复权
    )
    
    if stock not in data_map:
        return
        
    df = data_map[stock]
    
    # 如果数据长度不足,无法计算指标,直接返回
    if len(df) < ContextInfo.cci_n:
        return

    # 计算 CCI
    df['cci'] = get_cci(df['high'], df['low'], df['close'], ContextInfo.cci_n)
    
    # 获取最近两根 K 线的 CCI 值
    # iloc[-1] 是当前最新 K 线,iloc[-2] 是上一根 K 线
    current_cci = df['cci'].iloc[-1]
    prev_cci = df['cci'].iloc[-2]
    
    # 打印当前 CCI 值方便调试 (在回测或实盘日志中查看)
    # print(f"Time: {df.index[-1]}, CCI: {current_cci:.2f}")
    
    # 避免数据计算初期的 NaN 值干扰
    if np.isnan(current_cci) or np.isnan(prev_cci):
        return

    # --- 交易逻辑 ---
    
    # 1. 买入条件:CCI 下穿 -100
    # 逻辑:上一根 > -100 且 当前 < -100
    if prev_cci > -100 and current_cci < -100:
        print(f"触发买入信号: {stock}, 前值={prev_cci:.2f}, 现值={current_cci:.2f}")
        # 示例:全仓买入 (调整目标仓位到 100%)
        # 注意:实盘中请根据风控需求修改下单函数,如 order_shares 或 passorder
        order_target_percent(stock, 1.0, ContextInfo, ContextInfo.account_id)

    # 2. 卖出条件:CCI 上穿 +100
    # 逻辑:上一根 < 100 且 当前 > 100
    elif prev_cci < 100 and current_cci > 100:
        print(f"触发卖出信号: {stock}, 前值={prev_cci:.2f}, 现值={current_cci:.2f}")
        # 示例:清仓卖出 (调整目标仓位到 0%)
        order_target_percent(stock, 0.0, ContextInfo, ContextInfo.account_id)

代码说明与注意事项

  1. 编码格式

    • 第一行 # -*- coding: gbk -*- 是必须的,因为 QMT 的 Python 环境默认使用 GBK 编码,防止中文注释乱码。
  2. CCI 计算逻辑

    • CCI 的标准公式中用到的是 平均绝对偏差 (Mean Deviation),而不是标准差 (Standard Deviation)。代码中使用了 rolling().apply() 来准确计算 MD。
    • 公式:$CCI = (TP - MA) / (0.015 \times MD)$。
  3. 交易信号逻辑

    • 下穿 -100:通常被视为超卖区域。在某些策略中,这被视为“跌破支撑,趋势转弱”的信号,但在震荡策略中,这可能被视为“抄底”信号。代码严格按照你的要求执行:prev > -100curr < -100 时买入。
    • 上穿 +100:通常被视为进入超买区域或强势区域。代码按照你的要求:prev < 100curr > 100 时卖出。
  4. 下单函数

    • 代码使用了 order_target_percent。这是一个高级封装函数,1.0 代表买入至总资产的 100%(全仓),0.0 代表卖出至 0%(空仓)。
    • 实盘注意:如果你想买入固定数量(如 100 股),请将下单行改为 order_shares(stock, 100, ContextInfo, ContextInfo.account_id)
  5. 如何运行

    • 将代码复制到 QMT 的【策略编辑器】中。
    • 修改 init 函数中的 ContextInfo.account_id 为你真实的资金账号。
    • 在界面右侧设置好回测时间或直接点击“运行”进行实盘/模拟盘监控。

Q&A

Q: 为什么使用 get_market_data_ex 而不是 get_market_data?
A: get_market_data_ex 是 QMT 较新的接口,返回的数据结构更统一(字典包含 DataFrame),处理多只股票或单只股票时代码逻辑一致性更好,且性能通常更优。

Q: 如何修改 CCI 的周期,比如改成 20?
A: 在 init 函数中,将 ContextInfo.cci_n = 14 修改为 ContextInfo.cci_n = 20 即可。

Q: 这个策略是做趋势还是做反转?
A: 根据你设定的条件(下穿 -100 买入),这通常属于**左侧交易(逆势/抄底)**逻辑,即在价格急剧下跌进入超卖区时买入,博取反弹;而在价格冲高突破 +100 时卖出。请注意这种策略在单边下跌趋势中可能会面临风险。