下载股票的历史日交易数据并存入数据库——基于tushare

  1. tushare是一个非常神奇的Python模块包,基于新浪的API,可提供并不限于股票的历史数据。
  1. 数据库选用的是sqlite3,单文件,轻量化,不需要配置。

以下是完整代码,且使用的是多线程的方式。此处提到的多线程的方法可以参考Python黑魔法,一行实现并行化这篇文章,讲的很好。

准备工作

import tushare as ts
from sqlalchemy import create_engine #注1
import sqlite3
import pandas as pd #注2
from multiprocessing.dummy import Pool as ThreadPool #注3

conn1=sqlite3.connect('Stocklist.db') #注4
engine = create_engine('sqlite:///History.db', echo = False) #注5

conn2 = sqlite3.connect('History.db')
cur2=conn2.cursor() #注6

stocklist = []
errorlist = []
alreadylist = []
cur1=conn1.cursor()
query1 = "select * from Allist" #注7
cur1.execute(query1) #注8
stocklist = cur1.fetchall() #注9
cur1.close()
conn1.close()
query2 = "select name from sqlite_master where type='table' order by name" #注10
alreadylist = pd.read_sql(query2, conn2) #注11

注1sqlalchemy是Python自带的与数据库联结的包,导入创建数据库联结的函数
注2:导入pandas包,Python上的科学计算用的包
注3:多线程
注4Stocklist.db是存放股票列表的数据库
注5:创建与sqlite数据库的联结,名字为History.db
注6:创建一个游标
注7:SQL语句。AllistStocklist.db中的表,存放股票列表的。
注8:执行SQL语句
注9:获取执行SQL查询后的结果,stocklist是tuple类型
注10:意思是获取所有表名
注11:另一种读数据库的方法,直接用pandas读取数据库,alreadylist是DataFrame类型,有代码的那一列名为name

获取数据并保存的函数

def save(stock):
    code = stock[0][:6] #注1
    if code not in list(alreadylist.name): #注2
        marketday = stock[1] #注1
        i= 0
        try:
            startday = pd.Timestamp(marketday)
            df = ts.get_h_data(code, start=str(startday)[:10], retry_count = 5)
            df = df.sort_index(ascending=True) #注4
            ma_list = [5,10,20,60]
            for ma in ma_list:
                df['MA_' + str(ma)] = pd.rolling_mean(df.close, ma) #注5
            df.to_sql(code, engine, if_exists='append') #注6
        except:
            errorlist.append(stock[0])
    print errorless  #注7

该函数的思路是这样的:

  1. 利用tushare的get_h_data函数获取数据。
  2. 由于会出现如网络错误或其他错误,导致该程序重新执行,所以必须验证以防止添加重复数据。

注1stock取自上文的stocklist, 由于是tuple,含有两列,第一列取做code,第二列取作marketday,后者是该股票的上市日。
注2:上文中用SQL语句查询出了一个DataFramealreadlist,包含了History.db数据库中已有的表名,用alreadlist.name取出,namealreadlist的列名。
注3pd.Timestamp可以把文本类型的日期转成时间戳类型的,这样就可以进行时间的运算,例如通过pd.Timedelta。然后就照startdayenday的写法,三年一个跨度拉取数据。
注4:数据拉过来是以date为索引的,但是还需要重新排序,因而这样写以升序排列。
注5:没有移动均线的数据,因而手动计算。pandas直接自带移动平均数的计算函数pd.rolling_mean,两个参数分别是计算对象计算参数
注6:写入数据库,if_exists='append'意为追加的形式。
注7:用try...except的方式来避免异常中断,错误的股票写入errorlist,最后程序结束时打印出来。

多线程处理

pool = ThreadPool(4)
try:
    pool.map(save, stocklist)
except:
    pool.map(save, stocklist)
f = open('Notsaved.txt', 'w')
print >> f, errorlist
f.close()
pool.close()
pool.join()    

注:pool.map(save, stocklist)意思就是从stocklist中取每一个元素送入save的函数中运行。最后把上段代码的errorlist打印成文件。

每日的更新

import tushare as ts
from sqlalchemy import create_engine
import sqlite3
import pandas as pd
from datetime import datetime as dt

con = sqlite3.connect('History.db')
query1 = "select name from sqlite_master where type='table' order by name"
stocklist = pd.read_sql(query1, con).name

engine = create_engine('sqlite:///History.db', echo = False)

updatestock = []
for stock in stocklist:
    query2 = "select * from '%s' order by date" %stock
    df = pd.read_sql(query2, con)
    df = df.set_index('date')
    if dt.now().weekday() == 5: #注1
        today = str(pd.Timestamp(dt.now())-pd.Timedelta(days = 1))[:10]  #注2
    elif dt.now().weekday() == 6:
        today = str(pd.Timestamp(dt.now())-pd.Timedelta(days = 2))[:10] 
    else:
        today = str(pd.Timestamp(dt.now()))[:10]
    if today != df.ix[-1].name[:10]:
        try:
            df = ts.get_h_data(stock, start = df.ix[-1].name[:10], retry_count = 5)
            df.to_sql(stock, engine, if_exists='append')
            updatestock.append(stock)
        except:
            continue
        
f = open('updated.txt','w')
print >>f, updatestock
f.close()

注1dt.now()是指今天,dt.now().weekday是返回今天是星期几,5代表星期六,6代表星期天。
注2today指的是最近的一个交易日,df.ix[-1].name是数据库中最新的一天,if today != df.ix[-1].name[:10]意思就是,如果数据库最新的一天不是最近一个交易日,则要开始更新数据。

清洗数据库

import pandas as pd
import sqlite3
from multiprocessing.dummy import Pool as ThreadPool

con = sqlite3.connect('History.db')
query1 = "select name from sqlite_master where type='table' order by name"
stocklist = pd.read_sql(query1, con).name

delstock = []
f = open('Deleted.txt', 'w')
for stock in stocklist:
    query2 = "select * from '%s' order by date" %stock
    df = pd.read_sql(query2, con)
    cur=con.cursor()
    query4 = "delete from '%s' where rowid not in(select max(rowid) from '%s' group by date)" %(stock, stock) #注1
    cur.execute(query4)
    con.commit()

con.close()
print >> f, delstock
f.close()

注1:这句SQL语句的意思是以date分组,删除重复的行
注2:最后执行cur.execute(...)完后要con.commit()提交,才能有效

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容