问题描述
start_time 与 end_time 之间差一年,如果股票中间停牌过,哪么下载的数据就不够一年, 看下图,下载的一段数据是空值。get_market_data_ex 计算年线均值就不准了?
download_history_data2 接口里怎么没有 count 字段? 与 get_market_data_ex 对应不起来呀?
解决方案
在 QMT 平台中,关于数据下载接口和数据读取接口的设计逻辑是不同的,这也是为什么你会发现 download_history_data2 没有 count 字段,而 get_market_data_ex 有 count 字段的原因。
以下是详细的解答和解决停牌导致均线计算不准的方案:
1. 为什么 download_history_data2 没有 count 字段?
- 下载接口的逻辑(基于时间区间):
download_history_data2等数据下载接口的主要作用是将服务器上的历史数据同步到本地硬盘。它的逻辑是“把某段时间内(start_time到end_time)发生的所有真实交易数据拉取下来”。因此,它只需要时间区间,不需要count。如果这期间股票停牌了 10 天,那么这 10 天在交易所端本来就没有交易数据,下载下来的物理数据自然也就少 10 根 K 线。 - 读取接口的逻辑(基于条数/业务需求):
get_market_data_ex是从本地读取数据供策略计算使用的接口。在编写策略时,我们经常需要“过去 250 个交易日的数据”来计算年线,这时候就需要count=250。系统会从指定的结束时间往前推,直到凑齐 250 根有交易的 K 线(或者根据设置进行停牌填充)。
2. 停牌导致年线(250日均线)计算不准怎么办?
如果你仅仅通过 start_time 和 end_time 限制了一年的日历时间(比如 2022-01-01 到 2023-01-01),由于节假日和停牌,实际获取的 K 线数量肯定不足 250 根,直接求均值自然是不准的。
正确的做法是:在使用 get_market_data_ex 时,放弃使用 start_time,仅使用 end_time 和 count 参数。
解决方案代码示例:
#encoding:gbk
import pandas as pd
def init(ContextInfo):
# 设置股票池
ContextInfo.set_universe(['000001.SZ', '000004.SZ'])
def handlebar(ContextInfo):
# 确保在最后一根K线执行
if not ContextInfo.is_last_bar():
return
stock_list = ContextInfo.get_universe()
# 核心:不要设 start_time,只设 count=250
# 这样系统会自动往前找齐 250 根实际交易的 K 线
data = ContextInfo.get_market_data_ex(
fields=['close'],
stock_code=stock_list,
period='1d',
start_time='',
end_time='', # 为空表示取到最新时间
count=250, # 强制获取 250 根 K 线
dividend_type='front', # 前复权
subscribe=True
)
for stock in stock_list:
if stock in data and not data[stock].empty:
df = data[stock]
# 检查是否取够了 250 根数据(新股可能不足)
if len(df) == 250:
# 计算 250 日均线(年线)
ma250 = df['close'].mean()
print(f"{stock} 的 250 日均线为: {ma250:.2f}")
else:
print(f"{stock} 数据不足 250 根,当前只有 {len(df)} 根")
3. 关于数据中的空值(NaN)问题
如果你在某些特定场景下必须使用 start_time 和 end_time,并且遇到了停牌导致的空值(NaN),你可以利用 Python 的 pandas 库来进行向前填充(Forward Fill),即用停牌前最后一天的收盘价来填充停牌期间的价格。
# 假设 df 是你获取到的包含 NaN 的 DataFrame
# 使用 ffill() 方法,用前一个有效值填充缺失值
df['close'] = df['close'].fillna(method='ffill')
# 然后再计算均值
ma_value = df['close'].mean()
总结:
下载数据时按时间段下载(确保本地数据完整),但在策略代码中读取数据计算指标时,强烈建议使用 count 参数来获取固定长度的 K 线序列,这样可以完美避开停牌导致的数据长度不足问题,确保均线等技术指标计算的准确性。