问题描述
解决方案
这是一个基于 Heikin-Ashi (平均K线) 的交易策略。
策略原理
Heikin-Ashi(平均K线)是一种对标准K线(OHLC)进行平滑处理的技术,旨在过滤市场噪音,更清晰地展示趋势。
计算公式:
- HA_Close (收盘价) = (开盘价 + 最高价 + 最低价 + 收盘价) / 4
- HA_Open (开盘价) = (上一根 HA_Open + 上一根 HA_Close) / 2
- HA_High (最高价) = Max(最高价, HA_Open, HA_Close)
- 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)
代码说明
-
数据获取 (
get_market_data_ex):- 我们使用
get_market_data_ex获取历史数据。 count=100:Heikin-Ashi 的HA_Open依赖于前一根 K 线的值。为了让计算结果准确(收敛),我们需要获取一定长度的历史数据进行迭代计算,而不是仅获取当前一根 K 线。
- 我们使用
-
HA 计算逻辑 (
calculate_heikin_ashi):- 这是一个纯数学计算函数。
HA_Close可以直接向量化计算。HA_Open必须通过循环计算,因为t时刻的值依赖于t-1时刻的值。
-
交易信号:
- 看涨 (Bullish):
HA_Close > HA_Open。这表示平均价格在上升,动能向上。 - 看跌 (Bearish):
HA_Close < HA_Open。这表示平均价格在下降。
- 看涨 (Bullish):
-
下单函数 (
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 在趋势明显的周期表现更好,通常建议用于 日线 或 小时线。在分钟级震荡市中可能会产生较多磨损。