这是奔跑的键盘侠的第112篇文章
依旧,先贴一下目录:
├── README
├── MyQuant_v1 #量化分析程序目录
├── __init__.py
├── data #数据处理目录
│ ├── __init__.py
│ ├── basic_crawler.py# 爬取股票基础信息存入MongoDB数据库.
│ └── data_crawler.py #爬取指数、股票数据
├──util # 公用程序
│ ├── __init__.py
│ ├── stock_util.py#获取股票交易日期,所有股票代码
│ └── database.py #链接数据库
├── backtest #回测
│ ├── __init__.py
│ └── _backtest_ #计划写一下回测走势图
├── factor #因子
│ ├── __init__.py
│ └──_ factor_.py #不准备开发
├── strategy #策略
│ ├── __init__.py
│ └── _strategy_ #计划简单写个,主要用于回测
├── trading #交易
│ ├── __init__.py
│ └── _trading_ #不准备开发
└── log #日志目录
├── __init__.py
├── backtest.log #不准备开发
└── transactions.log#不准备开发
今天依旧没有什么硬干货,延伸一下前面讲过的2个代码的实操。
1
完整的爬取数据
data_crawler.py虽然早就写出来了,但总要完整的爬取一遍才敢投入应用中,果然,随便一爬就有问题,速度贼慢,龟速……
于是需要一个改进方法:使用db.daily.createIndex({code:1,date:1})建立数据集索引,还有前复权、后复权的数据集都建立索引,爬取数据的速度就会快非常多,至于为何,暂时还没得空去研究
先用起来再说
2
basic_crawler.py重写
《Python——量化分析常用命令介绍(五)》中贴的basic_crawler.py代码一跑起来发现很多问题,最关键的一点是数据类型不一致不断抛出异常的问题,至于为啥,先一掠而过……翻新完的代码如下:
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
# @Time : 2019-07-31 21:12
# @Author : Ed Frey
# @File : basic_crawler.py.py
# @Software: PyCharm
from pymongo import UpdateOne, DESCENDING
from util.database import DB_CONN
from util.stock_util import get_trading_dates
import tushare as ts
from datetime import datetime, timedelta
import numpy
"""
to get basic data from tushare and save it to MongoDB.
"""
class BasicCrawler:
def __init__(self):
self.basic = DB_CONN['basic']
self.daily = DB_CONN['daily']
def crawl_basic(self, begin_date=None, end_date=None):
'''
to get the basic infomation of stocks on "date"
:param begin_date:
:param end_date:
:return:
'''
if begin_date is None:
current_date = datetime.now().strftime('%Y-%m-%d')
begin_date = self.daily.find_one(
{'code': '000001', 'index': True, 'date': {'$lt': current_date}},
sort=[('date', DESCENDING)],
projection={'date': True})['date']
dates = get_trading_dates(begin_date=begin_date, end_date=end_date)
for date in dates:
try:
df_basic = ts.get_stock_basics(date)
update_requests = []
for index in df_basic.index:
doc = dict(df_basic.loc[index])
doc['code'] = index
doc['date'] = date
outstanding = doc['outstanding']
if outstanding == 0:
continue
# 解决流通股本和总股本单位不一致的情况,有些单位是股,目前a股股本规模的最大的工商银行,是3564亿股,最小的德方纳米4274万股
if outstanding > 4000:
outstanding *= 1e4
else:
outstanding *= 1e8
doc['outstanding'] = outstanding
totals = doc['totals']
if totals > 4000:
totals *= 1e4
else:
totals *= 1e8
doc['totals'] = totals
for key in doc:
field_type = type(doc[key])
if type(doc[key]) == numpy.float64:
doc[key] = float(doc[key])
elif field_type == numpy.int64:
doc[key] = int(doc[key])
# format"20180101'turned to format"2018-01-01'
timeToMarket = doc['timeToMarket']
doc['timeToMarket'] = datetime.strptime(
str(timeToMarket), '%Y%m%d').strftime('%Y-%m-%d')
update_requests.append(
UpdateOne(
{'code': doc['code'], 'date': doc['date']},
{'$set': doc},
upsert=True
))
if len(update_requests) > 0:
update_result = self.basic.bulk_write(update_requests, ordered=False)
print('更新基本数据, 日期:%s, 插入:%4d,更新:%4d' %
(date, update_result.upserted_count, update_result.modified_count),
flush=True)
except:
print('获取基本信息出错,日期 %s' % date, flush=True)
if __name__ == '__main__':
bc = BasicCrawler()
bc.crawl_basic('2018-01-01', '2019-07-28')
然后再试着跑一下,大功告成 运行结果就不贴了
同样,也要使用建立索引命令,加速代码运行速度。后面可能雷同问题,都可以用这招解决,记住了。
爬取这几个数据集(时间段1年半),大小已经到0.57G了,总耗时粗略估计在1.5-2小时左右。如果要下载更多年份的数据,估计3G收不住,我这边资源有限就一切从简了。
数据的准确性尤其特别重要,如果基础数据错误了,那后面的一切都有可能白费,所以……不能只依靠第三方数据,必须要自己动手整理自己的数据,不断发现问题然后修正到无瑕,最后才可以拿来用。