这是奔跑的键盘侠的第115篇文章
依旧,先贴一下目录:
├── README
├── MyQuant_v1 #量化分析程序目录
├── __init__.py
├── data #数据处理目录
│ ├── __init__.py
│ ├── basic_crawler.py# 爬取股票基础信息存入MongoDB数据库.
│ ├── data_crawler.py #爬取指数、股票数据
│ └── data_module.py #从数据集中获取股票数据
├──util # 公用程序
│ ├── __init__.py
│ ├── stock_util.py#获取股票交易日期、前一交易日日期、股票代码
│ └── database.py #链接数据库
├── backtest #回测
│ ├── __init__.py
│ └── _backtest_ #计划写一下回测走势图
├── factor #因子
│ ├── __init__.py
│ └── pe_factor.py#计算各股票的止盈率,用于后面的股票池策略
├── strategy #策略
│ ├── __init__.py │
└── _strategy_ #计划简单写个,主要用于回测
├── trading #交易
│ ├── __init__.py
│ └── _trading_ #不准备开发
└── log #日志目录
├── __init__.py
├── backtest.log #不准备开发
└── transactions.log#不准备开发
今天内容不多,也不复杂。首先,之前写的stock_util补充一个获取指定日期前某个交易日期的函数,毕竟后期写到买卖点指标的时候,难免要用到前后两个交易日指标值的计算。接着,data包中再新增一个从数据集中提取数据的模块。
1
更新后的stock_util.py
这个模块,修改完之后就是3个函数了:获取交易日、获取某日期的前一交易日、获取某日所有股票代码。
其中get_trading_date_before(date,days)是新加的,而get_all_codes(date)函数是进行了改进,更简洁明了。
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
# @Time : 2019-07-13 18:19
# @Author : Ed Frey
# @File : stock_util.py
# @Software: PyCharm
from pymongo import ASCENDING,DESCENDING
from util.database import DB_CONN
from datetime import datetime, timedelta
def get_trading_dates(begin_date=None, end_date=None):
"""
to get the list of trading dates.
if the begin_date is none, then get the date one year ago'
:param begin_date: beginning date
:param end_date: ending date
:return: a trading dates' list
"""
now = datetime.now()
if begin_date is None:
one_year_ago = now - timedelta(days=365)
begin_date = one_year_ago.strftime('%Y-%m-%d')
if end_date is None:
end_date = now.strftime('%Y-%m-%d')
daily_cursor = DB_CONN.daily.find(
{'code': '000001', 'date': {'$gte': begin_date, '$lte': end_date}, 'index': True},
sort=[('date', ASCENDING)],
projection={'date': True, '_id': False})
dates = [x['date'] for x in daily_cursor]
return dates
def get_trading_date_before(date, days):
'''
to get the trading date before,if days==1,means getting the last trading date;if days == 2,means getting the last second trading date
:param date:
:param days:
:return:
'''
count = days + 1
daily_cursor = DB_CONN.daily.find(
{'code': '000001', 'date': {'$lte': date}, 'index': True},
sort=[('date', DESCENDING)],
projection={'date': True, '_id': False},
limit=count
)
dates = [daily['date'] for daily in daily_cursor]
if len(dates) == count:
return dates[days]
return None
def get_all_codes(date=None):
"""
to get the list of stocks.
if there's no date, then get the last day's.
if the last day is not a trading day(can't get any code), then get the next last day's, and then on.
:param date: date
:return: a list of stocks' codes
"""
datetime_obj = datetime.now()
if date is None:
date = datetime_obj.strftime('%Y-%m-%d')
if date not in get_trading_dates(date,date):
date = get_trading_date_before(date, 1)
codes = []
code_cursor = DB_CONN.daily.find(
{'date': date},
projection={'code': True, '_id': False})
codes = [x['code'] for x in code_cursor]
return codes
if __name__ == "__main__":
# dates = get_trading_dates(begin_date='2018-01-01', end_date='2019-07-28')
# print(dates,flush=True)
code = get_all_codes("2019-07-28")
print(len(code),code,flush=True)
测试结果如下:
/Users/Ed_Frey/anaconda2/envs/python36/bin/python /Users/Ed_Frey/Desktop/MyQuant_v1/util/stock_util.py
3646 ['000001', '000300', '399001', '399005', '399006', '688016', '688022',………………'600781', '002481', '300788', '300108', '603778', '002660', '000918', '300431']
Process finished with exit code 0
中间省略了几千个股票代码。
2
data_module.py
这个模块是为后面做铺垫的,接下来在数据处理分析时,会时不时的从数据集中提取所需股票信息,而且不止一次两次的重复提取。要知道,从数据库中读取数据,也就是所谓的IO,定会严重影响到代码执行速度,毕竟要从3000多只股票中提取数据,就像爬取数据时,爬一圈要个把小时,加个索引可能二十分钟就能搞定。
于是,我们把数据提取做成一个专用模块,提取一次,存入变量放到内存中,后续重复使用,直接从内存读变量值即可。
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
# @Time : 2019-08-04 09:51
# @Author : Ed Frey
# @File : data_module.py
# @Software: PyCharm
from util.database import DB_CONN
from datetime import datetime
from pandas import DataFrame
class DataModule:
def __init__(self):
pass
def get_all_stock_k_data_at_date(self, autype=None, date=None):
if date is None:
date = datetime.now().strftime('%Y-%m-%d')
if autype is None:
collection = "daily"
elif autype == 'qfq':
collection = "qfq_daily"
elif autype == 'hfq':
collection = "hfq_daily"
else:
return []
daily_cursor = DB_CONN[collection].find(
{'date': date, 'index': False},
projection={'_id': False, 'index': False})
df_daily = DataFrame([daily for daily in daily_cursor])
if df_daily.index.size > 0:
df_daily.set_index(['code'], 1, inplace=True)
return df_daily
def get_stocks_at_date(self, codes=None, autype=None, date=None):
if codes is None:
return self.get_all_stock_k_data_at_date(
autype=autype, date=date)
if date is None:
date = datetime.now().strftime('%Y-%m-%d')
collection = 'daily' if autype is None or autype == '' else 'daily_' + autype
daily_cursor = DB_CONN[collection].find(
{'code': {'$in': codes}, 'date': date, 'index': False},
projection={'_id': False, 'index': False})
df_daily = DataFrame([daily for daily in daily_cursor])
if df_daily.index.size > 0:
df_daily.set_index(['code'], 1, inplace=True)
return df_daily
if __name__ == '__main__':
dm = DataModule()
df_daily = dm.get_all_stock_k_data_at_date(date='2019-07-25')
print(df_daily, flush=True)
运行结果这个样子:
本想这个周末给草草了事得了,结果发现没那么简单
为了回测,赶紧写好买卖点指标就差不多了。后来觉得指标太简单了会比较low,于是计划写个爬虫爬取财报、计算个市盈率啥的,等这些数据好不容易做好,发现买卖指标又来不及写了,更别提回测了。总之,磨死个人……