上一节介绍了数据获到的三种方式,从本节开始,选用baostock工具对后续操作。
本文继续作数据准备,具体介绍数据本地化的CSV
文件格式。
A股数据量比较大,需要进行筛选并分类保存。
基本思想
将采集下来的数据保存本地磁盘(数据库),存放的空间要足够,按分类存放,K线历史数据,本文以日为周期作说明,如果涉及到分钟,可以自行修改。第一次是执行是通创建的方式,后续每日采用追加的方式。为了方便说明,采用沪深300,300支股票数据进行讲解,日期从2020-1-1开始,在实际建模中,这些数据是不够的。
先获取当天交易的股票列表,并按列表遍历所有股票,剔除相关条件,比如ST,科创板,交易日小于200天等条件。
本地化 CSV
股票列表
获取股票列表
lg = bs.login()
# 获取上证50成分股 在实际应用中选择所有列表 bs.query_all_stock()
rs = bs.query_sz50_stocks()
stocks= rs.get_data()['code'].to_list()
bs.logout()
核心代码如下:
import gc
import time
lg = bs.login()
i=0
for code in stocks:
print(code)
rs = bs.query_history_k_data_plus(code,
"date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST",
start_date='2020-01-01', end_date='2023-3-1', #实际应用开始时间选2000-1-1 或更早
frequency="d", adjustflag="1")
df=rs.get_data();
df.to_csv("./data/daily/{0}.csv".format(code), index=False)
i=i+1
if i%100==0 :
gc.collect()
time.sleep(2)
bs.logout()
上述代码,有几个坑需要注意的,由于实际应用时采集所有股票,执行时间比较久,同时电脑的内存的要求,所以清空内存,代码中的gc.collect()
是其中的一个方法,另也要让电脑休息一下,sleep(2) 暂停 2 秒。
有小伙伴,会想为什么不用多进程,其实 baostock 是不支持多进程的。
完整代码如下:
首次执行
在执行之前,需要建立一个 data\daily 的目录。
# 第一次执行
import baostock as bs
import pandas as pd
import gc
import time
bs.login()
stock_df = bs.query_all_stock().get_data()
# 筛选股票数据,上证和深证股票代码在sh.600000与sz.39900之间
stock_df = stock_df[(stock_df['code'] >= 'sh.600000') & (stock_df['code'] < 'sz.399000')]
bs.logout()
stocks=stock_df['code'].to_list()
lg = bs.login()
i=0
for code in stocks:
rs = bs.query_history_k_data_plus(code,
"date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST",
start_date='2020-01-01', end_date='2023-3-1', #实际应用开始时间选2000-1-1 或更早
frequency="d", adjustflag="1")
df=rs.get_data()
# 剔除停盘数据
if df.shape[0]:
df = df[(df['volume'] != '0') & (df['volume'] != '')]
# 如果数据为空,则不创建
if not df.shape[0]:
continue
# 删除重复数据
df.drop_duplicates(['date'], inplace=True)
# 日线数据少于250,则不创建
if df.shape[0] < 250:
continue
# 将数值数据转为float型,便于后续处理
convert_list = ['open', 'high', 'low', 'close', 'preclose', 'volume', 'amount', 'turn', 'pctChg']
df[convert_list] = df[convert_list].astype(float)
df.to_csv("./data/daily/{0}.csv".format(code), index=False)
i=i+1
if i%100==0 :
gc.collect()
print('已完成',i)
time.sleep(2)
bs.logout()
日常执行
平时每个交易日,在17:30之后执行一次。(baostock 一般情况在17:30 时完成当天历史的数据更新,分时周期要到22:00左右)
# 日常执行
import baostock as bs
import pandas as pd
import gc
import time
todate=datetime.date.today().strftime('%Y-%m-%d')
bs.login()
stock_df = bs.query_all_stock().get_data()
# 筛选股票数据,上证和深证股票代码在sh.600000与sz.39900之间
stock_df = stock_df[(stock_df['code'] >= 'sh.600000') & (stock_df['code'] < 'sz.399000')]
bs.logout()
stocks=stock_df['code'].to_list()
lg = bs.login()
i=0
for code in stocks:
rs = bs.query_history_k_data_plus(code,
"date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST",
start_date=todate, end_date=todate, #选择当天
frequency="d", adjustflag="1")
df=rs.get_data()
# 剔除停盘数据
if df.shape[0]:
df = df[(df['volume'] != '0') & (df['volume'] != '')]
# 如果数据为空,则不创建
if not df.shape[0]:
continue
# 将数值数据转为float型,便于后续处理
convert_list = ['open', 'high', 'low', 'close', 'preclose', 'volume', 'amount', 'turn', 'pctChg']
df[convert_list] = df[convert_list].astype(float)
df.to_csv("./data/daily/{0}.csv".format(code), mode='a', index=False, header=False)
i=i+1
if i%500==0 :
gc.collect()
print('已完成',i)
time.sleep(2)
bs.logout()
不难发现 首次执行和日常执行 有大量共同的地方,大伙可以把他打包成函数,方便调用。
至此完整的流程就到这里,上述代码存在一些小问题,需要优化,日常执行时不小心多执行一次,或有一天忘记执行了,这会导致多添加了数据,或少添加数据,这里向大家提供一下思路,在执行日常操作时,执行bs.query_history_k_data_plus() 如果没有数据,则说明当天不是交易日,日期向前一天;在添加数据时,先检查数据表(csv) 的最后一次记录的日期与 采集到的数据是不是同一天,如果是同一天就不现追加。
总结
通过本地化的数据表形式保存数据,这样大大方便以后数据的操作。为了更高效的操作数据,下一节介绍数据库方式存放以上数据,基本的思路是一样的,只是存储方式不一样而已。