获取金融数据量化交易必不可少的步骤,目前有许多在线的金融数据库,但是每次使用时都要到云端获取数据效率太低,因此本文将结合tushare的api与python手把手教你搭建本地金融数据库。
tushare是一个金融大数据开放社区 ,免费提供各类金融数据和区块链数据。python也是各类领域中数据处理的常用语言。
首先需要安装python,安装了的同学可以跳过。
由于python2不再维护,这里我们需要安装python3。可以直接下载Anaconda来安装python,它会帮你装上各种常用的库,免去很多麻烦。
tushare提供了许多数据接口,但是需要注册后获取token才能调用接口。
可以通过以下链接注册,帮我赚个积分:https://tushare.pro/register?reg=311239
接口需要在python中安装tushare模块,在Anaconda prompt中输入“pip install tushare”后等待安装完成即可。
为了把数据存在本地的数据库,我们选用轻量化的sqlite3作为我们使用的数据库,Anaconda已经帮我们集成好了,可以直接调用。sqlite3不用提前安装,它会以一个“*.db”的格式保存在指定的目录下,方便迁移。
来到最关键的地方了,话不多说,我们直接开始讲代码。
首先导入需要用到的库,库的说明写在注释中了。
import tushare as ts # tushare
import pandas as pd # 数据分析库,集成了许多常用的操作,比如时间序列分析
import matplotlib.pyplot as plt # 绘图
import sqlite3 # 轻量化的sql数据库
为了下载数据,首先需要获得所有股票的代码,tushare的.stock_basic会返回所有的股票代码与上市时间。token需要注册才可以获得>>>性感TOKEN点击就送。
pro = ts.pro_api('0441c1c59f7ff1c2ad640c8b345a69ad34e1aeea864004a10046b2ae') # 初始化token
df_hsConst = pro.stock_basic(exchange='', list_status='L') # 获取所有股票的代码
df_hsConst.index = df_hsConst.ts_code # 把股票的代码作为dataframe的index
df_hsConst = df_hsConst.sort_index(ascending=True) # 按顺序重排一下,以上两步不是必须的
通过python提供的sqlite的api接口与数据库建立连接,它会保存在你当前python脚本的工作目录下面。
如果在执行sqlite3.connect时没有数据库,则代码会自动创建一个数据库文件。
adj = 'hfq'
sqlName = "stockData" +adj+".db"
conn=sqlite3.connect(sqlName) # 如果路径里面没有这个数据库,会自动创建
c=conn.cursor()
tushare提供了pro_bar方法来获取股票数据,使用方法如下:
df_tmpStock = ts.pro_bar(ts_code=ts_code, adj=adj, start_date=start_date, end_date=end_date)
其中ts_code指定了股票代码,adj可以设置是前复权、后复权还是不复权数据,start_date和end_date指定了起始和结束时间。
由于tushare的数据在基础积分下每分钟内最多调取200次,每次4000条数据,因此在数据获取过程中需要一些额外的处理。这里将简单讲解思路,具体代码最后会直接在文末给出。
首先读取df_hsConst中股票的上市时间,如果距离当前时间超过4000,则分批读取。如果数据库中已经有这个股票以前的数据了,则我们只要下未下载的数据即可。通过这样的操作,每天收盘后,只要再运行这个脚本就可以把新的数据加入到数据库中了(但是得注意复权的选项,前复权就不能这么做了)。
我们这里先用轮询的方式一个个查询数据,这样效率最低但是直观。如果想提高效率可以用并行的方式来查询和储存。
话不多说,最后的代码看这里。
"""
Created on Sun Oct 13 21:26:39 2019
@author: DJ666
# 数据下载脚本
"""
import tushare as ts
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import sqlite3
def try_get_data(ts_code,start_date,end_date,adj='None',tryCount=0):
try:
#df_tmpStock = pro.daily(ts_code=ts_code, start_date=start_date, end_date=end_date)
df_tmpStock = ts.pro_bar(ts_code=ts_code, adj=adj, start_date=start_date, end_date=end_date)
except Exception as e:
print(e)
tryCount = tryCount +1
if tryCount>100:
return TooManyTry
df_tmpStock = try_get_data(ts_code,start_date,end_date,tryCount)
return df_tmpStock
# --------TOKEN设置--------
pro = ts.pro_api('你的TOKEN') # 注册下就能拿到token,https://tushare.pro/register?reg=311239
# --------获取所有的股票列表与上市时间--------
df_hsConst = pro.stock_basic(exchange='', list_status='L')
df_hsConst.index = df_hsConst.ts_code
df_hsConst = df_hsConst.sort_index(ascending=True) # 重新排列方便查看
# --------创建数据库--------
adj = 'hfq'
sqlName = "stockData" +adj+".db"
conn=sqlite3.connect(sqlName)#如果路径里面没有这个数据库,会自动创建
c=conn.cursor()
# --------自动下载--------
count = 0
for ii in df_hsConst.index:
count = count + 1
print('%s, remain: %2.3f%%' % (ii, 100*count/len(df_hsConst.index)))
# 判断数据库中当前的股票数据表是否存在,如果存在则更新数据库中最后日期到当前日期的数据,否则添加整个股票数据表
c.execute("select * from sqlite_master where type = 'table' and name = '" + ii + "'")
if len(c.fetchall()):
isTable = True
c.execute("SELECT MAX(trade_date) FROM '" + ii + "'")
tmp = c.fetchall()
startDate = pd.to_datetime(tmp[0][0])+pd.Timedelta(days=1)
nowDate = pd.to_datetime(pd.datetime.now())
else:
isTable = False
startDate = df_hsConst.loc[ii].list_date
startDate = pd.to_datetime(startDate)
nowDate = pd.to_datetime(pd.datetime.now())
tmpDf = nowDate-startDate
quitFlag = False
endDate = nowDate
# 循环读取
if tmpDf.days>=0:
newLog = False
while (True):
if tmpDf.days>3500: # 一次获取4000条的限制
print('Too many data, need loop, loopping...')
endDate = startDate+pd.Timedelta(days=3500) # 一次获取4000条的限制
if endDate >= nowDate:
endDate = nowDate
quitFlag = True
else:
quitFlag = True
startDateStr = pd.to_datetime(startDate).strftime('%Y%m%d')
endDateStr = pd.to_datetime(endDate).strftime('%Y%m%d')
df_tmpStock = try_get_data(ts_code=ii, start_date=startDateStr,
end_date=endDateStr,adj=adj)
if newLog == False:
df_Stock = df_tmpStock
newLog = True # 第一次读取数据则创建该变量
else: # 否则append到dataframe里
df_Stock = df_Stock.append(df_tmpStock,ignore_index=True)
if quitFlag == True:
break
startDate = endDate+pd.Timedelta(days=1)
endDate = nowDate
tmpDf = nowDate-startDate
df_Stock.index = pd.to_datetime(df_Stock['trade_date'])
df_Stock.index = df_Stock.index.strftime('%Y-%m-%d')
df_Stock = df_Stock.sort_index(ascending=True)
print('Data Length: '+str(df_Stock.shape[0]))
if isTable == True and not df_Stock.empty:
pd.io.sql.to_sql(df_Stock,name=ii,
con=conn,if_exists='append')
df_Stock.plot(y="close");
elif not df_Stock.empty:
pd.io.sql.to_sql(df_Stock,name=ii,
con=conn,if_exists='replace')
df_Stock.plot(y="close");
else:
print('Suspension. Skipped.')
else:
print(ii + ' Newest Data.')
plt.pause(0.000001)
# --------完成后关闭数据库--------
conn.close()
后续会探讨关于指数的数据分析。