🚀 AI 一键生成 qmt 策略代码

TD Sequential 计数转折策略 Python 源码解析

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

问题描述

请提供 TD 序列 (DeMark) 策略的 Python 代码实现

解决方案

这是一个基于 QMT (Quantitative Trading) 平台的 TD 序列 (DeMark Sequential) 策略代码实现。

策略说明

TD 序列(TD Sequential)是由 Tom DeMark 发明的一种反趋势指标,用于识别价格趋势的衰竭点。本代码实现了最核心的 TD Setup (TD 结构) 部分:

  1. TD 买入结构 (TD Buy Setup 9):连续 9 根 K 线的收盘价都低于 4 根 K 线前的收盘价。通常视为下跌趋势衰竭,是买入信号。
  2. TD 卖出结构 (TD Sell Setup 9):连续 9 根 K 线的收盘价都高于 4 根 K 线前的收盘价。通常视为上涨趋势衰竭,是卖出信号。

QMT Python 代码实现

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

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 1. 设置资金账号 (请替换为您自己的资金账号)
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 2. 设置股票池 (示例使用 沪深300ETF)
    ContextInfo.stock_code = '510300.SH'
    ContextInfo.set_universe([ContextInfo.stock_code])
    
    # 3. 策略参数设置
    ContextInfo.lookback = 4      # TD策略比较的位移周期 (通常为4)
    ContextInfo.setup_len = 9     # TD结构需要的连续周期数 (通常为9)
    
    # 4. 设置运行周期 (例如日线 '1d')
    ContextInfo.period = '1d'

def handlebar(ContextInfo):
    """
    K线逐根运行函数
    """
    # 获取当前正在处理的股票代码
    stock_code = ContextInfo.stock_code
    
    # 获取当前K线索引
    index = ContextInfo.barpos
    
    # 确保有足够的数据进行计算 (9 + 4 = 13, 预留20根以防万一)
    if index < 20:
        return

    # 1. 获取历史行情数据
    # 我们需要获取足够长度的数据来判断当前的TD结构
    # count = setup_len + lookback + buffer
    data_count = ContextInfo.setup_len + ContextInfo.lookback + 5
    
    market_data = ContextInfo.get_market_data_ex(
        ['close'], 
        [stock_code], 
        period=ContextInfo.period, 
        count=data_count, 
        dividend_type='front' # 前复权
    )
    
    if stock_code not in market_data:
        return
        
    df = market_data[stock_code]
    
    # 再次检查数据长度
    if len(df) < (ContextInfo.setup_len + ContextInfo.lookback):
        return
    
    # 获取收盘价序列 (转换为numpy数组提高效率)
    closes = df['close'].values
    
    # 2. 计算 TD 结构
    # 我们需要检查最近的9根K线是否满足条件
    
    is_buy_setup = True
    is_sell_setup = True
    
    # 循环检查最近9根K线 (从当前K线往前推)
    # 逻辑:检查 Close[i] < Close[i-4] 是否对最近9根K线都成立
    for i in range(ContextInfo.setup_len):
        # 当前考察的K线索引 (倒数第1根是 -1, 倒数第2根是 -2...)
        current_idx = -(i + 1) 
        # 用于比较的K线索引 (4根K线前)
        compare_idx = -(i + 1 + ContextInfo.lookback)
        
        current_close = closes[current_idx]
        compare_close = closes[compare_idx]
        
        # 检查买入结构条件: 收盘价 < 4根前的收盘价
        if current_close >= compare_close:
            is_buy_setup = False
        
        # 检查卖出结构条件: 收盘价 > 4根前的收盘价
        if current_close <= compare_close:
            is_sell_setup = False
            
    # 3. 交易逻辑
    
    # 获取当前持仓
    positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
    current_vol = 0
    for pos in positions:
        if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock_code:
            current_vol = pos.m_nVolume
            break

    # 信号触发:TD 买入结构完成 (TD 9) -> 看涨/反弹
    if is_buy_setup:
        print(f"[{stock_code}] 时间: {df.index[-1]} - 触发 TD买入结构(9) - 准备买入")
        # 示例:全仓买入 (目标仓位 100%)
        # 注意:实盘请根据风控调整仓位
        order_target_percent(stock_code, 1.0, ContextInfo, ContextInfo.account_id)

    # 信号触发:TD 卖出结构完成 (TD 9) -> 看跌/回调
    elif is_sell_setup:
        print(f"[{stock_code}] 时间: {df.index[-1]} - 触发 TD卖出结构(9) - 准备卖出")
        # 示例:清仓 (目标仓位 0%)
        order_target_percent(stock_code, 0.0, ContextInfo, ContextInfo.account_id)

    # 可选:在图表上画出信号 (仅在回测或界面运行时有效)
    if is_buy_setup:
        ContextInfo.draw_text(True, closes[-1], 'B9')
    elif is_sell_setup:
        ContextInfo.draw_text(True, closes[-1], 'S9')

代码详解

  1. 数据获取 (get_market_data_ex):

    • 我们获取了 close 收盘价。
    • count 设置为 setup_len (9) + lookback (4) + 5,确保有足够的数据回溯比较。
    • 使用 dividend_type='front' 进行前复权,保证价格连续性。
  2. TD 逻辑核心:

    • 代码使用了一个 for 循环来回溯最近的 9 根 K 线。
    • 买入结构: 检查 closes[current] < closes[current - 4] 是否连续 9 次成立。
    • 卖出结构: 检查 closes[current] > closes[current - 4] 是否连续 9 次成立。
  3. 交易执行:

    • 使用 order_target_percent 函数。
    • TD Buy Setup 9 完成时,视为底部信号,执行买入(目标仓位设为 1.0,即满仓)。
    • TD Sell Setup 9 完成时,视为顶部信号,执行卖出(目标仓位设为 0.0,即清仓)。
  4. 可视化:

    • 使用 ContextInfo.draw_text 在 K 线图上标记 "B9" (买入9) 和 "S9" (卖出9),方便回测时观察。

注意事项

  • 账号设置: 请务必将 init 函数中的 YOUR_ACCOUNT_ID 替换为您实际的 QMT 资金账号。
  • 周期选择: TD 策略在不同的周期(日线、周线、分钟线)效果不同,请根据需要调整 ContextInfo.period
  • 风险提示: TD 9 只是一个逆势信号,在强劲的单边趋势中(如连续暴跌或暴涨),TD 9 可能会失效(即出现钝化,价格继续沿着原方向运动)。实际交易中通常需要配合止损或其他过滤条件(如 TD 计数 13 或趋势线突破)使用。

Q&A

Q: 如何在回测中查看策略表现?
A: 在 QMT 界面中打开“模型研究” -> “策略编辑器”,将上述代码粘贴进去,设置好回测时间段和基准,点击“回测”即可。

Q: 代码中的 lookback 为什么是 4?
A: 这是 Tom DeMark 在设计 TD Sequential 指标时的标准定义。他认为比较当前价格与 4 根 K 线前的价格能有效过滤掉短期噪音,捕捉市场动能的衰竭。

Q: 这个策略可以用于期货吗?
A: 可以。只需将 ContextInfo.stock_code 修改为期货合约代码(如 IF00.IF),并将 order_target_percent 替换为期货专用的下单函数(如 buy_open, sell_close 等)即可。