🚀 AI 一键生成 qmt 策略代码

QMT 平台如何利用 Heikin-Ashi (平均K线) 捕捉趋势?

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

问题描述

请编写一个基于 Heikin-Ashi K线的交易策略

解决方案

这是一个基于 Heikin-Ashi (平均K线) 的交易策略。

策略原理

Heikin-Ashi(平均K线)是一种对标准K线(OHLC)进行平滑处理的技术,旨在过滤市场噪音,更清晰地展示趋势。

计算公式:

  1. HA_Close (收盘价) = (开盘价 + 最高价 + 最低价 + 收盘价) / 4
  2. HA_Open (开盘价) = (上一根 HA_Open + 上一根 HA_Close) / 2
  3. HA_High (最高价) = Max(最高价, HA_Open, HA_Close)
  4. HA_Low (最低价) = Min(最低价, HA_Open, HA_Close)

交易逻辑:

  • 买入信号:当 Heikin-Ashi K线由红变绿(收盘价 > 开盘价),视为上涨趋势开始,全仓买入。
  • 卖出信号:当 Heikin-Ashi K线由绿变红(收盘价 < 开盘价),视为下跌趋势开始,清仓卖出。

策略代码

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

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 设置资金账号 (请替换为您自己的资金账号)
    ContextInfo.account_id = '6000000000' 
    ContextInfo.account_type = 'STOCK'
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 设置股票池 (示例:平安银行)
    ContextInfo.stock_code = '000001.SZ'
    ContextInfo.set_universe([ContextInfo.stock_code])
    
    # 策略参数
    ContextInfo.period = '1d'  # 周期:日线
    ContextInfo.lookback = 100 # 回溯K线数量,用于计算HA值的稳定性

def calculate_heikin_ashi(df):
    """
    计算 Heikin-Ashi 数据
    """
    ha_df = df.copy()
    
    # 1. 计算 HA_Close
    ha_df['HA_Close'] = (df['open'] + df['high'] + df['low'] + df['close']) / 4
    
    # 2. 计算 HA_Open
    # HA_Open 依赖于前一根 K 线的 HA 数据,需要迭代计算
    # 初始化列表,第一根 K 线的 HA_Open 设为普通 Open
    ha_open_list = [df['open'].iloc[0]]
    
    # 获取原始 Open 和 High, Low 数据用于后续计算(虽然 HA_Open 只依赖前值)
    # 注意:这里为了效率使用循环,对于极长序列可能需要优化,但对于 lookback=100 很快
    ha_close_values = ha_df['HA_Close'].values
    
    for i in range(1, len(df)):
        # HA_Open = (Prev_HA_Open + Prev_HA_Close) / 2
        prev_ha_open = ha_open_list[-1]
        prev_ha_close = ha_close_values[i-1]
        current_ha_open = (prev_ha_open + prev_ha_close) / 2
        ha_open_list.append(current_ha_open)
        
    ha_df['HA_Open'] = ha_open_list
    
    # 3. 计算 HA_High 和 HA_Low (本策略逻辑主要依赖 Open 和 Close,High/Low 可选)
    ha_df['HA_High'] = ha_df[['high', 'HA_Open', 'HA_Close']].max(axis=1)
    ha_df['HA_Low'] = ha_df[['low', 'HA_Open', 'HA_Close']].min(axis=1)
    
    return ha_df

def handlebar(ContextInfo):
    """
    K线运行函数
    """
    # 获取当前 bar 的索引
    index = ContextInfo.barpos
    
    # 获取当前时间
    realtime = ContextInfo.get_bar_timetag(index)
    
    # 获取股票代码
    stock = ContextInfo.stock_code
    
    # 获取历史行情数据 (多取一些数据以确保 HA 计算收敛)
    # 注意:get_market_data_ex 返回的是 {code: dataframe}
    data_map = ContextInfo.get_market_data_ex(
        ['open', 'high', 'low', 'close'], 
        [stock], 
        period=ContextInfo.period, 
        count=ContextInfo.lookback,
        dividend_type='front' # 前复权
    )
    
    if stock not in data_map:
        return
        
    df = data_map[stock]
    
    if len(df) < 2:
        return

    # 计算 Heikin-Ashi
    ha_df = calculate_heikin_ashi(df)
    
    # 获取当前 K 线的 HA 数据 (Series对象)
    current_bar = ha_df.iloc[-1]
    # 获取上一根 K 线的 HA 数据 (用于判断反转)
    prev_bar = ha_df.iloc[-2]
    
    # 定义颜色:True 为阳线(绿/涨),False 为阴线(红/跌)
    # 注意:国内习惯 红涨绿跌,但 HA 逻辑通常指 Close > Open 为强势
    is_bullish = current_bar['HA_Close'] > current_bar['HA_Open']
    is_bearish = current_bar['HA_Close'] < current_bar['HA_Open']
    
    # 获取当前持仓
    positions = ContextInfo.get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
    current_holding = 0
    for pos in positions:
        if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock:
            current_holding = pos.m_nVolume
            break
            
    # --- 交易逻辑 ---
    
    # 信号:HA 阳线 (看涨)
    if is_bullish:
        # 如果当前空仓或持仓不足,则买入
        # 这里简单演示全仓买入,实际需计算资金
        if current_holding == 0:
            # 获取账户可用资金
            account_info = ContextInfo.get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'ACCOUNT')
            if account_info:
                available_cash = account_info[0].m_dAvailable
                # 预留一点资金防止手续费不足,取 95%
                target_value = available_cash * 0.95
                
                print(f"[{stock}] HA转强 (Close: {current_bar['HA_Close']:.2f} > Open: {current_bar['HA_Open']:.2f}) -> 买入")
                # 使用 order_target_value 调整持仓市值
                order_target_value(stock, target_value, ContextInfo, ContextInfo.account_id)

    # 信号:HA 阴线 (看跌)
    elif is_bearish:
        # 如果有持仓,则清仓
        if current_holding > 0:
            print(f"[{stock}] HA转弱 (Close: {current_bar['HA_Close']:.2f} < Open: {current_bar['HA_Open']:.2f}) -> 卖出")
            order_target_value(stock, 0, ContextInfo, ContextInfo.account_id)

    # 绘图 (可选,用于回测界面观察)
    # 绘制 HA 的收盘价趋势
    ContextInfo.paint('HA_Close', current_bar['HA_Close'], -1, 0)

代码说明

  1. 数据获取 (get_market_data_ex):

    • 我们使用 get_market_data_ex 获取历史数据。
    • count=100:Heikin-Ashi 的 HA_Open 依赖于前一根 K 线的值。为了让计算结果准确(收敛),我们需要获取一定长度的历史数据进行迭代计算,而不是仅获取当前一根 K 线。
  2. HA 计算逻辑 (calculate_heikin_ashi):

    • 这是一个纯数学计算函数。
    • HA_Close 可以直接向量化计算。
    • HA_Open 必须通过循环计算,因为 t 时刻的值依赖于 t-1 时刻的值。
  3. 交易信号:

    • 看涨 (Bullish): HA_Close > HA_Open。这表示平均价格在上升,动能向上。
    • 看跌 (Bearish): HA_Close < HA_Open。这表示平均价格在下降。
  4. 下单函数 (order_target_value):

    • 使用 order_target_value 是最方便的仓位管理方式。
    • 买入时,目标市值设为可用资金的 95%(预留手续费)。
    • 卖出时,目标市值设为 0(清仓)。

注意事项

  • 回测与实盘: 该代码既可用于回测,也可用于实盘(需将 ContextInfo.account_id 替换为真实账号)。
  • 滞后性: Heikin-Ashi 本质上是一种平均算法,因此信号会比标准 K 线略有滞后,但能有效过滤震荡市中的假信号。
  • 第一根K线: 计算逻辑中,序列的第一根 K 线 HA_Open 被强制设为普通 Open,这会导致前几根 K 线的 HA 值不完全准确。这就是为什么我们在 get_market_data_ex 中读取 100 根 K 线的原因——经过几十根 K 线的迭代,数值会趋于精确。

Q&A

Q: 为什么不直接用 QMT 自带的指标计算?
A: QMT 的 Python API 主要提供原始行情数据。虽然部分技术指标库(如 TA-Lib)可以集成,但 Heikin-Ashi 这种特殊的 K 线形态构造通常需要手动计算,这样可以更灵活地控制逻辑(例如添加 HA_High/HA_Low 的过滤条件)。

Q: 如何增加过滤条件,例如只有“无下影线的阳线”才买入?
A: 您可以在 handlebar 函数的 is_bullish 判断中增加条件:

# 无下影线意味着 HA_Low 等于 HA_Open
is_strong_bullish = (current_bar['HA_Close'] > current_bar['HA_Open']) and \
                    (abs(current_bar['HA_Low'] - current_bar['HA_Open']) < 0.01)

Q: 这个策略适合什么周期?
A: Heikin-Ashi 在趋势明显的周期表现更好,通常建议用于 日线小时线。在分钟级震荡市中可能会产生较多磨损。