问题描述
解决方案
这是一个计算沪深300指数腾落指标(ADL)的 QMT Python 策略脚本。
策略说明
腾落指标 (ADL - Advance-Decline Line) 是一种市场广度指标,用于衡量参与市场涨跌的股票数量。
- 计算公式:$今日ADL = 昨日ADL + (今日上涨家数 - 今日下跌家数)$
- 逻辑:
- 在
init中初始化 ADL 累加器。 - 在
handlebar中,获取当前 K 线时间点的沪深300成分股。 - 批量获取这些成分股的行情数据(当前收盘价和前一日收盘价)。
- 统计上涨家数和下跌家数,计算净值并累加到 ADL。
- 使用
paint函数在副图绘制曲线。
- 在
策略代码
# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
"""
初始化函数
"""
# 定义目标指数代码:沪深300
ContextInfo.index_code = '000300.SH'
# 初始化 ADL 累积值,从0开始
ContextInfo.adl_value = 0
# 设置副图显示的指标名称和颜色
# 注意:paint函数会自动处理绘图,这里主要用于逻辑初始化
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 获取当前K线的位置
barpos = ContextInfo.barpos
# 获取当前K线的时间戳(毫秒)
timetag = ContextInfo.get_bar_timetag(barpos)
# 1. 获取该时间点沪深300的成分股列表
# 注意:使用 timetag 可以获取历史时刻真实的成分股,避免幸存者偏差
stock_list = ContextInfo.get_sector(ContextInfo.index_code, timetag)
if not stock_list:
return
# 2. 批量获取成分股的行情数据
# 我们需要比较今日收盘价和昨日收盘价,所以 count=2
# period='1d' 表示日线,dividend_type='front' 使用前复权价格
data_map = ContextInfo.get_market_data_ex(
fields=['close'],
stock_code=stock_list,
period='1d',
count=2,
dividend_type='front',
fill_data=True, # 填充停牌数据
subscribe=False
)
up_count = 0 # 上涨家数
down_count = 0 # 下跌家数
# 3. 遍历所有成分股计算涨跌
for stock in stock_list:
if stock in data_map:
df = data_map[stock]
# 确保有足够的数据进行比较(至少需要两天的数据)
if len(df) >= 2:
# 获取今日收盘价和昨日收盘价
# iloc[-1] 是最新一根K线(当前bar),iloc[-2] 是前一根
close_today = df.iloc[-1]['close']
close_prev = df.iloc[-2]['close']
# 判断涨跌
if close_today > close_prev:
up_count += 1
elif close_today < close_prev:
down_count += 1
# 平盘(close_today == close_prev)不计入
# 4. 计算当期净腾落值
net_change = up_count - down_count
# 5. 累加到 ADL
# 注意:如果是第一根K线,ADL就是当天的净值,之后累加
ContextInfo.adl_value += net_change
# 6. 绘图输出
# 在副图绘制 ADL 指标线
ContextInfo.paint('ADL', ContextInfo.adl_value, -1, 0, 'yellow')
# 可选:绘制一条0轴参考线
ContextInfo.paint('Zero', 0, -1, 0, 'gray', 'noaxis')
使用方法与注意事项
-
运行模式:
- 请在 QMT 的 “模型研究” 或 “策略编辑器” 中新建一个 Python 策略。
- 将上述代码复制进去。
- 点击 “运行” 或 “回测”。
- 重要:请确保运行周期选择 “日线 (1d)”,因为 ADL 通常是基于日线级别的统计指标。
-
数据准备:
- 运行前,请确保已下载 沪深300指数 以及 其成分股 的日线历史数据。
- 如果数据不全,
get_market_data_ex可能无法获取足够的历史价格,导致计算结果为 0。
-
显示位置:
- 在策略编辑器的“基本信息”中,将 “位置” 设置为 “副图”,这样 ADL 曲线会显示在 K 线图的下方。
-
逻辑解释:
ContextInfo.get_sector(..., timetag):这是关键步骤。它确保了在回测历史时间点(比如2020年)时,使用的是当时(2020年)的沪深300成分股,而不是现在的成分股,从而保证了回测的准确性。count=2:我们需要“今天”和“昨天”的数据来判断涨跌,所以一次性取2根K线。
常见问题 (Q&A)
Q: 为什么 ADL 曲线的数值很大或者是负数?
A: ADL 是一个累积指标,其绝对数值的大小取决于计算的起始时间点。绝对值本身没有意义,有意义的是曲线的走势和形态(例如与指数价格的背离)。
Q: 为什么第一根 K 线的 ADL 值不是 0?
A: 脚本逻辑是 ContextInfo.adl_value += net_change。在图表的第一根 K 线,它会计算当天的 (涨-跌),所以值是当天的净变化量,不一定是 0。
Q: 如何计算其他指数(如中证500)的 ADL?
A: 只需将 init 函数中的 ContextInfo.index_code = '000300.SH' 修改为 '000905.SH' (中证500) 或其他指数代码即可。