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

这是奔跑的键盘侠的第118篇文章

依旧,先贴一下目录:

├── README
├── 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 #链接数据库
   ├── 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#不准备开发

开弓没有回头箭,no zuo no die……

这节要写的是从网站爬取财务报表信息,然后写入自己的数据集中。财务信息有了,接着就可以自己算各个股票的PE市盈率了。

1

finance_report_crawler.py

爬取上市公司财报数据,说白了就是个简单的爬虫,数据来源:东方财富官网。

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
# @Time    : 2019-08-04 06:40
# @Author  : Ed Frey
# @File    : finance_report_crawler.py
# @Software: PyCharm
import json

import urllib3
from pymongo import UpdateOne

from util.database import DB_CONN
from util.stock_util import get_all_codes
import traceback


class FinanceReportCrawler:

    def __init__(self):
        self.finance_report = DB_CONN['finance_report']

    def crawl_finance_summary(self):
        """
        to get summary information from financial reports of the listed company
        """
        codes = get_all_codes()
        conn_pool = urllib3.PoolManager()
        url = 'http://dcfm.eastmoney.com//em_mutisvcexpandinterface/api/js/get?' \
              'type=YJBB20_YJBB&token=70f12f2f4f091e459a279469fe49eca5&st=reportdate&sr=-1' \
              '&filter=(scode={0})&p={page}&ps={pageSize}&js={"pages":(tp),"data":(x)}'
        for code in codes:
            try:
                response = conn_pool.request('GET', url.replace('{0}', code))
                result = json.loads(response.data.decode('UTF-8'))
                reports = result['data']

                update_requests = []
                for report in reports:
                    doc = {
                        'report_date': report['reportdate'][0:10],
                        'announced_date': report['latestnoticedate'][0:10],
                        'eps': report['basiceps'],
                        'code': code
                    }

                    update_requests.append(
                        UpdateOne(
                            {'code': code, 'report_date': doc['report_date']},
                            {'$set': doc}, upsert=True))

                if len(update_requests) > 0:
                    update_result = self.finance_report.bulk_write(update_requests, ordered=False)
                    print('股票 %s, 财报,更新 %d, 插入 %d' %
                          (code, update_result.modified_count, update_result.upserted_count))
            except:
                print('获取业绩报表时,发生错误:%s' % code, flush=True)
                traceback.print_exc()


if __name__ == '__main__':
    frc = FinanceReportCrawler()
    frc.crawl_finance_summary()

运行结果:

同样,建立一下索引,运行速度会大幅提升,没几分钟就爬取完毕。打开终端看一下数据集信息。

爬取到了138854条信息。

2

pe_factor.py

这篇依旧是爬取数据,爬取上市公司财报数据,说白了就是个简单的爬虫,数据来源:东方财富官网。

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
# @Time    : 2019-08-04 07:20
# @Author  : Ed Frey
# @File    : pe_factor.py
# @Software: PyCharm
from util.database import DB_CONN
from data.data_module import DataModule
from util.stock_util import get_trading_dates
from pymongo import UpdateOne
import traceback

class PEFactor:
    def __init__(self):
        self.daily_collection = DB_CONN['daily']
        self.finance_report = DB_CONN['finance_report']
        self.dm = DataModule()

    def compute_one_day(self, date):
        df_daily = self.dm.get_all_stock_k_data_at_date(autype=None,date=date)

        factors = []
        for code in df_daily.index:
            try:
                eps = self.finance_report.find_one(
                    {
                        'code': code,
                        'report_date': '2018-12-31',

                    },
                    projection = {'_id': False, 'code': False})
                # print(eps)
                if eps is None:
                    continue
                close = df_daily.loc[code]['close']

                if 'eps' not in eps or eps['eps'] == '-':
                    print('计算pe因子,EPS有误, 股票代码:%s,日期:%s' %(code, date), eps)
                    continue
                pe = close/eps['eps']
                factors.append({
                    'date': date,
                    'code': code,
                    'pe': round(pe, 2)
                })
            except:
                print('计算pe因子出错, 股票代码:%s,日期:%s' %(code, date))
                traceback.print_exc()

        return factors


    def compute(self, begin_date, end_date):

        dates = get_trading_dates(begin_date, end_date)

        for date in dates:
            factors = self.compute_one_day(date)
            # print('计算pe因子:,日期:%s,数量:%4d。' %(date, len(factors)))
            update_requests = []
            for factor in factors:
                update_requests.append(
                    UpdateOne({'code': factor['code'], 'date': factor['date'],'index':False},
                              {'$set': factor},
                              upsert=True))

            if len(update_requests) > 0:
                update_result = self.daily_collection.bulk_write(update_requests, ordered=False)
                print('保存pe因子,日期:%s,插入:%4d,更新:%4d' %
                      (date, update_result.upserted_count, update_result.modified_count))


if __name__ == '__main__':
    pf = PEFactor()
    pf.compute('2018-01-01', '2019-07-28')

这个计算起来可能比较花时间,可以同时并行运算,比如按不同的季度同时运算上面的代码

关于市盈率的计算,简单起见,就直接取18年年度EPS来计算2018-2019的市盈率,要深入的话,需要在第二年三四月份财报发布后才知道前一年的EPS,可见PE的计算本身就不是完全合拍的。所以,就酱紫吧。

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

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

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

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券