如何从tushare获取point in time的数据
作者:互联网
tushare ID:456497
在资产定价的研究中,我们所使用的数据应该遵循point in time原则,既获取:对应调用日期所能获取的最新数据。听起来简单做起来却不然。一般来说,从原始报表构造的因子(截面,不是时序)有五种方法,分别为:1.获取对应调用日期所能获取的最新报告期的最新(实际报告期)数据。2.获取对应调用日期所能获取的最新报告期的单季度数据(如利润表中大部分数据都是按季度累计的,需要差分,然而差分也会随着调用日期的变化而有变化)。3.获取对应调用日期所能获取的对应的最新报告期的同比增长率。4.获取对应报告期所能获取的最新报告期的ttm数据(过去一年的对应数据的加总或平均)。5.获取对应报告期所能获取的最新报告期的单季度的ttm数据(2和4的综合)。显然第一种情况最简单,后面因为涉及到跨季度的情况,较为复杂。复杂的原因在于:调用之前的数据时调用的数据会随着调用日期的变化而变化,比如某公司在2017年4月公布2016年年报,总资产1亿,而在2017年8月公布调整年报,或者于2018年4月公布基准报表,都会改变2016年年报的总资产,假设改成了1.5亿。那么在2017年4月调用总资产就应该调用1亿,而在2018年4月之后计算总资产同比增长率,会需要2016年年报数据,那么就应该用1.5亿计算。
首先先获取tushare的所有报表:
import tushare as ts
import pandas as pd
import numpy as np
from time import time
path='D://data//data_test'
ts.set_token(自己的token)
pro = ts.pro_api()
code = pro.stock_basic()
def get_balancesheet(codelist,starttime,endtime,report_type=1):
try:
startdate=str(starttime)
enddate=str(endtime)
df = pro.balancesheet(ts_code=codelist,start_date=startdate,end_date=enddate,report_type=report_type)
return df.set_index('ts_code')
except:
df=get_balancesheet(codelist,starttime,endtime,report_type)
return df.set_index('ts_code')
def get_income(codelist,starttime,endtime,report_type=1):
try:
startdate=str(starttime)
enddate=str(endtime)
df = pro.income(ts_code=codelist,start_date=startdate,end_date=enddate,report_type=report_type)
return df.set_index('ts_code')
except:
df=get_income(codelist,starttime,endtime,report_type)
return df.set_index('ts_code')
def get_cashflow(codelist,starttime,endtime,report_type=1):
try:
startdate=str(starttime)
enddate=str(endtime)
df = pro.cashflow(ts_code=codelist,start_date=startdate,end_date=enddate,report_type=report_type)
return df.set_index('ts_code')
except:
df=get_cashflow(codelist,starttime,endtime,report_type)
return df.set_index('ts_code')
def get_bar(codelist,starttime,endtime,typ=None):
try:
startdate=str(starttime)
enddate=str(endtime)
df = ts.pro_bar(ts_code=codelist,start_date=startdate,end_date=enddate,adj=typ)
return df.set_index('ts_code')
except:
df=get_bar(codelist,starttime,endtime)
return df.set_index('ts_code')
def get_name(codelist):
try:
data = pro.namechange(ts_code=codelist)
return data
except:
data=get_name(codelist)
return data
for i in range(0,code.shape[0]):
try:
bfq1=get_bar(code['ts_code'].iloc[i],20100101,20201231)
bfq2=get_bar(code['ts_code'].iloc[i],20000101,20091231)
bfq=bfq1.append(bfq2).sort_values('trade_date',ascending=False)
if bfq.shape[0]>0:
bfq.to_excel(path+'//0//bar//bfq//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
hfq1=get_bar(code['ts_code'].iloc[i],20100101,20201231,'hfq')
hfq2=get_bar(code['ts_code'].iloc[i],20000101,20091231,'hfq')
hfq=hfq1.append(hfq2).sort_values('trade_date',ascending=False)
if hfq.shape[0]>0:
hfq.to_excel(path+'//0//bar//hfq//'+code['ts_code'].iloc[i]+'.xlsx')
except:
try:
if hfq1.shape[0]>0:
hfq1.to_excel(path+'//0//bar//hfq//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
balancesheet1=get_balancesheet(code['ts_code'].iloc[i],20000101,20201231,1)
if balancesheet1.shape[0]>0:
balancesheet1.to_excel(path+'//0//balancesheet//1//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
balancesheet4=get_balancesheet(code['ts_code'].iloc[i],20000101,20201231,4)
if balancesheet4.shape[0]>0:
balancesheet4.to_excel(path+'//0//balancesheet//4//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
balancesheet5=get_balancesheet(code['ts_code'].iloc[i],20000101,20201231,5)
if balancesheet5.shape[0]>0:
balancesheet5.to_excel(path+'//0//balancesheet//5//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
income1=get_income(code['ts_code'].iloc[i],20000101,20201231,1)
if income1.shape[0]>0:
income1.to_excel(path+'//0//income//1//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
income4=get_income(code['ts_code'].iloc[i],20000101,20201231,4)
if income4.shape[0]>0:
income4.to_excel(path+'//0//income//4//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
income5=get_income(code['ts_code'].iloc[i],20000101,20201231,5)
if income5.shape[0]>0:
income5.to_excel(path+'//0//income//5//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
cashflow1=get_cashflow(code['ts_code'].iloc[i],20000101,20201231,1)
if cashflow1.shape[0]>0:
cashflow1.to_excel(path+'//0//cashflow//1//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
cashflow4=get_cashflow(code['ts_code'].iloc[i],20000101,20201231,4)
if cashflow4.shape[0]>0:
cashflow4.to_excel(path+'//0//cashflow//4//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
cashflow5=get_cashflow(code['ts_code'].iloc[i],20000101,20201231,5)
if cashflow5.shape[0]>0:
cashflow5.to_excel(path+'//0//cashflow//5//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
try:
name=get_name(code['ts_code'].iloc[i])
if name.shape[0]>0:
name.to_excel(path+'//0//name//'+code['ts_code'].iloc[i]+'.xlsx')
except:
1
值得一提的是,报表有多种类型,我们需要调用的是调整后初始报表,调整后基准报表和调整前的初始报表,调整前基准报表。相关数据在tushare函数的report_type分别为1,4,5时返回。有些公司report_type=4或5时相关报表可能是空值。我们需要做的是尽量下载这三种报表并且合并,然后分别根据f_ann_date,end_date和update_flag三个数据来选择自己需要的数据。其中,f_ann_date是实际公告日期,end_date是报告期,update_flag是调整标识。想要观察某个样本究竟是原始报表,还是调整或者修正后的需要比较f_ann_date和end_date。倘若有两个样本的end_date相同,而f_ann_date不同,那毫无疑问f_ann_date大的样本是调整或修正的。当然还有很多情况,比如:有两个样本,一个end_date大,f_ann_date小,另一个end_date小,f_ann_date大,那么第二个样本一定是已经公布第一个样本对应的报表后的修正数据。另外还有一种极端情况:修正数据和初始数据在同一天出现,这时仅保留update_flag=1的即可。下面是一个提取point in time数据的函数:
def get_pit_data(codelist,table='balancesheet',req_type=1,varlist=None):
data1=pd.read_excel(path+'//0//'+table+'//1//'+codelist+'.xlsx')
try:
data4=pd.read_excel(path+'//0//'+table+'//4//'+codelist+'.xlsx')
except:
1
try:
data5=pd.read_excel(path+'//0//'+table+'//5//'+codelist+'.xlsx')
except:
1
data=1*data1
data_tool=1*data1
try:
data=data.append(data4)
data_tool=data_tool.append(data4)
except:
1
try:
data=data.append(data5)
data_tool=data_tool.append(data5)
except:
1
data=data.sort_values(['end_date','f_ann_date','update_flag'])
if varlist!=None:
try:
var1=['f_ann_date','end_date']
varlist=var1+varlist
varlist.append('update_flag')
data=data[varlist]
except:
var1=['f_ann_date','end_date']
var1.append(varlist)
var1.append('update_flag')
data=data[var1]
上面是函数的第一段。其中codelist如'000001.SZ',table可选'balancesheet','income'或'cashflow',req_type可选1-5,分别对应开头的五种情况,varlist可以选择报表中的变量组成的字符串或者不选。接下来首先要处理修正数据和初始数据同一天公布的情况,比如股票002157.SZ的利润表:
f_ann_date end_date update_flag
6 20191024 20190930 0
0 20201028 20190930 0
5 20200421 20191231 0
4 20200421 20191231 1
2 20200421 20200331 0
3 20200421 20200331 1
1 20200828 20200630 1
0 20201028 20200930 1
其中2020年4月21号连续公布了多个数据,此时应该只保留update_flag=1的样本。
data.index=range(0,data.shape[0])
data=data.loc[data[['f_ann_date','end_date']].drop_duplicates(keep='last').index]
data_tool=data_tool.sort_values(['end_date','f_ann_date','update_flag'])
注意,data是删除了上述情况的数据,而data_tool一直是全数据。接下来处理第一种情况。第一种情况的关键是删除类似如下的样本:
f_ann_date end_date update_flag tool
4 20070816 20060630 0 210.0
6 20071026 20060930 0 -300.0
7 20070726 20061231 0 9692.0
8 20080418 20061231 0 8.0
10 20080426 20070331 0 -9610.0
f_ann_date end_date update_flag tool
113 20201028 20190930 0 -607.0
115 20200421 20191231 1 0.0
117 20200421 20200331 1 407.0
118 20200828 20200630 1 200.0
其中20171026公布的报表和20200421公布的2019年年报需要删去(保留当前调用日期的最新报告期的最新实际报告期数据)。
if req_type==1:
for i in range(0,100):
data['tool']=data['f_ann_date'].diff().shift(-1).fillna(1)
data=data[data['tool']>0]
data['tool']=data['f_ann_date'].diff().shift(-1).fillna(1)
if data['tool'].min()>0:
break
del data['tool']
return data
接下来处理第二种情况。第二种情况的关键是对于每一个f_ann_date,找到最新的报告期,倘若报告期不是一季度的,那么再找上一个报告期并且实际报告期在当前f_ann_date之前的所有数据。如果end_date有重复那么保留f_ann_date最大的数据。倘若上一个报告期缺失那么当前季度数据也应该缺失,倘若当前报告期是一季度,那么当前季度数据就是原数据。
if req_type==2:
result=data*1
for i in range(0,100):
result['tool']=result['f_ann_date'].diff().shift(-1).fillna(1)
result=result[result['tool']>0]
result['tool']=result['f_ann_date'].diff().shift(-1).fillna(1)
if result['tool'].min()>0:
break
del result['tool']
result['year']=(result['end_date']/10000).astype(int)
result['season']=((result['end_date']-10000*result['year'])/400+1).astype(int)
data_tool['year']=(data_tool['end_date']/10000).astype(int)
data_tool['season']=((data_tool['end_date']-10000*data_tool['year'])/400+1).astype(int)
droping_code=['ts_code', 'ann_date', 'f_ann_date', 'end_date', 'report_type','comp_type', 'end_type','update_flag']
for i in range(0,result.shape[0]):
#所有数据中选中了某个实际公告期并且筛选此前公告期
tool3=data_tool[data_tool['f_ann_date']<=result['f_ann_date'].iloc[i]]
#tool3是某个实际公告日期对应的同年上一个季度且实际公告期小于等于当前实际公告期的数据(如果是一季度,那么就是空矩阵)
tool3=tool3[tool3['year']==result['year'].iloc[i]]
tool3=tool3[tool3['season']==result['season'].iloc[i]-1]
tool3=tool3[tool3['f_ann_date']<=result['f_ann_date'].iloc[i]]
#选择tool3的最新结果作为当前实际公告期所知的上年同季度数据
try:
tool3=tool3.iloc[tool3.shape[0]-1]
for j in data.columns:
if j not in droping_code:
result[j].iloc[i]=result[j].iloc[i]-tool3[j]
#如果报错,那么必然是因为上面第一句里面tool3是空矩阵,有可能是本来就没有上一个
#季度数据或者本季度是一季度
except:
for j in data.columns:
if j not in droping_code:
if result['season'].iloc[i]==1:
result[j].iloc[i]=result[j].iloc[i]
else:
result[j].iloc[i]=np.nan
del result['year']
del result['season']
return result
后面的暂时懒得写了,大家自己看代码吧(捂脸)
if req_type==3:
tool1=1*data
tool1['year']=(tool1['end_date']/10000).astype(int)
tool1['season']=((tool1['end_date']-10000*tool1['year'])/400+1).astype(int)
#tool2是所有数据
tool2=1*data_tool
tool2['year']=(tool2['end_date']/10000).astype(int)
tool2['season']=((tool2['end_date']-10000*tool2['year'])/400+1).astype(int)
droping_code=['ts_code', 'ann_date', 'f_ann_date', 'end_date', 'report_type','comp_type', 'end_type','update_flag']
for i in range(0,100):
tool1['tool']=tool1['f_ann_date'].diff().shift(-1).fillna(1)
tool1=tool1[tool1['tool']>0]
tool1['tool']=tool1['f_ann_date'].diff().shift(-1).fillna(1)
if tool1['tool'].min()>0:
break
del tool1['tool']
for i in range(0,tool1.shape[0]):
#tool3是所有数据中选中了某个实际公告期的筛选后数据
tool3=tool2[tool2['f_ann_date']<=tool1['f_ann_date'].iloc[i]]
#tool3是某个实际公告日期对应的上一年同季度的数据
tool3=tool3[tool3['year']==tool1['year'].iloc[i]-1]
tool3=tool3[tool3['season']==tool1['season'].iloc[i]]
tool3=tool3[tool3['f_ann_date']<=tool1['f_ann_date'].iloc[i]]
#选择tool3的最新结果作为当前实际公告期所知的上年同季度数据
try:
tool3=tool3.iloc[tool3.shape[0]-1]
for j in data.columns:
if j not in droping_code:
tool1[j].iloc[i]=100*(tool1[j].iloc[i]-tool3[j])/tool3[j]
except:
for j in data.columns:
if j not in droping_code:
tool1[j].iloc[i]=np.nan
del tool1['year']
del tool1['season']
return tool1
if req_type==4:
result=data*1
for i in range(0,100):
result['tool']=result['f_ann_date'].diff().shift(-1).fillna(1)
result=result[result['tool']>0]
result['tool']=result['f_ann_date'].diff().shift(-1).fillna(1)
if result['tool'].min()>0:
break
del result['tool']
result['year']=(result['end_date']/10000).astype(int)
result['season']=((result['end_date']-10000*result['year'])/400+1).astype(int)
data_tool['year']=(data_tool['end_date']/10000).astype(int)
data_tool['season']=((data_tool['end_date']-10000*data_tool['year'])/400+1).astype(int)
droping_code=['ts_code', 'ann_date', 'f_ann_date', 'end_date', 'report_type','comp_type', 'end_type','update_flag']
for i in range(0,result.shape[0]):
tool3=data_tool[data_tool['f_ann_date']<=result['f_ann_date'].iloc[i]]
tool3=tool3[tool3['year']>=result['year'].iloc[i]-1]
tool3=tool3[tool3['year']<=result['year'].iloc[i]]
tool3.index=range(0,tool3.shape[0])
tool3.loc[tool3[tool3['year']==result['year'].iloc[i]-1][tool3[tool3['year']==result['year'].iloc[i]-1]['season']<=result['season'].iloc[i]].index]=np.nan
tool3=tool3.dropna(axis=0,how='all')
tool3.index=range(0,tool3.shape[0])
tool3.loc[tool3[tool3['year']==result['year'].iloc[i]][tool3[tool3['year']==result['year'].iloc[i]]['season']>result['season'].iloc[i]].index]=np.nan
tool3=tool3.dropna(axis=0,how='all')
tool3.index=range(0,tool3.shape[0])
tool3=tool3.loc[tool3['end_date'].drop_duplicates(keep='last').index]
if tool3.shape[0]==4:
tool3=tool3.sum(skipna=False)
for j in data.columns:
if j not in droping_code:
result[j].iloc[i]=tool3[j]
else:
for j in data.columns:
if j not in droping_code:
result[j].iloc[i]=np.nan
del result['year']
del result['season']
return result
if req_type==5:
result=data*1
for i in range(0,100):
result['tool']=result['f_ann_date'].diff().shift(-1).fillna(1)
result=result[result['tool']>0]
result['tool']=result['f_ann_date'].diff().shift(-1).fillna(1)
if result['tool'].min()>0:
break
del result['tool']
result['year']=(result['end_date']/10000).astype(int)
result['season']=((result['end_date']-10000*result['year'])/400+1).astype(int)
data_tool['year']=(data_tool['end_date']/10000).astype(int)
data_tool['season']=((data_tool['end_date']-10000*data_tool['year'])/400+1).astype(int)
droping_code=['ts_code', 'ann_date', 'f_ann_date', 'end_date', 'report_type','comp_type', 'end_type','update_flag']
for i in range(0,result.shape[0]):
tool3=data_tool[data_tool['f_ann_date']<=result['f_ann_date'].iloc[i]]
tool3=tool3[tool3['year']>=result['year'].iloc[i]-1]
tool3=tool3[tool3['year']<=result['year'].iloc[i]]
tool3.index=range(0,tool3.shape[0])
tool3.loc[tool3[tool3['year']==result['year'].iloc[i]-1][tool3[tool3['year']==result['year'].iloc[i]-1]['season']<result['season'].iloc[i]].index]=np.nan
tool3=tool3.dropna(axis=0,how='all')
tool3.index=range(0,tool3.shape[0])
tool3.loc[tool3[tool3['year']==result['year'].iloc[i]][tool3[tool3['year']==result['year'].iloc[i]]['season']>result['season'].iloc[i]].index]=np.nan
tool3=tool3.dropna(axis=0,how='all')
tool3.index=range(0,tool3.shape[0])
tool3=tool3.loc[tool3['end_date'].drop_duplicates(keep='last').index]
try:
tool4=tool3[tool3['year']==tool3['year'].iloc[tool3.shape[0]-1]-1]
tool5=tool4[tool4['season']==tool3['season'].iloc[tool3.shape[0]-1]]
tool6=tool4[tool4['season']==4]
for j in data.columns:
if j not in droping_code:
result[j].iloc[i]=np.nan
result[j].iloc[i]=tool3[j].iloc[tool3.shape[0]-1]+tool6[j].iloc[0]-tool5[j].iloc[0]
except:
for j in data.columns:
if j not in droping_code:
result[j].iloc[i]=np.nan
del result['year']
del result['season']
return result
祝大家好运
标签:tushare,code,point,tool,ts,result,time,date,data 来源: https://blog.csdn.net/liulianqianceng/article/details/122117473