Tushare数据平台提供了丰富的金融数据,对于量化分析来说是必不可少的利器。但是相比其他在线平台,它提供的数据都是比较基础的,需要自己加工。
比如量化分析时经常需要剔除当时的ST、*ST股票,tushare没有提供现成的工具。
现成方法
网上现成的方法都是筛选某一只股票在特定时间是否ST,比如这样的:Tushare判断指定日期股票是否ST,基本思路是使用tushare的“股票曾用名”函数,先提取单只股票所有的更名记录,然后判断要筛选的时间是否在ST的时间范围内。
我试了一下,运行这位大佬的函数需要0.1秒,对单只股票来说不错,但是如果要筛选一个时间点所有ST股票难道要调用5000多次,那就是500多分钟,8个多小时?显然是不可接受的。
函数解析
tushare的“股票曾用名”函数定义如下:
pro = ts.pro_api()
df = pro.namechange(ts_code,start_date,end_date,fields)
返回结果:
名称 类型 默认输出 描述
ts_code str Y TS代码
name str Y 证券名称
start_date str Y 开始日期
end_date str Y 结束日期
ann_date str Y 公告日期
change_reason str Y 变更原因
注意这里有个小坑:参数中的start_date,end_date是公告日期,返回结果中的start_date,end_date是st的开始时间和结束时间,不过对接下来的程序影响不大,知道就行了。
这个函数可以不用指定股票代码,甚至不用任何参数,也就是说可以一次调取历史上所有股票所有更名记录。经测试,调用所有数据只需要0.8秒,在可接受范围。
当然还可以优化,由于ST最多3年就要退市,可以只取3年内被ST的记录。这样时间可以缩短到大约0.4秒。
注意有坑
说到这里思路就出来了:提取3年内所有股票更名记录,然后筛选目标时间在返回结果的start_date和end_date之间的数据,就是目标时间处于ST状态的股票了。但是注意有个坑:
运行如下代码:
pro.namechange(ts_code='002122.SZ')
输出结果:
ts_code name start_date end_date ann_date change_reason
0 002122.SZ 天马股份 20230228 None 20230227 撤销ST
1 002122.SZ ST天马 20230110 None 20230107 撤销*ST
2 002122.SZ ST天马 20230110 20230227 20230107 撤销*ST
3 002122.SZ *ST天马 20221102 None 20221101 *ST
4 002122.SZ *ST天马 20221102 20230109 20221101 *ST
5 002122.SZ ST天马 20210616 None 20210615 摘星
6 002122.SZ ST天马 20210616 20221101 20210615 摘星
7 002122.SZ *ST天马 20180503 None 20180502 *ST
8 002122.SZ *ST天马 20180503 20210615 20180502 *ST
9 002122.SZ 天马股份 20070328 20180502 None 其他|
注意看,每次更名ST的记录都出现了两次,其中一次end_date为None,另一次为正常时间。如果直接判断会出错,必须把多余的一次去掉。使用如下代码:
pro.namechange(ts_code='002122.SZ').sort_values(by='end_date',ascending=True).drop_duplicates(['ts_code','start_date'],keep='first')
输出为:
ts_code name start_date end_date ann_date change_reason
9 002122.SZ 天马股份 20070328 20180502 None 其他
8 002122.SZ *ST天马 20180503 20210615 20180502 *ST
6 002122.SZ ST天马 20210616 20221101 20210615 摘星
4 002122.SZ *ST天马 20221102 20230109 20221101 *ST
2 002122.SZ ST天马 20230110 20230227 20230107 撤销*ST
0 002122.SZ 天马股份 20230228 None 20230227 撤销ST
输出正确!
完整代码
import datetime as datetime
import tushare as ts
ts.set_token('******')
#此处为注册后才有的token,请用文章开头的链接注册
pro = ts.pro_api()
def get_st(trade_date):
'''
功能:筛选指定时间ST、*ST股票
输入:要筛选的目标日期,格式YYYYMMDD
输出:该时间内处于ST、*ST状态的股票代码、名称、ST开始结束日期、公告日期
'''
# 获取三年前日期,因为ST最多3年
start_date = (datetime.datetime.strptime(trade_date,'%Y%m%d') - datetime.timedelta(days=365*3)).strftime('%Y%m%d')
# 获取三年内所有更名记录
df = pro.namechange(start_date=start_date,end_date=trade_date, fields='ts_code,name,start_date,end_date,ann_date,change_reason')
# 筛选更名原因为ST或*ST的记录,去掉结束日期重复为None的
df = df[(df['change_reason']=='ST') | (df['change_reason']=='*ST')] \
.sort_values(by='end_date',ascending=True).drop_duplicates(subset=['ts_code','start_date'],keep='first')
# 筛选目标日期在ST时间段的记录
result = df[(df.start_date<=trade_date) & ((df.end_date>=trade_date) | (df.end_date.isna()))]
return result