美文网首页我爱编程
股票量化分析入门——抓取数据

股票量化分析入门——抓取数据

作者: coolwind | 来源:发表于2018-01-03 00:30 被阅读547次

    目标

    我的目标是抓取所有的 A 股所有股票按日的历史交易数据。将交易数据存储到本地数据库,一遍后续的数据分析之用。

    材料

    1. Python 用与编写相关的功能
    2. pip 用于安装所需的包,如:Pandas、lxml、sqlalchemy、Tushare
    3. Tushare 用于抓取数据
    4. Mysql 用户存储数据

    尝试

    通过对 Tushare 的试用,掌握的 Tushare 抓取数据的要点。

    时间需要分割

    get_h_data函数默认抓取最近三年的数据,如果要抓取更早之前的数据,可以指定相应的日期。但是如果时间指定的太长,则容易产生超时失败。所以如果要抓取一只股票从1992年到现在的所有数据,在需要逐年获取数据,并追加到同一张表中。使用如下的代码就能轻松完成年份分割的功能。

    def getInteralArray(start,end):
         startDate = time.strptime(start,'%Y-%m-%d')
         startDate_ = datetime.datetime(*startDate[:3])
         endDate = time.strptime(end,'%Y-%m-%d')
         endDate_ = datetime.datetime(*endDate[:3])
         datelYear = endDate_.year - startDate_.year
         internalArray = [ startDate_.year + x for x in range(0,datelYear+1)]
         internalArray_ = []
         for i in range(0,len(internalArray)):
             if i == 0:
                 internalArray_.append(start)
             else:
                 internalArray_.append("%s-%s-%s"%(internalArray[i],'01','01'))
             if i == len(internalArray)-1:
                 internalArray_.append(end)
             else:
                 internalArray_.append("%s-%s-%s"%(internalArray[i],12,31))
    
         return internalArray_
    

    以上代码,如果调用参数为‘2015-05-12’,‘2017-12-23’。则返回值为['2015-05-12',2015-12-31','2016-01-01','2016-12-31','2017-01-01','2017-12-23']。其中,第一第二个时间组成一个分割对,如此类推,三和四 ,五和六个组成一个。可以直接用于get_h_data的调用。

    数据存储

    Tushare 抓取数据之后,返回一个dataframe对象。利用对象的to_sql方法,即可将数据存入数据库。to_sql方法,接受的参数有:数据库链接、表名、写入方式(如果表已经存在,是直接失败、覆盖 或 追加)、索引名称。

    思路

    基于以上的尝试,得到了以下的一个思路。

    1.获取所有的股票代码及对应的上市时期列表
    2.循环获取每支股票的历史数据
    3.获取单只股票的历史数据时,从上市日期到现在,把时间按年划分。按年获取股票历史数据。
    4.获取的数据,直接存入数据库中。

    上述的思路中,股票的代码以及对应的上市日期的列表可以借由get_stock_basics()方法获取。

    在返回值中 timeToMarket 字段是代表对应股票的上市时间。发现10多只股票的上市时间是0。这个问题后续在做补充,这部分数据在获取数据是先排除。

    绕坑方法

    建表错误

    在使用to_sql方法存储数据时,偶尔发生使用了索引的名称当做字段名称来创建数据表。这样就导致后续的股票数据无法存储的情况。为此,我是提前把所有的表结构全部传建好,这样就不会发生这个异常了。

    请求失败

    在使用get_h_data方法获取数据时,经常会发生网络的异常,有:服务不可用、超市、服务找不到等。原因应该是访问频繁被服务端暂时封掉了。根据几次尝试。发生类似状况的时候,等待10分钟,然后再尝试,基本就能解决了。在获取数据的时候应该要写一个重试的逻辑。我写的逻辑是发生异常就等待10分钟再尝试。如果继续异常,则增加5分钟的等待时间,一共重试三次。目前根据日志,还没有等待10分钟之后重试,继续失败的情况。

    频繁发生请求失败

    每次请求最好间隔6秒钟。如果没有这个间隔,请求失败的概率会大大的上升。经过尝试每次请求间隔6秒钟是比较OK的。

    日志

    获取的过程一定要记录完整的日志,这样方便在发生异常时,对个别年份的数据进行重新获取。

    主要代码

    def initData():
        #前12个股票的上市时间是“0”所以从第13个开始获取
        start = 13
        count = 4000
        logger.info("Begin fetch init data stock start from %s fetch %s items"%(start,count))
        sql = "select * from stockBasics order by timeToMarket limit %s,%s"%(start,count)
        logger.info("The SQL get Stocks info is:"+sql)
        #从数据库中选取所有上市的股票信息
        result = engine.execute(sql)
        count = 0
        for row in result:
            timeStr = str(row['timeToMarket'])
            startDateStr =("%s-%s-%s"%(timeStr[0:4],timeStr[4:6],timeStr[6:8]))
            logger.info("fetch the[[[%s]]] stock:%s from %s To %s"%(start+count,row['code'],startDateStr,'2017-12-12'))
            fetchStockData(row['code'],'s'+row['code'],startDateStr,'2017-12-12')
            count += 1
        loger.info(">>>>>>>>>>>>get stock data SUCCESS<<<<<<<<<<<<<<<")
    
    def fetchStockData(code,tableName,startDateStr,endDateStr):
        global _callCount
        internalArray_ = getInteralArray(startDateStr,endDateStr)
        for i in range(0,len(internalArray_),2):
            _callCount = 0
            doFetchStockData(code,tableName,internalArray_[i],internalArray_[i+1],engine)
    
    def doFetchStockData(code,tableName,startDateStr,endDateStr,engine):
        global _callCount
        flag = False
        while _callCount < 4 and flag == False:
            _callCount = _callCount + 1
            #_callCount大于一,说明上次请求失败了,所以本次请求必须等待一定的时长
            if _callCount > 1 :
                sleepScd = 300 + 300 * (_callCount-1)
                logger.info("RETRY AND SLEEP %s seconds"%(str(sleepScd)))
                time.sleep(sleepScd)
            logger.info("Call %s times"%(_callCount))
            try:
                now = datetime.datetime.now()
                logger.info("Fetch Stock data start: %s end: %s"%(startDateStr,endDateStr))
                #每次请求等待6秒
                time.sleep(6)
                df=ts.get_h_data(code,start=startDateStr,end=endDateStr,index=False,pause=3)
                logger.info("SUCCESS fetch Stock data start: %s end: %s"%(startDateStr,endDateStr))
                df.to_sql(tableName,engine,if_exists='append')
                flag = True
                logger.info("SECCESS save data to database!!")
            except Exception as err:
                logger.warning("EXCEPTION happen err ",exc_info=True)
                if _callCount == 4:
                    sys.exit(0)
    

    相关文章

      网友评论

        本文标题:股票量化分析入门——抓取数据

        本文链接:https://www.haomeiwen.com/subject/bxoiwxtx.html