也没啥好总结的,目录如下:
1
最后再贴一次框架目录
├── MyQuant_v1 #量化分析程序目录
├── __init__.py
├── data #数据处理目录
│ ├── __init__.py
│ ├── basic_crawler.py# 爬取股票基础信息存入MongoDB数据库.
│ ├── data_crawler.py #爬取指数、股票数据
│ ├── data_module.py #从数据集中获取股票数据
│ └── finance_report_crawler.py #爬取财报数据
├──util # 公用程序
│ ├── __init__.py
│ ├── stock_util.py#获取股票交易日期、前一交易日日期、股票代码
│ └── database.py #链接数据库
├── factor #因子
│ ├── __init__.py
│ └── pe_factor.py#计算各股票的止盈率,用于后面的股票池策略
├── strategy #策略
│ ├── __init__.py
└─── stock_pool_strategy.py #股票池策略及效果演示
最后这篇吧,其实吧,砍掉很多啰嗦的章节,目录就根据已写的内容重新整理一下。前几天,很多粉丝反应有点云里雾里,甚至吐槽看不懂,所以我想还是赶快收尾吧,早点翻过这篇换新章。
讲一下最后这节的干货吧:stock_pool_strategy.py #股票池策略及效果演示
其实就是包含一个策略:选出pe在0—30之间的100只个股,7个交易日做一次调仓,持有股票全部以调仓日收盘价为准,可以卖出。假装都可以卖出,不考虑停牌、跌停限制等等。
接着就是这100只股票收益率累加求均值,其实是包含了一个按资金大小进行均仓的策略。比如使用1000万资金操作股票,100只股票各买10万元,根据调仓日卖出价减去买入价,再除以买入价,就是单只股票盈利比率,100只求一下平均值,就是此次调仓区间的盈亏比率了。
每期的盈亏比率有了,各期按复利的思路累计一下,再折算成净值。然后跟沪深300的净值进行比对,得到一个对比曲线图,于是,大功告成,有了对比就知道策略的好坏了
2
stock_pool_strategy.py
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
# @Time : 2019-08-05 21:47
# @Author : Ed Frey
# @File : stock_pool_strategy.py
# @Software: PyCharm
"""
实现股票池,条件是0 < PE <30, 按照PE正序排列,最多取100只票;
再平衡周期为7个交易日
主要的方法包括:
stock_pool:找到两个日期之间所有出的票
find_out_stocks:找到当前被调出的股票
evaluate_stock_pool:对股票池的性能做初步验证,确保股票池能够带来Alpha
"""
from pymongo import ASCENDING
import pandas as pd
import matplotlib.pyplot as plt
from util.database import DB_CONN
from util.stock_util import get_trading_dates
daily = DB_CONN['daily']
daily_hfq = DB_CONN['daily_hfq']
def stock_pool(begin_date, end_date):
"""
股票池
:param begin_date: 开始日期
:param end_date: 结束日期
:return: tuple,所有调整日,以及调整日和代码列表对应的dict
"""
adjust_date_codes_dict = dict()
all_dates = get_trading_dates(begin_date=begin_date, end_date=end_date)
last_phase_codes = []
adjust_interval = 7
all_adjust_dates = []
for _index in range(0, len(all_dates), adjust_interval):
adjust_date = all_dates[_index]
all_adjust_dates.append(adjust_date)
# print('调整日期:%s' % adjust_date, flush=True)
daily_cursor = daily.find(
{'date': adjust_date, 'pe': {'$lt': 30, '$gt': 0},
'index':False, 'is_trading': True},
sort=[('pe', ASCENDING)],
projection={'code': True},
limit=100
)
codes = [x['code'] for x in daily_cursor]
this_phase_codes = []
if len(last_phase_codes) > 0:
suspension_cursor = daily.find(
{'code': {'$in': last_phase_codes}, 'date': adjust_date, 'is_trading': False},
projection={'code': True}
)
suspension_codes = [x['code'] for x in suspension_cursor]
this_phase_codes = suspension_codes
# print('上期停牌', flush=True)
# print(this_phase_codes, flush=True)
this_phase_codes += codes[0: 100 - len(this_phase_codes)]
last_phase_codes = this_phase_codes
adjust_date_codes_dict[adjust_date] = this_phase_codes
# print('最终出票', flush=True)
# print(this_phase_codes, flush=True)
return all_adjust_dates, adjust_date_codes_dict
def evaluate_stock_pool():
"""
对股票池做一个简单的评价
"""
# 设定评测周期
adjust_dates, codes_dict = stock_pool('2018-01-01', '2019-07-28')
# 用DataFrame保存收益
df_profit = pd.DataFrame(columns=['profit', 'hs300'])
df_profit.loc[adjust_dates[0]] = {'profit': 0, 'hs300': 0}
hs300_begin_value = daily.find_one({'code': '000300', 'index': True, 'date': adjust_dates[0]})['close']
# 通过净值计算累计收益
net_value = 1
for _index in range(1, len(adjust_dates) - 1):
last_adjust_date = adjust_dates[_index - 1]
current_adjust_date = adjust_dates[_index]
# 获取上一期的股票池
codes = codes_dict[last_adjust_date]
# 构建股票代码和后复权买入价格的股票
code_buy_close_dict = dict()
buy_daily_cursor = daily_hfq.find(
{'code': {'$in': codes}, 'date': last_adjust_date,'index':False},
projection={'close': True, 'code': True}
)
for buy_daily in buy_daily_cursor:
code = buy_daily['code']
code_buy_close_dict[code] = buy_daily['close']
# 获取到期的股价
sell_daily_cursor = daily_hfq.find(
{'code': {'$in': codes}, 'date': current_adjust_date,'index':False},
projection={'close': True, 'code': True}
)
# 计算单期收益
profit_sum = 0
count = 0
for sell_daily in sell_daily_cursor:
code = sell_daily['code']
if code in code_buy_close_dict:
buy_close = code_buy_close_dict[code]
sell_close = sell_daily['close']
profit_sum += (sell_close - buy_close) / buy_close
count += 1
print("收益报告:%s,%s"%(current_adjust_date,profit_sum))
if count > 0:
profit = round(profit_sum / count, 4)
hs300_close = daily.find_one({'code': '000300', 'index': True, 'date': current_adjust_date})['close']
net_value = net_value * (1 + profit)
df_profit.loc[current_adjust_date] = {
'profit': round((net_value - 1) * 100, 4),
'hs300': round((hs300_close - hs300_begin_value) * 100 / hs300_begin_value, 4)}
print(df_profit)
df_profit.plot(title='Stock Pool Evaluation Result', kind='line')
df_profit.plot()
plt.show()
if __name__ == "__main__":
# stock_pool('2018-01-01', '2019-07-28')
evaluate_stock_pool()
3
运行结果和曲线图呢?
略…………
有点坑?其实感觉我自己才是最大的受害者……
不过运行结果还是不能省的,贴两张出来:
这个是运行stock_pool('2018-01-01', '2019-07-28')的时候一个股票池情况
而运行evaluate_stock_pool()的结果是这个样子:
有木有一种妥妥跑赢沪深300的错觉呢??别飘,哥没有算买卖手续费、印花税,假定一年200交易日、如有30个买卖区间来算,按千分之二算一期的费率,就是-6%了,而且跌停、退市什么的总是会碰到,毕竟操作那么多股票。
总之,要做一个量化分析的项目,需要花费大量的精力时间去建模,不断的修正完善,有很多问题要实战起来,才会发现,哇靠,这么复杂!!!
至于,沪深300与策略收益曲线对比图呢,一把辛酸泪?!收尾阶段碰到一个难以解决的异常,就是使用matplotlib模块时,抛出一个异常:
Intel MKL FATAL ERROR: Error on loading function mkl_blas_avx2_get_kernel_api_version.
这个问题挺棘手的,反正吧,碰到这种跟软件安装有关的问题,都是令人头疼的
后来的后来,想想不对劲,matplotlib是一个很常用的模块,不能就这么算了,于是煞费苦心继续死磕,总算搞定收工!
于是…… 本来想略过的曲线图,可以隆重登场了,咚咚咚