🚀 AI 一键生成 qmt 策略代码

如何用 Python 和 TA-Lib 在 QMT 中实现锤头线、启明/黄昏星等 K 线形态识别策略?

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

问题描述

请帮我写一个能识别 K 线形态(比如锤头线或启明/黄昏星)并进行交易的策略

解决方案

这是一个基于 QMT 平台编写的 K 线形态识别策略。该策略利用 QMT 内置的 TA-Lib 库(技术分析库)来自动识别 锤头线 (Hammer)启明之星 (Morning Star)黄昏之星 (Evening Star),并根据识别结果进行买卖操作。

策略逻辑说明

  1. 数据获取:使用 ContextInfo.get_market_data_ex 获取股票的历史 OHLC(开高低收)数据。
  2. 形态识别:调用 talib 库的函数:
    • CDLHAMMER:识别锤头线(看涨信号)。
    • CDLMORNINGSTAR:识别启明之星(底部反转,看涨信号)。
    • CDLEVENINGSTAR:识别黄昏之星(顶部反转,看跌信号)。
  3. 交易执行
    • 买入条件:当识别出“锤头线”或“启明之星”形态时,且当前无持仓,执行买入。
    • 卖出条件:当识别出“黄昏之星”形态时,且当前有持仓,执行清仓。

策略代码

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

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 设置资金账号 (请替换为您自己的资金账号)
    ContextInfo.accID = '6000000000' 
    ContextInfo.set_account(ContextInfo.accID)
    
    # 设置股票池 (示例:平安银行,贵州茅台)
    ContextInfo.stock_list = ['000001.SZ', '600519.SH']
    ContextInfo.set_universe(ContextInfo.stock_list)
    
    # 设置策略参数
    ContextInfo.lookback = 20  # 获取历史K线数量,形态识别通常需要前几根K线
    ContextInfo.position_ratio = 0.2  # 每只股票买入占总资金的比例
    
    print("策略初始化完成,监控形态:锤头线、启明之星、黄昏之星")

def handlebar(ContextInfo):
    """
    K线周期运行函数
    """
    # 获取当前正在处理的K线索引
    index = ContextInfo.barpos
    
    # 获取当前时间戳
    realtime = ContextInfo.get_bar_timetag(index)
    
    # 遍历股票池
    for stock in ContextInfo.stock_list:
        # 1. 获取历史行情数据
        # 注意:形态识别至少需要一定数量的历史数据,这里取 lookback 数量
        # subscribe=True 确保实盘时数据订阅更新
        data_map = ContextInfo.get_market_data_ex(
            ['open', 'high', 'low', 'close'], 
            [stock], 
            period=ContextInfo.period, 
            count=ContextInfo.lookback,
            subscribe=True
        )
        
        if stock not in data_map:
            continue
            
        df = data_map[stock]
        
        # 数据长度校验,防止数据不足导致报错
        if len(df) < 10:
            continue
            
        # 2. 准备 TA-Lib 需要的数据格式 (numpy array, float类型)
        # 注意:TA-Lib计算是基于序列的,我们需要传入完整的序列
        open_prices = df['open'].values.astype(float)
        high_prices = df['high'].values.astype(float)
        low_prices = df['low'].values.astype(float)
        close_prices = df['close'].values.astype(float)
        
        # 3. 调用 TA-Lib 进行形态识别
        # 结果说明:100 表示看涨形态,-100 表示看跌形态,0 表示无形态
        
        # 识别锤头线 (Hammer) - 看涨
        hammer = talib.CDLHAMMER(open_prices, high_prices, low_prices, close_prices)
        
        # 识别启明之星 (Morning Star) - 看涨
        morning_star = talib.CDLMORNINGSTAR(open_prices, high_prices, low_prices, close_prices)
        
        # 识别黄昏之星 (Evening Star) - 看跌
        evening_star = talib.CDLEVENINGSTAR(open_prices, high_prices, low_prices, close_prices)
        
        # 获取最新一根K线的形态结果 (即当前 bar 的结果)
        # 注意:在回测中,df的最后一行是当前bar;在实盘中,如果bar未走完,信号可能会闪烁
        # 建议实盘使用上一根K线确认信号,或者在当前K线即将收盘时确认
        current_hammer = hammer[-1]
        current_morning = morning_star[-1]
        current_evening = evening_star[-1]
        
        # 4. 获取当前持仓信息
        positions = get_trade_detail_data(ContextInfo.accID, 'stock', 'position')
        holding_vol = 0
        for pos in positions:
            if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock:
                holding_vol = pos.m_nVolume
                break
        
        # 5. 交易逻辑判断
        
        # --- 买入逻辑 ---
        # 如果出现 锤头线(100) 或者 启明之星(100)
        if (current_hammer == 100 or current_morning == 100):
            if holding_vol == 0:
                print(f"[{stock}] 发现看涨形态 (锤头线/启明之星) - 时间: {timetag_to_datetime(realtime, '%Y-%m-%d %H:%M:%S')}")
                # 目标市值下单:调整仓位到总资产的 20%
                order_target_percent(stock, ContextInfo.position_ratio, ContextInfo, ContextInfo.accID)
                
                # 在图表上标记
                ContextInfo.draw_text(True, low_prices[-1], '买入')
        
        # --- 卖出逻辑 ---
        # 如果出现 黄昏之星(-100)
        elif (current_evening == -100):
            if holding_vol > 0:
                print(f"[{stock}] 发现看跌形态 (黄昏之星) - 时间: {timetag_to_datetime(realtime, '%Y-%m-%d %H:%M:%S')}")
                # 清仓
                order_target_percent(stock, 0, ContextInfo, ContextInfo.accID)
                
                # 在图表上标记
                ContextInfo.draw_text(True, high_prices[-1], '卖出')

代码关键点解析

  1. import talib: QMT 自带了 talib 库,这是量化领域最标准的形态识别库,计算效率极高。
  2. 数据转换: talib 的函数通常要求输入 numpy.ndarray 类型的浮点数数组。代码中使用了 .values.astype(float) 将 pandas Series 转换为符合要求的格式。
  3. 信号判断:
    • talib 的形态函数返回值通常为整数序列。
    • 100: 表示识别出标准的看涨形态。
    • -100: 表示识别出标准的看跌形态。
    • 0: 表示未识别出形态。
  4. order_target_percent: 使用目标比例下单函数。这比指定股数下单更方便,它会自动计算需要买入多少股才能达到设定的仓位比例(例如 20%),或者卖出多少股才能清仓(设为 0)。

如何在 QMT 中运行

  1. 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
  2. 新建一个 Python 策略。
  3. 将上述代码完整复制粘贴进去。
  4. 修改 ContextInfo.accID 为你实际的资金账号。
  5. 点击【编译】检查无误。
  6. 在左侧选择回测区间和周期(建议选择 日线,因为形态学在日线级别准确率相对较高),点击【运行】或【回测】。

常见问题 Q&A

Q: 为什么实盘时信号会闪烁(一会有一会没有)?
A: 在实盘中,handlebar 会在每个 Tick(分笔数据)到来时运行。如果当前 K 线还没有收盘(例如日线还在交易中),形态可能会随着最新价的变化而成立或消失。

  • 解决方法:可以在代码中判断 ContextInfo.is_last_bar() 并且只在 K 线即将结束的时间点(如 14:55)下单,或者逻辑改为判断 hammer[-2](即以前一根已收盘的 K 线作为信号)。

Q: 可以识别其他形态吗?
A: 可以。talib 支持几十种形态,例如:

  • 红三兵: talib.CDL3WHITESOLDIERS
  • 三只乌鸦: talib.CDL3BLACKCROWS
  • 十字星: talib.CDLDOJI
    只需将代码中的函数名替换即可。

Q: 为什么回测没有交易?
A:

  1. 请检查回测时间段内是否真的出现了该形态(形态出现频率并不高)。
  2. 请检查 ContextInfo.accID 是否设置正确(回测模式下通常不需要真实账号,但代码逻辑中获取持仓依赖账号)。
  3. 请确保数据已经下载补充完整(在数据管理中下载日线数据)。