前文介绍了从BaoStock下载股票代码,本文记录利用这些股票代码下载股票日线数据的过程。
主要代码分析
参考前文,新建源文件,新文件命名为data_center_v2.py,全部内容见文末,v2比v1新增了函数create_data:
def create_data(stock_codes, from_date='1990-12-19', to_date=datetime.date.today().strftime('%Y-%m-%d'), adjustflag='2'):
该函数用于下载指定日期内,指定股票的日线数据。其中:
– 参数stock_codes为待下载数据的股票代码
– 参数from_date为日线开始日期,默认为1990-12-19
– 参数to_date为日线结束日期,默认为函数调用当日
– 参数adjustflag为复权选项,为1时表示后复权,为2时表示前复权,为3时表示不复权,默认为前复权
– 返回值为空
for code in stock_codes:
下载股票循环。
bs.login()
登录BaoStock,每次从BaoStock查询数据前,都需要先登录。
out_df = bs.query_history_k_data_plus(code, g_baostock_data_fields, start_date=from_date, end_date=to_date,
frequency='d', adjustflag=adjustflag).get_data()
调用BaoStock的query_history_k_data_plus函数,该函数官方文档说明如下:
方法说明:通过API接口获取A股历史交易数据,可以通过参数设置获取日k线、周k线、月k线,以及5分钟、15分钟、30分钟和60分钟k线数据,适合搭配均线数据进行选股和分析。
返回类型:pandas的DataFrame类型。
能获取1990-12-19至当前时间的数据;
可查询不复权、前复权、后复权数据。
这里我们定义了全局变量
“`g_baostock_data_fields“`来记录需要下载的日线数据字段:
g_baostock_data_fields = 'date,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,peTTM,pbMRQ, psTTM,pcfNcfTTM,isST'
更多说明参见可参考官方链接。
将下载数据转为DataFrame。同query_all_stock函数一样,query_history_k_data_plus的返回值类型也是
bs.logout()
注销BaoStock登录。
if out_df.shape[0]:
out_df = out_df[(out_df['volume'] != '0') & (out_df['volume'] != '')]
剔除停盘数据并打印最终下载数据结果。在回测过程中,通常不需要停盘数据对回测造成干扰,这里选择直接将这些数据删除。当out_df不为空时,筛选出成交量为非’0’或者空字符”的行,即剔除了停盘数据。这里需要注意的是,从BaoStock下载的日线数据元素类型均为object,因此这里要使用str类型’0’作判断,而非整形0。
以603016新宏泰为例,该股票在2017-12-21至2017-12-28停盘,我们截取2017-12-20至2017-12-29之间的数据打印,只选择打印列date、open、close、volume
print(out_df[(out_df['date'] >= '2017-12-20') & (out_df['date'] <= '2017-12-29')][['date', 'open', 'close', 'volume']]) # test code
打印结果为:
date open close volume
360 2017-12-20 37.2596538300 37.0382545500 438502
367 2017-12-29 33.3390415800 33.3390415800 101000
如果不剔除停盘数据,打印结果为:
date open close volume
360 2017-12-20 37.2596538300 37.0382545500 438502
361 2017-12-21 37.0382545500 37.0382545500 0
362 2017-12-22 37.0382545500 37.0382545500 0
363 2017-12-25 37.0382545500 37.0382545500 0
364 2017-12-26 37.0382545500 37.0382545500 0
365 2017-12-27 37.0382545500 37.0382545500 0
366 2017-12-28 37.0382545500 37.0382545500 0
367 2017-12-29 33.3390415800 33.3390415800 101000
可以看到,2017-12-21至2017-12-28停盘期间volume的值均为’0’(也有时空字符”的情况),open、close值与停盘前相同(low、high与停盘前也相同)。在后续使用数据时,如果不剔除停盘数据,这些点需要注意。
小结
至此,程序能够打印下载的所有数据。data_center_v2.py是一个临时版本,不需要等待程序都执行完毕,只要确保程序能正常运行即可。这里只对数据进行了打印,没有存储数据,后续会使用下载的数据计算扩展指标,改为多进程,最后再将数据存入MySQL。
data_center_v2.py的全部代码如下:
import baostock as bs
import datetime
import sys
# BaoStock日线数据字段
g_baostock_data_fields = 'date,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,peTTM,pbMRQ, psTTM,pcfNcfTTM,isST'
def get_stock_codes(date=None):
"""
获取指定日期的A股代码列表
若参数date为空,则返回最近1个交易日的A股代码列表
若参数date不为空,且为交易日,则返回date当日的A股代码列表
若参数date不为空,但不为交易日,则打印提示非交易日信息,程序退出
:param date: 日期
:return: A股代码的列表
"""
# 登录baostock
bs.login()
# 从BaoStock查询股票数据
stock_df = bs.query_all_stock(date).get_data()
# 如果获取数据长度为0,表示日期date非交易日
if 0 == len(stock_df):
# 如果设置了参数date,则打印信息提示date为非交易日
if date is not None:
print('当前选择日期为非交易日或尚无交易数据,请设置date为历史某交易日日期')
sys.exit(0)
# 未设置参数date,则向历史查找最近的交易日,当获取股票数据长度非0时,即找到最近交易日
delta = 1
while 0 == len(stock_df):
stock_df = bs.query_all_stock(datetime.date.today() - datetime.timedelta(days=delta)).get_data()
delta += 1
# 注销登录
bs.logout()
# 筛选股票数据,上证和深证股票代码在sh.600000与sz.39900之间
stock_df = stock_df[(stock_df['code'] >= 'sh.600000') & (stock_df['code'] < 'sz.399000')]
# 返回股票列表
return stock_df['code'].tolist()
def create_data(stock_codes, from_date='1990-12-19', to_date=datetime.date.today().strftime('%Y-%m-%d'), adjustflag='2'):
"""
下载指定日期内,指定股票的日线数据
:param stock_codes: 待下载数据的股票代码
:param from_date: 日线开始日期
:param to_date: 日线结束日期
:param adjustflag: 复权选项 1:后复权 2:前复权 3:不复权 默认为前复权
:return: None
"""
# 下载股票循环
for code in stock_codes:
print('正在下载{}...'.format(code))
# 登录BaoStock
bs.login()
# 下载日线数据
out_df = bs.query_history_k_data_plus(code, g_baostock_data_fields, start_date=from_date, end_date=to_date,
frequency='d', adjustflag=adjustflag).get_data()
# 注销登录
bs.logout()
# 剔除停盘数据
if out_df.shape[0]:
out_df = out_df[(out_df['volume'] != '0') & (out_df['volume'] != '')]
print(out_df)
if __name__ == '__main__':
stock_codes = get_stock_codes()
create_data(stock_codes)
博客内容只用于交流学习,不构成投资建议,盈亏自负!
欢迎大家转发、留言。已建微信群用于学习交流,群1已满,群2已创建,感兴趣的读者请扫码加微信!
如果认为博客对您有帮助,可以扫码进行捐赠,感谢!
微信二维码 | 微信捐赠二维码 |
---|---|
![]() |
![]() |
“后续…….改为多进程,最后再将数据存入MySQL”,谢谢!期待中!
嗯嗯,后面会发出来,莫急莫急
# 剔除停盘数据
if out_df.shape[0]:
out_df = out_df[(out_df[‘volume’] != ‘0’) & (out_df[‘volume’] != ”)]
应该修改为:
if out_df.shape[0]:
out_df = out_df[(out_df[‘volume’] != ‘0’) & (out_df[‘turn’] != ”)]
Good blog you have got here.. It’s difficult to find high-quality writing
like yours these days. I really appreciate individuals like you!
Take care!!
Hmm it seems like your blog ate my first comment (it was super long) so I guess I’ll just
sum it up what I wrote and say, I’m thoroughly enjoying your blog.
I too am an aspiring blog writer but I’m still new to everything.
Do you have any recommendations for rookie blog writers?
I’d definitely appreciate it.
我用的wordpress
Wow, incredible blog layout! How long have you been blogging
for? you make blogging look easy. The overall look
of your website is great, let alone the content!