Python——量化分析介绍(十一)

也没啥好总结的,目录如下:

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是一个很常用的模块,不能就这么算了,于是煞费苦心继续死磕,总算搞定收工!

于是…… 本来想略过的曲线图,可以隆重登场了,咚咚咚

原文发布于微信公众号 - 奔跑的键盘侠(runningkeyboardhero)

原文发表时间:2019-08-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券