如何从tushare获取point in time的数据

2021/12/23 23:08:08

本文主要是介绍如何从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获取point in time的数据的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程