前言:
距离上一篇文章好快又过了一个月了,这段时间大体深入学了点backtrader回测的内容,感觉有点难,在写tushare数据处理过程遇到了数据合并这一难题,首先tushare的收盘价开盘价获取得到的数据是以下这样的,
df_daily = ts.pro_bar(ts_code=stock_code, start_date='20150101', end_date='20210203', adj='qfq', freq='D')
df_stockind = pro.daily_basic(ts_code=stock_code, start_date='20150101', end_date='20210203', adj='qfq', freq='D',
fields='trade_date, pe, pb, turnover_rate, volume_ratio')
df_fina = pro.fina_indicator(ts_code=stock_code, start_date='20150101')
简直要兔血。
之所以要合并,是因为我是打算回测股票的投资组合,其中包括了基本面的股票筛选,比如ROE大于多少之类的,处理起来有点烦,今天一点一点的print调试,目前得出了以下效果,写出来给大家参考下,如果有更好方法希望给个建议,以下都是自己一个人摸着石头过河的。
代码如下:
import tushare as ts
import pandas as pd
# pd.set_option()就是pycharm输出控制显示的设置
pd.set_option('expand_frame_repr', False) # True就是可以换行显示。设置成False的时候不允许换行
pd.set_option('display.max_columns', None) # 显示所有列
# pd.set_option('display.max_rows', None) # 显示所有行
pd.set_option('colheader_justify', 'centre') # 显示居中
ts.set_token('到tushare官网注册token,财务数据至少800积分才可以调取,目前我的积分是2000')
# 初始化pro接口
pro = ts.pro_api()
df_basic_all = pro.stock_basic(exchange='', list_status='L') # 获取所有上市公司的信息为全部上市公司回测做准备
for stock_code in df_basic_all['ts_code']:
print(stock_code)
df_daily = ts.pro_bar(ts_code=stock_code, start_date='20150101', end_date='20210203', adj='qfq', freq='D') # 获取每日数据
df_daily = df_daily.drop(['pre_close', 'change', 'pct_chg', 'amount'], axis=1)
df_stockind = pro.daily_basic(ts_code=stock_code, start_date='20150101', end_date='20210203', adj='qfq', freq='D',
fields='trade_date, pe, pb, turnover_rate, volume_ratio') # 获取每日基本指标数据
df_fina = pro.fina_indicator(ts_code=stock_code, start_date='20150101') # 获取财务数据
# 将ann_date列即公告日期(财务数据公布的那一天)更名,为后面数据合并提供依据,且减少数据处理
df_fina = df_fina.rename(columns={'ann_date': 'trade_date'})
df_fina = df_fina[['trade_date', 'roe']]
# 先合并每日数据跟每日基本指标数据
df_first = pd.merge(left=df_daily, right=df_stockind, on='trade_date', how='outer')
'''因为tushare获取财务数据的格式时阶段性的,跟日k线数据进行合并需要特殊的处理,
问题1:财务数据根据trade_date合并后只有公布的那一天有数据,比如20201210公布财务数据,然后20201211那一天是NaN空值
问题2:合并时有时候财务数据公布时恰好股票是休息日,那么日k线数据是NaN空值。
解决1:使用df.fillna(method='ffill', inplace=True)函数向后面的日期填充数据,直到下一财务数据公布
解决2:填充完财务数据后删除收盘价或开盘价或最高价数据为NaN的那一行数据(即停牌或休息日),注意解决1跟解决2的顺序,不可颠倒'''
df_all = pd.merge(left=df_first, right=df_fina, on='trade_date', how='outer')
df_all.set_index('trade_date', inplace=True) # 设置索引覆盖原来的数据
df_all = df_all.sort_index(ascending=True) # 将时间顺序升序,符合时间序列
# 使用向前填充缺失的数据,就是说假如000001.sz今天20200202公布了财务数据,ROE为8.544,那么明天20200203至到下一财务数据公布日都是8.544
df_all.roe.fillna(method='ffill', inplace=True)
df_all = df_all[df_all['close'].notna()] # 删除停牌数据
print(df_all)
import tushare as ts
import pandas as pd
import time
from datetime import datetime, timedelta
# pd.set_option()就是pycharm输出控制显示的设置
pd.set_option('expand_frame_repr', False) # True就是可以换行显示。设置成False的时候不允许换行
pd.set_option('display.max_columns', None) # 显示所有列
# pd.set_option('display.max_rows', None) # 显示所有行
pd.set_option('colheader_justify', 'centre') # 显示居中
ts.set_token('到tushare官网注册token,财务数据至少800积分才可以调取,目前我的积分是2000')
# 初始化pro接口
pro = ts.pro_api()
df_basic_all = pro.stock_basic(exchange='', list_status='L') # 获取所有上市公司的信息为全部上市公司回测做准备
input_start_date = '20150101'
input_end_date = '20210203'
# 以下财务数据获取的是上一年的时间日期,之所以这样做是因为今年的1月1日在pro.fina_indicator函数里你是得不到1月1日这一天的财务数据的
input_lastyear_date = datetime.strptime(input_start_date, '%Y%m%d') - timedelta(days=365) # str转time
input_fina_start_date = datetime.strftime(input_lastyear_date, '%Y%m%d') # time转str
# print(datetime.strptime(input_start_date, '%Y%m%d') - timedelta(days=365))
for stock_code in df_basic_all['ts_code']:
print(stock_code)
# 获取每日数据
df_daily = ts.pro_bar(ts_code=stock_code, start_date=input_start_date, end_date=input_end_date, adj='qfq', freq='D')
df_daily = df_daily.drop(['pre_close', 'change', 'pct_chg', 'amount'], axis=1)
# 获取每日基本指标数据
df_stockind = pro.daily_basic(ts_code=stock_code, start_date=input_start_date, end_date=input_end_date, adj='qfq',
freq='D', fields='trade_date, pe, pb, turnover_rate, volume_ratio')
# 获取财务数据
# 假设start_date='20150101',结果将只获得2015年的财务数据,结果将导致直到2015年第一季度数据发布时,前面的日期财务数据都是NaN
df_fina = pro.fina_indicator(ts_code=stock_code, start_date=input_fina_start_date)
# print(df_fina)
# 将ann_date列即公告日期(财务数据公布的那一天)更名,为后面数据合并提供依据,且减少数据处理
df_fina = df_fina.rename(columns={'ann_date': 'trade_date'})
df_fina = df_fina[['trade_date', 'roe']]
# 先合并每日数据跟每日基本指标数据
df_first = pd.merge(left=df_daily, right=df_stockind, on='trade_date', how='outer')
'''因为tushare获取财务数据的格式时阶段性的,跟日k线数据进行合并需要特殊的处理,
问题1:财务数据根据trade_date合并后只有公布的那一天有数据,比如20201210公布财务数据,然后20201211那一天是NaN空值
问题2:合并时有时候财务数据公布时恰好股票是休息日,那么日k线数据是NaN空值。
解决1:使用df.fillna(method='ffill', inplace=True)函数向后面的日期填充数据,直到下一财务数据公布
解决2:填充完财务数据后删除收盘价或开盘价或最高价数据为NaN的那一行数据(即停牌或休息日),注意解决1跟解决2的顺序,不可颠倒'''
df_all = pd.merge(left=df_first, right=df_fina, on='trade_date', how='outer')
df_all.set_index('trade_date', inplace=True) # 设置索引覆盖原来的数据
df_all = df_all.sort_index(ascending=True) # 将时间顺序升序,符合时间序列
# 使用向前填充缺失的数据,就是说假如000001.sz今天20200202公布了财务数据,ROE为8.544,那么明天20200203至到下一财务数据公布日都是8.544
df_all.roe.fillna(method='ffill', inplace=True)
df_all = df_all[df_all['close'].notna()] # 删除停牌数据
time.sleep(1.2) # 加个休眠时间,财务数据积分不够每分钟好像只能获取80条数据,上个保险,不然等你运行半个小时后突然冒出来说你积分不够,瞬间要崩溃
print(df_all)