问题描述
解决方案
在 QMT 中过滤上市时间不足一年的股票,核心逻辑是利用 ContextInfo.get_open_date(stockcode) 获取股票的上市日期,并将其与当前策略运行的日期进行对比,计算时间差是否大于 365 天。
以下是具体的实现步骤和代码示例。
核心逻辑说明
- 获取上市日期:使用
ContextInfo.get_open_date(stockcode),该函数返回一个整数类型的日期(格式如20200101)。 - 获取当前日期:在
handlebar中通过ContextInfo.get_bar_timetag(ContextInfo.barpos)获取当前 K 线的时间戳,并使用timetag_to_datetime转换为字符串日期。 - 计算时间差:利用 Python 的标准库
datetime将上述两个日期转换为日期对象,相减得到天数,判断是否大于等于 365。
策略代码实现
# -*- coding: gbk -*-
import datetime
def init(ContextInfo):
# 示例:设置股票池为沪深300成分股
# 实际使用时可根据需求设置为全A股或其他板块
index_code = '000300.SH'
ContextInfo.set_universe([index_code])
# 这里为了演示,我们先获取板块成分股作为待筛选列表
# 注意:get_sector 返回的是成分股列表
ContextInfo.stock_list = ContextInfo.get_sector(index_code)
print(f"初始股票池数量: {len(ContextInfo.stock_list)}")
def handlebar(ContextInfo):
# 仅在最后一根K线或回测的每一根K线执行筛选逻辑
# 获取当前K线的时间戳
timetag = ContextInfo.get_bar_timetag(ContextInfo.barpos)
# 将时间戳转换为 'YYYYMMDD' 格式的字符串
current_date_str = timetag_to_datetime(timetag, '%Y%m%d')
# 存储筛选后的股票
valid_stocks = []
for stock in ContextInfo.stock_list:
# 1. 获取上市日期 (返回格式为 int,例如 20210101)
open_date_int = ContextInfo.get_open_date(stock)
# 异常处理:如果获取不到上市日期(返回0),则跳过
if open_date_int == 0:
continue
try:
# 2. 格式转换:将 int 和 str 转换为 datetime 对象
open_date_dt = datetime.datetime.strptime(str(open_date_int), '%Y%m%d')
current_date_dt = datetime.datetime.strptime(current_date_str, '%Y%m%d')
# 3. 计算上市天数
days_diff = (current_date_dt - open_date_dt).days
# 4. 过滤条件:上市时间 >= 365天
if days_diff >= 365:
valid_stocks.append(stock)
except Exception as e:
# 捕获可能的日期格式错误
print(f"处理股票 {stock} 日期时出错: {e}")
continue
# 输出结果
print(f"日期: {current_date_str}, 筛选后剩余股票数量: {len(valid_stocks)}")
# 如果需要将筛选后的股票用于后续交易,可以更新到 ContextInfo 中
# ContextInfo.trade_stocks = valid_stocks
代码关键点解析
timetag_to_datetime: QMT 内置的全局函数,非常方便地将毫秒级时间戳转换为指定格式的日期字符串。datetime.datetime.strptime: 用于将字符串(如'20230101')解析为 Python 的日期对象,这是进行日期加减运算的前提。- 异常处理:
open_date_int == 0的判断是必要的,因为某些未上市或数据缺失的标的可能会返回 0,直接转换会导致程序报错。
Q&A
Q: ContextInfo.get_open_date 返回的数据类型是什么?
A: 它返回的是一个 number (整数),格式为 YYYYMMDD(例如 20200101)。在使用 datetime.strptime 解析前,通常需要先用 str() 将其转换为字符串。
Q: 如何过滤掉 ST 股票?
A: 可以使用 ContextInfo.is_st_stock(stockcode) (注意:API文档中未直接列出 is_st_stock,通常使用 ContextInfo.get_his_st_data(stockCode) 获取历史 ST 状态) 或者通过名称判断。最准确的方法是使用 ContextInfo.get_his_st_data(stockCode),该函数返回一个字典,包含该股票 ST 的历史区间,如果当前日期在 ST 区间内,则剔除。
Q: 这段代码可以在回测和实盘中使用吗?
A: 是的。handlebar 函数在回测模式下会逐 K 线运行,current_date_str 会随着回测时间推进而变化,从而动态判断当时的股票是否满足上市满一年的条件。在实盘模式下,它会取最新的时间进行判断。