├── assets └── imgs │ ├── 20190520.jpg │ ├── 201904262245.png │ ├── 201904271217.jpg │ ├── 201904271328.png │ ├── 201904271817.png │ ├── 201904271950.jpg │ ├── 201904271953.png │ ├── 201904281250.png │ ├── 201905012052.png │ ├── 201905022239.png │ ├── 201905031521.jpg │ ├── 201905072238.png │ ├── 201905072303.png │ ├── 201905072311.png │ ├── 201905081102.png │ ├── 201905081112.png │ ├── 201905081409.png │ ├── 201905081642.png │ ├── 201905081711.png │ ├── 20190516102436.png │ ├── 201905181224.png │ ├── 20190520111714.png │ ├── 201905201329.jpg │ ├── 201905211027.jpg │ ├── 201905211033.jpg │ ├── 20190521151217.png │ ├── 20190521155326.png │ ├── mind201904281842.jpg │ ├── mind201905012008.jpg │ ├── mind201904281842.jpeg │ └── mind201905012008_origin.png ├── .gitignore └── README.md /assets/imgs/20190520.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/20190520.jpg -------------------------------------------------------------------------------- /assets/imgs/201904262245.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201904262245.png -------------------------------------------------------------------------------- /assets/imgs/201904271217.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201904271217.jpg -------------------------------------------------------------------------------- /assets/imgs/201904271328.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201904271328.png -------------------------------------------------------------------------------- /assets/imgs/201904271817.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201904271817.png -------------------------------------------------------------------------------- /assets/imgs/201904271950.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201904271950.jpg -------------------------------------------------------------------------------- /assets/imgs/201904271953.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201904271953.png -------------------------------------------------------------------------------- /assets/imgs/201904281250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201904281250.png -------------------------------------------------------------------------------- /assets/imgs/201905012052.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905012052.png -------------------------------------------------------------------------------- /assets/imgs/201905022239.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905022239.png -------------------------------------------------------------------------------- /assets/imgs/201905031521.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905031521.jpg -------------------------------------------------------------------------------- /assets/imgs/201905072238.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905072238.png -------------------------------------------------------------------------------- /assets/imgs/201905072303.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905072303.png -------------------------------------------------------------------------------- /assets/imgs/201905072311.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905072311.png -------------------------------------------------------------------------------- /assets/imgs/201905081102.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905081102.png -------------------------------------------------------------------------------- /assets/imgs/201905081112.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905081112.png -------------------------------------------------------------------------------- /assets/imgs/201905081409.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905081409.png -------------------------------------------------------------------------------- /assets/imgs/201905081642.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905081642.png -------------------------------------------------------------------------------- /assets/imgs/201905081711.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905081711.png -------------------------------------------------------------------------------- /assets/imgs/20190516102436.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/20190516102436.png -------------------------------------------------------------------------------- /assets/imgs/201905181224.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905181224.png -------------------------------------------------------------------------------- /assets/imgs/20190520111714.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/20190520111714.png -------------------------------------------------------------------------------- /assets/imgs/201905201329.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905201329.jpg -------------------------------------------------------------------------------- /assets/imgs/201905211027.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905211027.jpg -------------------------------------------------------------------------------- /assets/imgs/201905211033.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/201905211033.jpg -------------------------------------------------------------------------------- /assets/imgs/20190521151217.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/20190521151217.png -------------------------------------------------------------------------------- /assets/imgs/20190521155326.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/20190521155326.png -------------------------------------------------------------------------------- /assets/imgs/mind201904281842.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/mind201904281842.jpg -------------------------------------------------------------------------------- /assets/imgs/mind201905012008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/mind201905012008.jpg -------------------------------------------------------------------------------- /assets/imgs/mind201904281842.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/mind201904281842.jpeg -------------------------------------------------------------------------------- /assets/imgs/mind201905012008_origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CatsJuice/quantitative-investment-learning/HEAD/assets/imgs/mind201905012008_origin.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # quantitative-investment-learning 2 | 3 | 使用Python进行量化投资的学习报告 4 | **Python量化投资学习报告** 5 | 6 | `CatsJuice` 编辑于 `2019-4-26` 7 | 8 | 上一次更新: `2019-05-21 16:04` 9 | 10 | **CONTENTS:** 11 | 12 | - [quantitative-investment-learning](#quantitative-investment-learning) 13 | - [1. **数据抓取**](#1-%e6%95%b0%e6%8d%ae%e6%8a%93%e5%8f%96) 14 | - [1.1. **通过第三方数据平台直接调用api**](#11-%e9%80%9a%e8%bf%87%e7%ac%ac%e4%b8%89%e6%96%b9%e6%95%b0%e6%8d%ae%e5%b9%b3%e5%8f%b0%e7%9b%b4%e6%8e%a5%e8%b0%83%e7%94%a8api) 15 | - [1.1.1. **TuShare(挖地兔)**](#111-tushare%e6%8c%96%e5%9c%b0%e5%85%94) 16 | - [1.1.1.1. **A. 概述**](#1111-a-%e6%a6%82%e8%bf%b0) 17 | - [1.1.1.2. **B. 基本使用**](#1112-b-%e5%9f%ba%e6%9c%ac%e4%bd%bf%e7%94%a8) 18 | - [1.1.2. **其他平台**](#112-%e5%85%b6%e4%bb%96%e5%b9%b3%e5%8f%b0) 19 | - [1.1.2.1. **Win.d**](#1121-wind) 20 | - [1.1.2.2. **优矿**](#1122-%e4%bc%98%e7%9f%bf) 21 | - [1.2. **使用爬虫抓取**](#12-%e4%bd%bf%e7%94%a8%e7%88%ac%e8%99%ab%e6%8a%93%e5%8f%96) 22 | - [1.2.1. **新浪财经**](#121-%e6%96%b0%e6%b5%aa%e8%b4%a2%e7%bb%8f) 23 | - [1.2.1.1. **获取所有股票代码**(这里只考虑沪深A股)](#1211-%e8%8e%b7%e5%8f%96%e6%89%80%e6%9c%89%e8%82%a1%e7%a5%a8%e4%bb%a3%e7%a0%81%e8%bf%99%e9%87%8c%e5%8f%aa%e8%80%83%e8%99%91%e6%b2%aa%e6%b7%b1a%e8%82%a1) 24 | - [1.2.1.2. **获取日线数据**](#1212-%e8%8e%b7%e5%8f%96%e6%97%a5%e7%ba%bf%e6%95%b0%e6%8d%ae) 25 | - [1.2.1.3. **获取财务数据**](#1213-%e8%8e%b7%e5%8f%96%e8%b4%a2%e5%8a%a1%e6%95%b0%e6%8d%ae) 26 | - [1.2.2. **网易财经**](#122-%e7%bd%91%e6%98%93%e8%b4%a2%e7%bb%8f) 27 | - [1.2.2.1. **获取所有股票代码**(这里只考虑沪深A股)](#1221-%e8%8e%b7%e5%8f%96%e6%89%80%e6%9c%89%e8%82%a1%e7%a5%a8%e4%bb%a3%e7%a0%81%e8%bf%99%e9%87%8c%e5%8f%aa%e8%80%83%e8%99%91%e6%b2%aa%e6%b7%b1a%e8%82%a1) 28 | - [1.2.2.2. **获取日线数据**](#1222-%e8%8e%b7%e5%8f%96%e6%97%a5%e7%ba%bf%e6%95%b0%e6%8d%ae) 29 | - [1.2.2.3. **网易财经财务数据**](#1223-%e7%bd%91%e6%98%93%e8%b4%a2%e7%bb%8f%e8%b4%a2%e5%8a%a1%e6%95%b0%e6%8d%ae) 30 | - [1.2.3. **东方财富**](#123-%e4%b8%9c%e6%96%b9%e8%b4%a2%e5%af%8c) 31 | - [1.2.3.1. **股票信息列表**](#1231-%e8%82%a1%e7%a5%a8%e4%bf%a1%e6%81%af%e5%88%97%e8%a1%a8) 32 | - [1.2.3.2. **交易数据, 财务数据**](#1232-%e4%ba%a4%e6%98%93%e6%95%b0%e6%8d%ae-%e8%b4%a2%e5%8a%a1%e6%95%b0%e6%8d%ae) 33 | - [2. **热点获取**](#2-%e7%83%ad%e7%82%b9%e8%8e%b7%e5%8f%96) 34 | - [2.1. **东方财富**](#21-%e4%b8%9c%e6%96%b9%e8%b4%a2%e5%af%8c) 35 | - [3. **数据分析**](#3-%e6%95%b0%e6%8d%ae%e5%88%86%e6%9e%90) 36 | - [3.1. **换手率分析**](#31-%e6%8d%a2%e6%89%8b%e7%8e%87%e5%88%86%e6%9e%90) 37 | - [3.2. **CCI指标**](#32-cci%e6%8c%87%e6%a0%87) 38 | - [3.2.1. **概念**](#321-%e6%a6%82%e5%bf%b5) 39 | - [3.2.2. **指标用法**](#322-%e6%8c%87%e6%a0%87%e7%94%a8%e6%b3%95) 40 | - [3.2.3. **公式**](#323-%e5%85%ac%e5%bc%8f) 41 | - [3.2.3.1. **公式一:**](#3231-%e5%85%ac%e5%bc%8f%e4%b8%80) 42 | - [3.2.3.2. **公式二:**](#3232-%e5%85%ac%e5%bc%8f%e4%ba%8c) 43 | - [3.2.4. **程序设计**](#324-%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1) 44 | - [3.2.5. **参数说明**](#325-%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e) 45 | - [3.2.6. **测试结果**](#326-%e6%b5%8b%e8%af%95%e7%bb%93%e6%9e%9c) 46 | - [3.3. **《胡立阳股票投资100招》** 由“价量关系”来为个股打分数](#33-%e8%83%a1%e7%ab%8b%e9%98%b3%e8%82%a1%e7%a5%a8%e6%8a%95%e8%b5%84100%e6%8b%9b-%e7%94%b1%e4%bb%b7%e9%87%8f%e5%85%b3%e7%b3%bb%e6%9d%a5%e4%b8%ba%e4%b8%aa%e8%82%a1%e6%89%93%e5%88%86%e6%95%b0) 47 | - [3.3.1. **概念**](#331-%e6%a6%82%e5%bf%b5) 48 | - [3.3.2. **程序设计**](#332-%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1) 49 | - [3.3.3. **结果**](#333-%e7%bb%93%e6%9e%9c) 50 | - [3.3.4. **Source Code**](#334-source-code) 51 | - [3.4. **移动平均线分析**](#34-%e7%a7%bb%e5%8a%a8%e5%b9%b3%e5%9d%87%e7%ba%bf%e5%88%86%e6%9e%90) 52 | - [3.4.1. **概念**](#341-%e6%a6%82%e5%bf%b5) 53 | - [3.4.2. **计算**](#342-%e8%ae%a1%e7%ae%97) 54 | - [3.4.3. **程序设计**](#343-%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1) 55 | - [3.4.4. **参数说明**](#344-%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e) 56 | - [3.4.5. **购买策略分析**](#345-%e8%b4%ad%e4%b9%b0%e7%ad%96%e7%95%a5%e5%88%86%e6%9e%90) 57 | - [3.4.5.1. **策略一: '老太太选股法' 一根均线打天下**](#3451-%e7%ad%96%e7%95%a5%e4%b8%80-%e8%80%81%e5%a4%aa%e5%a4%aa%e9%80%89%e8%82%a1%e6%b3%95-%e4%b8%80%e6%a0%b9%e5%9d%87%e7%ba%bf%e6%89%93%e5%a4%a9%e4%b8%8b) 58 | - [3.4.5.2. **策略二:'黄金交叉'和'死亡交叉'**](#3452-%e7%ad%96%e7%95%a5%e4%ba%8c%e9%bb%84%e9%87%91%e4%ba%a4%e5%8f%89%e5%92%8c%e6%ad%bb%e4%ba%a1%e4%ba%a4%e5%8f%89) 59 | - [3.4.6. **分析结果**](#346-%e5%88%86%e6%9e%90%e7%bb%93%e6%9e%9c) 60 | - [3.4.6.1. **老太太选股法**](#3461-%e8%80%81%e5%a4%aa%e5%a4%aa%e9%80%89%e8%82%a1%e6%b3%95) 61 | - [3.4.6.2. **'黄金交叉'和'死亡交叉'**](#3462-%e9%bb%84%e9%87%91%e4%ba%a4%e5%8f%89%e5%92%8c%e6%ad%bb%e4%ba%a1%e4%ba%a4%e5%8f%89) 62 | - [3.4.7. **Source Code**](#347-source-code) 63 | - [3.5. **分时数据 成交手分析**](#35-%e5%88%86%e6%97%b6%e6%95%b0%e6%8d%ae-%e6%88%90%e4%ba%a4%e6%89%8b%e5%88%86%e6%9e%90) 64 | - [3.5.1. **基本概念**](#351-%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5) 65 | - [3.5.2. **分析的形态**](#352-%e5%88%86%e6%9e%90%e7%9a%84%e5%bd%a2%e6%80%81) 66 | - [3.5.3. **程序设计**](#353-%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1) 67 | - [3.5.4. **参数说明**](#354-%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e) 68 | - [3.5.5. **结果及分析**](#355-%e7%bb%93%e6%9e%9c%e5%8f%8a%e5%88%86%e6%9e%90) 69 | - [3.5.6. **Source Code**](#356-source-code) 70 | - [3.6. **MACD**](#36-macd) 71 | - [3.6.1. **基本概念**](#361-%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5) 72 | - [3.6.1.1. **MACD**](#3611-macd) 73 | - [3.6.1.2. **MACD 金叉**](#3612-macd-%e9%87%91%e5%8f%89) 74 | - [3.6.1.3. **MACD 死叉**](#3613-macd-%e6%ad%bb%e5%8f%89) 75 | - [3.6.2. **程序设计**](#362-%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1) 76 | - [3.6.2.1. **数据计算**](#3621-%e6%95%b0%e6%8d%ae%e8%ae%a1%e7%ae%97) 77 | - [3.6.2.2. **数据分析**](#3622-%e6%95%b0%e6%8d%ae%e5%88%86%e6%9e%90) 78 | - [3.6.3. **参数说明**](#363-%e5%8f%82%e6%95%b0%e8%af%b4%e6%98%8e) 79 | - [3.6.4. **function注释**](#364-function%e6%b3%a8%e9%87%8a) 80 | - [3.6.5. **结果分析**](#365-%e7%bb%93%e6%9e%9c%e5%88%86%e6%9e%90) 81 | - [3.6.6. **Source Code**](#366-source-code) 82 | 83 | # 1. **数据抓取** 84 | 85 | ## 1.1. **通过第三方数据平台直接调用api** 86 | 87 | ### 1.1.1. **TuShare(挖地兔)** 88 | 89 | #### 1.1.1.1. **A. 概述** 90 | 91 | > **Tushare**是一个免费、开源的python财经数据接口包。主要实现对股票等金融数据从**数据采集**、**清洗加工** 到**数据存储**的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。 92 | 93 | 接口文档地址:[http://tushare.org/](http://tushare.org/) 94 | 95 | ToShare Pro: [https://tushare.pro/](https://tushare.pro/) 96 | 97 | #### 1.1.1.2. **B. 基本使用** 98 | 99 | **使用前提**: 100 | 101 | - 安装Python 102 | - 安装Pandas, lxml 103 | 104 | **下载安装**: 105 | 106 | - 方式1:`pip install tushare` 107 | - 方式2:访问[https://pypi.python.org/pypi/Tushare/](https://pypi.python.org/pypi/Tushare/)下载安装 108 | 109 | **使用**: 110 | 111 | 以[历史行情](http://tushare.org/trading.html#id2)接口为例, 如下调用: 112 | 113 | ```python 114 | import tushare as ts 115 | 116 | ts.get_hist_data('600848') #一次性获取全部日k线数据 117 | ``` 118 | 119 | **结果显示**: 120 | 121 | ![历史行情接结果返回](./assets/imgs/201904262245.png "历史行情结果") 122 | 123 | > `Tushare`返回的绝大部分的数据格式都是`pandas DataFrame`类型,非常便于用`pandas` / `NumPy` / `Matplotlib`进行数据分析和可视化 124 | 125 | ### 1.1.2. **其他平台** 126 | 127 | #### 1.1.2.1. **Win.d** 128 | 129 | 官网: [https://www.wind.com.cn/Default.html](https://www.wind.com.cn/Default.html) 130 | >中国市场的精准金融数据服务供应商,为量化投资与各类金融业务系统提供准确、及时、完整的落地数据,内容涵盖 131 | 股票、债券、基金、衍生品、指数、宏观行业等各类金融市场数据,助您运筹帷幄,决胜千里 132 | 133 | #### 1.1.2.2. **优矿** 134 | 135 | 官网: [https://uqer.io/](https://uqer.io/) 136 | > 提供各类资产的财务、因子、主题、宏观行业特色大数据,以及量化场景下的PIT数据,保障量化过程不引入未来数据。 137 | > 股票、期货、指数、场内外基金等多资产多策略回测。丰富的衍生工具,保证多因子策略、事件驱动等快速实现。 138 | 139 | ## 1.2. **使用爬虫抓取** 140 | 141 | 手动写爬虫进行抓取, 首先需要确定数据来源, 较为主流的财经数据平台有**新浪财经**, **东方财富**, **网易财经**等。 接下来针对若干平台, 分析抓取的过程以及可能遇到的问题; 142 | 143 | ### 1.2.1. **新浪财经** 144 | 145 | #### 1.2.1.1. **获取所有股票代码**(这里只考虑沪深A股) 146 | 147 | 新浪财经的数据地址为[http://vip.stock.finance.sina.com.cn/q/go.php/vIR_CustomSearch/index.phtml](http://vip.stock.finance.sina.com.cn/q/go.php/vIR_CustomSearch/index.phtml), 通过切换页面可以发现, 地址栏的url的参数发生了变化,变化的规律为:`p=n`, `n`为当前页码, 而股票代码和股票名称, 通过`F12`打开开发者工具, 表单中的值均可定位到, 应该可以通过爬虫抓取所有股票的基本信息, 通过新浪财经抓取股票的代码我这里没有写, 暂先略过; 148 | 149 | #### 1.2.1.2. **获取日线数据** 150 | 151 | 在新浪财经数据中心, 我并没有找到**交易数据**的表格, 要查看某只股票的**日线** / **分线**只能通过点击某只股票进到[详情页](https://finance.sina.com.cn/realstock/company/sh601789/nc.shtml)(而url中的股票代码对应着不同的股票), 而新浪财经的数据并非以表格的形式展示, 而是通过图表展示, 鼠标移动时通过`JavaScript`更新日期及当前股票的数据信息;那么直接抓取网页是无法获取到数据的, 现在的思路是分析js文件, 找到鼠标移动时监听到的事件, 查明js是如何更新数据的, js的数据从哪里提取,以此来抓取信息; 152 | 153 | 首先, 通过页面元素审查可以发现, 分时线是通过`HTML5`的`canvas`绘制的, 在Sources找相关的js文件, 可以找到`paintSth.js`文件, 由于在鼠标移动时会更新页面元素, 所以可以直接在文件中查找`mousemove`, 找到了相关代码如下: 154 | 155 | ```js 156 | C = this.interactCanvas, 157 | ... 158 | ... 159 | ... 160 | C.addEventListener("mousemove", o), 161 | ``` 162 | 163 | 可以看到Canvas加了一个mousemove的监听器, 执行`o`, 再查找`o()`, 可以找到如下代码: 164 | 165 | ```js 166 | function o() { 167 | if (!c) { 168 | var t = document.createElement("canvas"); 169 | c = t.getContext("2d") 170 | } 171 | return c 172 | } 173 | ``` 174 | 175 | 这里`c`又是一个未知量, 所以应该继续检索`c`的信息, 由于关联的js文件较多, 这种做法过于费时费力, 爬取新浪财经的交易数据应该不是明智的选择; 176 | 177 | **换种思路**, 既然可以浏览, 那么使用 `selenium` 就有可能, `selenium` 可以进行自动化测试, 让鼠标在固定位置移动, 同时抓取更新的信息, 这种做法是可行的, 我也尝试着做了, 由于这一方法过于不实用, 源码略; 178 | 179 | **这种做法局限性太大**, 首先, **效率过低**, 这是很致命的一个缺陷, 除此之外, 由于移动导致的像素不同, 可能会出现数据遗漏或重复;最后, 新浪财经默认只显示一定日期的交易数据, 要查看更早的需要手动拖动进度条, 这就使得`selenium`的操作误差更大; 180 | 181 | 综上所述, 在新浪抓取交易数据是挺不容易的事情; 182 | 183 | #### 1.2.1.3. **获取财务数据** 184 | 185 | 新浪的财务数据在[http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/profit/index.phtml?p=1](http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/profit/index.phtml?p=2), 这应该是爬虫抓取中喜闻乐见的格式了,换页不需要通过ajax, 所以抓取的时候只需要设定好抓取的总页数, 循环抓取页面再解析即可, 接下来即可直接进行代码的编写(未亲自验证) 186 | 187 | ### 1.2.2. **网易财经** 188 | 189 | #### 1.2.2.1. **获取所有股票代码**(这里只考虑沪深A股) 190 | 191 | 网易财经的所有沪深A股数据位于[http://quotes.money.163.com/old/#query=EQA&DataType=HS_RANK&sort=PERCENT&order=desc&count=24&page=0](http://quotes.money.163.com/old/#query=EQA&DataType=HS_RANK&sort=PERCENT&order=desc&count=24&page=0), 从`url`来看, 换页通过url传参即可改变了, 但是实际操作可以发现, 点击换页时`url`中的`page`并不会改变, 但改变`url`中的`page`参数, 当前页面序号会改变;但这不意味着可以像[1.2.1. **新浪财经**](#121-新浪财经)中爬取新浪财经一样, 枚举url的page参数来爬取所有信息;因为股票数据是异步加载的, 直接抓取无法获取到值; 192 | 193 | 对于网易财经,由于点击换页时页面的url没有更新,所以应该是使用了`Ajax`或`Js`来更新数据, 通过`F12`调起开发者工具, 在`Network`选型卡中, 筛选`XHR`, 每当点击换页时, 就会有新的`XHR`, 分析这些`XHR`的url可以发现,只有`page`值在改变: 194 | 195 | ![XHR URL](./assets/imgs/201904271217.jpg) 196 | 197 | 直接复制`Request URL`并使用浏览器访问, 可以得到`json`格式的数据, 但是可以看到中文通过`Unicode`编码了, 在获取后, 可以通过`s.decode('unicode_escape')`来解码;接下来就是对`json`解析并提取需要的信息了, json格式如下: 198 | 199 | ![网易财经股票JSON格式](./assets/imgs/201904271328.png) 200 | 201 | 在`list`中有`[0]`到`[23]`共24条数据, 对应请求中的参数`count=24`, 关于字段名的解释, 以下为我的分析: 202 | 203 | No. | key_name | meaning 204 | :--:| :--: | :--: 205 | 1 | ANNOUNMT | 公告信息,并非必须,对应在页面中有公告标签的股票才有这个字段 206 | 2 | CODE | 股票代码 207 | 3 | FIVE_MINUTE | 5分钟涨跌额 208 | 4 | HIGH | 最高 209 | 5 | HS | 换手率(不带%) 210 | 6 | LB | 量比 211 | 7 | LOW | 最低 212 | 8 | MCAP | 流通市值 213 | 9 | MFRATIO | list, 包含2个值`MFRATIO2`:净利润, `MFRATIO10`: 主营收 214 | 10 | MFSUM | 每股收益 215 | 11 | NAME | 名称 216 | 12 | NO | 网易财经中的编号 217 | 13 | OPEN | 今日开盘 218 | 14 | PE | 市盈率 219 | 15 | PERCENT | 涨跌幅 220 | 16 | PRICE | 价格 221 | 17 | TCAP | 总市值 222 | 18 | TURNOVER | 成交额 223 | 19 | VOLUME | 成交量 224 | 20 | WB | 委比 225 | 226 |   所以可以直接抓取这个url来获取相关的数据, 更有趣的是, 请求参数中有个`count`参数, 决定了数据的数量, 所以我尝试将`count`设置成全部数量, 查看网易财经沪深A股, 网易的编号最后一只为`3607`, 所以如下请求: 227 | 228 | ```js 229 | 'http://quotes.money.163.com/hs/service/diyrank.php?host=http%3A%2F%2Fquotes.money.163.com%2Fhs%2Fservice%2Fdiyrank.php&page=0&query=STYPE%3AEQA&fields=NO%2CSYMBOL%2CNAME%2CPRICE%2CPERCENT%2CUPDOWN%2CFIVE_MINUTE%2COPEN%2CYESTCLOSE%2CHIGH%2CLOW%2CVOLUME%2CTURNOVER%2CHS%2CLB%2CWB%2CZF%2CPE%2CMCAP%2CTCAP%2CMFSUM%2CMFRATIO.MFRATIO2%2CMFRATIO.MFRATIO10%2CSNAME%2CCODE%2CANNOUNMT%2CUVSNEWS&sort=PERCENT&order=desc&count=3607&type=query' 230 | ``` 231 | 232 | 即可返回所有`json`格式的数据, 然后再进行解析, 并写入文件, 完整代码如下: 233 | 234 | ```py 235 | import urllib 236 | import json 237 | import csv 238 | from tqdm import tqdm 239 | 240 | # 下载器 241 | class Downloader(object): 242 | def __init__(self, url): 243 | self.url = url 244 | 245 | def download(self): 246 | html_content = urllib.request.urlopen(self.url).read() 247 | html_content = html_content.decode("utf-8") 248 | return html_content 249 | 250 | # 调度器 251 | class Controller(object): 252 | 253 | def __init__(self): 254 | self.downloader = None 255 | self.parser = None 256 | self.saver = None 257 | 258 | def get_data(self): 259 | url = "http://quotes.money.163.com/hs/service/diyrank.php?host=http%3A%2F%2Fquotes.money.163.com%2Fhs%2Fservice%2Fdiyrank.php&page=0&query=STYPE%3AEQA&fields=NO%2CSYMBOL%2CNAME%2CPRICE%2CPERCENT%2CUPDOWN%2CFIVE_MINUTE%2COPEN%2CYESTCLOSE%2CHIGH%2CLOW%2CVOLUME%2CTURNOVER%2CHS%2CLB%2CWB%2CZF%2CPE%2CMCAP%2CTCAP%2CMFSUM%2CMFRATIO.MFRATIO2%2CMFRATIO.MFRATIO10%2CSNAME%2CCODE%2CANNOUNMT%2CUVSNEWS&sort=PERCENT&order=desc&count=3607&type=query" 260 | html_content = urllib.request.urlopen(url).read() 261 | # 这时候解码可能导致json解析错误!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 262 | # html_content = html_content.decode("unicode_escape") 263 | # 当数量大于2995会报错, json解析失败, 原因是编号为2996的股票, 在公告中嵌套了引号导致json解析失败 264 | data = json.loads(html_content) 265 | 266 | self.saver = Saver(data=data) 267 | self.saver.save() 268 | 269 | class Saver(object): 270 | 271 | def __init__(self, data): 272 | self.data = data 273 | self.prifix = 'F:\\files\\sharesDatas\\code_list\\' # 存放目录 274 | 275 | def save(self): 276 | # 新建文件, 写入文件头 277 | file_header = ["代码", "名称", '流通市值', '每股收益', '总市值'] 278 | csv_file = open(self.prifix+'沪深A股.csv', 'w', newline='') 279 | writer = csv.writer(csv_file) 280 | writer.writerow(file_header) 281 | 282 | list = self.data['list'] 283 | sum = len(list) 284 | for i in tqdm(range(0, sum)): 285 | item = list[i] 286 | 287 | # 处理股票代码, 去掉网易财经的0/1前缀, 并使其在Excel中显示正常(加`) 288 | code = str(item['CODE']) 289 | code = code[1:7] if len(code) == 7 else code[:] 290 | code = "`" + code 291 | 292 | row = [code, item['NAME'], item['MCAP'], item['MFSUM'], item['TCAP']] 293 | csv_file = open(self.prifix + '沪深A股.csv', 'a', newline='') # 追加 294 | writer = csv.writer(csv_file) 295 | writer.writerow(row) 296 | 297 | 298 | if __name__ == '__main__': 299 | controller = Controller() 300 | controller.get_data() 301 | ``` 302 | 303 | #### 1.2.2.2. **获取日线数据** 304 | 305 | 网易财经的日线交易数据可在[http://quotes.money.163.com/trade/lsjysj_601318.html#06f01](http://quotes.money.163.com/trade/lsjysj_601318.html#06f01)查看, 需要将`url`中的`601318`替换成相应的股票代码, 在这个页面没有换页按钮, 仅显示若干条数据, 但是在数据表的右上角有个`下载数据`的链接, 点击后, 需要勾选需要下载的字段, 点击下载后会下载一个`code.csv`文件, 所以要做的就是抓取下载的真实`url`, 按`F12`打开开发者工具, 点击下载按钮后, 在控制台看到如下提示: 306 | 307 | ![网易财经下载数据控制台捕获](./assets/imgs/201904271817.png) 308 | 其中已经包含了请求的真实地址, 即: 309 | 310 | ```js 311 | "http://quotes.money.163.com/service/chddata.html?code=0601318&start=20070301&end=20190426&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP" 312 | ``` 313 | 314 | 而想要搞清楚url的参数, 可以转到`submit`的文件, 这里即`b.667271.min.js:1`, 这是一个压缩的js文件, 格式化后, 在最后可以找到如下关键代码: 315 | 316 | ```js 317 | submit: function() { 318 | var e = n.value; 319 | if (e) e = e.replace(/-/g, ""); 320 | var a = i.value; 321 | if (a) a = a.replace(/-/g, ""); 322 | var o = t.elem.getElementsByTagName("input"), 323 | r = []; 324 | for (var d = 0; d < o.length; d++) { 325 | if (o[d].type == "checkbox" && o[d].checked) { 326 | r.push(o[d].value) 327 | } 328 | } 329 | var c = "/service/chddata.html?code=" + window["STOCKCODE"]; 330 | e && /^\d{8}$/.test(e) && (c += "&start=" + e); 331 | a && /^\d{8}$/.test(a) && (c += "&end=" + a); 332 | r.length && (c += "&fields=" + r.join(";")); 333 | location.href = c 334 | } 335 | ``` 336 | 337 | 能够清楚地看到url的拼接过程, 具体参数如下: 338 | 339 | 编号 | 参数 | 解释 | 规范 340 | :--: | :--: | :--: | :--: 341 | 1 | start | 起始日期 | 年月日直接拼接,如`20190427`,不足2位补0 342 | 2 | end | 截止日期 | 年月日直接拼接,如`20190427`,不足2位补0 343 | 3 | fields | 即需要下载的字段 | 使用`;`分割,如:`TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP` 具体意义不作详述 344 | 4 | code | 股票代码 | 关于股票代码, 网易财经的股票代码在传参时, 如果是以`6`开头的股票, 需要在前面加`0`, 而以`0`和`3`开头的股票需要在前面加`1`,如:`1000333`, `1300001`, `0601318` 345 | 346 | 接下来是做抓取, 抓取就是根据已经获取的**股票代码**, 枚举股票代码并下载对应的日线数据, 仅需注意每次循环最好使用`time.sleep(random.random()*2)`, 否则可能因操作频繁被拒绝访问;下面是部分源代码(注: 这里源代码中的股票代码是实时获取的, 抓取的是**股城网**, 因为只需要抓取股票代码即可): 347 | 348 | ```py 349 | import random 350 | import time 351 | 352 | from stock.classes.Downloader import Downloader 353 | from stock.classes.Parser import Parser 354 | from stock.classes.Saver import Saver 355 | 356 | # 控制器 357 | class Controller(object): 358 | 359 | # 构造函数 360 | def __init__(self, url, kline_filepath, codelist_filepath, date): 361 | ''' 362 | :param url: 股票基本信息url( 股城网>行情>沪深A股 ) 363 | :param kline_filepath: 日线数据文件保存路径 364 | :param codelist_filepath: 股票代码文件保存路径 365 | :param date: 查询截止日期 366 | ''' 367 | self.url = url 368 | self.kline_filepath = kline_filepath 369 | self.codelist_filepath = codelist_filepath 370 | self.date = date 371 | self.downloader = None # 下载器实例 372 | self.parser = None # 解析器实例 373 | self.saver = Saver() # 存储器实例 374 | 375 | # 执行函数 376 | def start(self): 377 | page = 1 378 | all_code = [] 379 | while page <= 181: 380 | print("当前为第%s页" % page) 381 | time.sleep(random.random()*2) 382 | self.downloader = Downloader(self.url % page) 383 | page += 1 384 | html_content = self.downloader.download() 385 | self.parser = Parser(html_content) 386 | codeList = self.parser.parseSharesCode() 387 | for code in codeList: 388 | all_code.append(code) 389 | # print(codeList) 390 | self.saver.saveKlineToCSV(codeList=codeList, filepath=self.kline_filepath, date=self.date) 391 | self.save(codelist=all_code) 392 | 393 | def save(self,codelist): 394 | self.saver.saveCodeListToCSV(codeList=codelist, filepath=self.codelist_filepath) # 保存代码到csv 395 | # self.saver.saveKlineToMySQL(filepath=self.kline_filepath) # 保存所有股票的信息到数据库 396 | 397 | 398 | # 程序入口 399 | if __name__ == '__main__': 400 | url = 'https://hq.gucheng.com/HSinfo.html?en_hq_type_code=&sort_field_name=px_change_rate&sort_type=desc&page=%s' # 股城网>行情>沪深A股 401 | kline_filepath = 'F:\\files\\sharesDatas\\dayline\\' # 定义数据文件保存路径 402 | codelist_filepath = 'F:\\files\\sharesDatas\\code_list\\' # 定义数据文件保存路径 403 | controller = Controller(url=url, kline_filepath=kline_filepath, codelist_filepath=codelist_filepath, date='20190428') 404 | controller.start() 405 | ``` 406 | 407 | 项目地址: [https://github.com/CatsJuice/netease-stock-day-line](https://github.com/CatsJuice/netease-stock-day-line)) 408 | 409 | `或者:` 410 | 411 | ```bash 412 | git clone https://github.com/CatsJuice/netease-stock-day-line.git 413 | ``` 414 | 415 | #### 1.2.2.3. **网易财经财务数据** 416 | 417 | 网页url为[http://quotes.money.163.com/f10/zycwzb_601318.html#01c01](http://quotes.money.163.com/f10/zycwzb_601318.html#01c01), 可以看到同交易日线数据一样, 这里有一个下载数据的按钮, 对应`盈利能力`, `偿还能力`等, 而这里直接通过开发者工具审查元素, 即可看到超链接的`href`:`/service/zycwzb_601318.html?type=report&part=ylnl`, 很快, 就能拿到完整的`url`, 然后操作同网易日线数据, 项目地址同样位于[https://github.com/CatsJuice/netease-stock-day-line](https://github.com/CatsJuice/netease-stock-day-line)) 418 | 419 | ### 1.2.3. **东方财富** 420 | 421 | #### 1.2.3.1. **股票信息列表** 422 | 423 | 因为没找到合适的页面, 实时资金流向排行[http://data.eastmoney.com/zjlx/detail.html](http://data.eastmoney.com/zjlx/detail.html)爬取所有沪深A股代码, 这里不作详述; 424 | 425 | #### 1.2.3.2. **交易数据, 财务数据** 426 | 427 | 东方财富的交易数据/财务数据我也尝试过使用爬虫爬取, 但是还是要走不少弯路的, 而且可能最后还没成功, 首先, 东方财富的数据页面和其他平台一样, 股票代码在url中, 如[http://data.eastmoney.com/bbsj/yjbb/600175.html](http://data.eastmoney.com/bbsj/yjbb/600175.html), 直接爬取, 或者使用开发者工具定位页面元素会发现: 428 | 429 | ![东方财富页面元素审查](./assets/imgs/201904271950.jpg "东方财富页面元素审查") 430 | 431 | 对应的数据是乱码的, 而如果继续挖掘其js文件, 是可以找到有加密的函数的,如下图所示: 432 | 433 | ![东方财富js加密](./assets/imgs/201904271953.png "东方财富js加密") 434 | 435 | 在这个名字特别明显直白的`js`文件`load_table_data_pc.js?201606021831`中, 可以看到加密, 解密的方法, 这也使得爬取成为可能, 但是太大费周章暂不考虑。 436 | 437 | # 2. **热点获取** 438 | 439 | ## 2.1. **东方财富** 440 | 441 | 这里我抓取的是东方财富的**国内经济要闻**, 页面地址位于[http://finance.eastmoney.com/news/cgnjj.html](http://finance.eastmoney.com/news/cgnjj.html) 442 | 443 | 这一页面的新闻列表不是通过Ajax异步加载的, 可以直接抓取, 而页码由url中`cgnjj_x`(x为页码)决定,抓取过程较为简单;这里统计的思路是, 将所有的要闻简述拼接成字符串(以`;`分隔并写入txt作备份), 然后利用`jieba`库分词并统计词频, 项目地址:[https://github.com/CatsJuice/eastmoney-yaowen-keyword](https://github.com/CatsJuice/eastmoney-yaowen-keyword) 444 | 445 | 也可以直接`clone`至本地 446 | 447 | ```bash 448 | git clone https://github.com/CatsJuice/eastmoney-yaowen-keyword.git 449 | ``` 450 | 451 | # 3. **数据分析** 452 | 453 | 在证券投资中, 有很多技术层面的投资策略, 如各种公式, 通过策略可以筛选出股票, 但并不意味着一定能盈利, 而量化投资可以验证这一策略的可靠性, 接下来就是我对若干策略的验证; 454 | 455 | ## 3.1. **换手率分析** 456 | 457 | 分析**连续处于低换手率**的股票, 脱离低换手率后, 出现**连续处于高换手率**, 判断2个时期的**收盘价**均价, 分析满足这一特征的股票的价格是否会上涨; 458 | 459 | 程序设计的思路如下 460 | 461 | - 迭代日线数据文件 462 | - 判断是否是连续高换手率 463 | - 判断是否在连续高换手率后出现连续低换手率 464 | - 结果展示 465 | 466 | **注:** 因为数据文件是按日期的倒序排序的, 所以分析迭代时, 先判断是否出现连续高换手率 467 | 468 | 核心代码如下: 469 | 470 | ```py 471 | high = [] 472 | low = [] 473 | for row in arr: 474 | rate = row[10] 475 | if rate == "None": 476 | high = [] 477 | low = [] 478 | continue 479 | if rate == 0: 480 | if len(high) >= self.min_days and len(low) >= self.min_days: 481 | dic = {'high': high, 'low': low} 482 | self.res.append(dic) 483 | high = [] 484 | low = [] 485 | continue 486 | rate = float(rate) 487 | # 4. 判断是否是 高 换手率 488 | if rate >= self.border_rate: 489 | # 4.3 判断是否是: 连续高 ->连续低 -> 结束连续低 490 | if len(low) >= self.min_days: 491 | # 符合条件, 写入 492 | dic = {'high': high, 'low': low} 493 | self.res.append(dic) 494 | high = [] 495 | low = [] 496 | elif len(low) > 0: # 连续低中有值 497 | # 不满足连续 低, 重置 498 | high = [] 499 | low = [] 500 | high.append(row) 501 | elif len(high) < self.min_days: # 是低换手率, 判断是否前面是连续高换手率 502 | # 4.1 前面不是连续的高换手率, 重置高换手率数组 503 | high = [] 504 | else: 505 | # 4.2 前面是连续高换手率, 地换手率写入 506 | low.append(row) 507 | 508 | # 判断日期是否已达到最后 509 | if row[0] <= self.end_date: 510 | # 判断是否满足条件 511 | if len(high) >= self.min_days and len(low) >= self.min_days: 512 | dic = {'high': high, 'low': low} 513 | self.res.append(dic) 514 | high = [] 515 | low = [] 516 | break 517 | ``` 518 | 519 | 简易流程图如下: 520 | 521 | ![流程图](./assets/imgs/mind201905012008.jpg "换手率程序设计流程图") 522 | 523 | [点此查看流程图原图](./assets/imgs/mind201905012008_origin.png) 524 | 525 | 程序可调整参数如下: 526 | 527 | No | param | type | meaning | demo 528 | :--:|:--:|:--: |:--: |:--: 529 | 1 | `file_path_prefix` | `str` | 日线数据目录前缀 | `'F:\\files\\sharesDatas\\kline\\'` 530 | 2 | `min_days` | `int` | 最小连续天数 | `10` 531 | 3 | `border_rate` | `float` | 换手率高低边界 | `2` 532 | 4 | `end_date` | `str` | 统计的最早日期 | `'2018-12-28'` 533 | 534 | 程序运行结果截图如下:201905012052.png 535 | 536 | ![screenshot](./assets/imgs/201905012052.png) 537 | 538 | 完整项目地址:[https://github.com/CatsJuice/low-switch-hand-rate](https://github.com/CatsJuice/low-switch-hand-rate) 539 | 540 | 或者: 541 | 542 | ```bash 543 | git clone https://github.com/CatsJuice/low-switch-hand-rate.git 544 | ``` 545 | 546 | ## 3.2. **CCI指标** 547 | 548 | ### 3.2.1. **概念** 549 | 550 | > 顺势指标又叫CCI指标,CCI指标是美国股市技术分析 家唐纳德·蓝伯特(Donald Lambert)于20世纪80年代提出的,专门测量股价、外汇或者贵金属交易是否已超出常态分布范围。属于超买超卖类指标中较特殊的一种。波动于正无穷大和负无穷大之间。但是,又不需要以0为中轴线,这一点也和波动于正无穷大和负无穷大的指标不同。 551 | 552 | ### 3.2.2. **指标用法** 553 | 554 | > `1`. 当`CCI`指标曲线在`+100`线~`-100`线的常态区间里运行时,`CCI`指标参考意义不大,可以用KDJ等其它技术指标进行研判。 555 | > 556 | > `2`. 当`CCI`指标曲线从上向下突破`+100`线而重新进入常态区间时,表明市场价格的上涨阶段可能结束,将进入一个比较长时间的震荡整理阶段,应及时平多做空。 557 | > 558 | > `3`. 当`CCI`指标曲线从上向下突破`-100`线而进入另一个非常态区间(超卖区)时,表明市场价格的弱势状态已经形成,将进入一个比较长的寻底过程,可以持有空单等待更高利润。如果`CCI`指标曲线在超卖区运行了相当长的一段时间后开始掉头向上,表明价格的短期底部初步探明,可以少量建仓。`CCI`指标曲线在超卖区运行的时间越长,确认短期的底部的准确度越高。 559 | > 560 | > `4`. `CCI`指标曲线从下向上突破`-100`线而重新进入常态区间时,表明市场价格的探底阶段可能结束,有可能进入一个盘整阶段,可以逢低少量做多。 561 | > 562 | > `5`. `CCI`指标曲线从下向上突破`+100`线而进入非常态区间(超买区)时,表明市场价格已经脱离常态而进入强势状态,如果伴随较大的市场交投,应及时介入成功率将很大。 563 | > 564 | > `6`. `CCI`指标曲线从下向上突破`+100`线而进入非常态区间(超买区)后,只要`CCI`指标曲线一直朝上运行,表明价格依然保持强势可以继续持有待涨。但是,如果在远离`+100`线的地方开始掉头向下时,则表明市场价格的强势状态将可能难以维持,涨势可能转弱,应考虑卖出。如果前期的短期涨幅过高同时价格回落时交投活跃,则应该果断逢高卖出或做空。 565 | 566 | ### 3.2.3. **公式** 567 | 568 | 关于公式有两种: 569 | 570 | #### 3.2.3.1. **公式一:** 571 | 572 | ```php 573 | TYP:=(HIGH+LOW+CLOSE)/3; 574 | CCI:(TYP-MA(TYP,N))/(0.015*AVEDEV(TYP,N)); 575 | ``` 576 | 577 | 该公式来自`通达信`, 含义如下: 578 | 579 | ```php 580 | TYP赋值:(最高价+最低价+收盘价)/3 581 | 输出CCI:(TYP-TYP的N日简单移动平均)/(0.015*TYP的N日平均绝对偏差) 582 | ``` 583 | 584 | #### 3.2.3.2. **公式二:** 585 | 586 | ![cci公式](./assets/imgs/201905022239.png?20100504_2 "cci") 587 | 588 | 该公式摘录于[https://www.joinquant.com/view/community/detail/219](https://www.joinquant.com/view/community/detail/219) 589 | 590 | 程序中我采用的是**公式二**, 生成的 `CCI` 指标追加到日线文件中, 在相应日期后增加 `CCI` 的值, 在 `Python` 中对 `csv` 文件进行增加列的方法, 在网上可找到的方法较少, 以下为一个提供了多种解决方案的, 较为完善的链接: [https://stackoverflow.com/questions/11070527/how-to-add-a-new-column-to-a-csv-file](https://stackoverflow.com/questions/11070527/how-to-add-a-new-column-to-a-csv-file), 我使用的是 `pandas` 库, 关键代码如下: 591 | 592 | ```py 593 | df = pd.read_csv(filename, encoding='gbk') 594 | df['cci'] = '' 595 | for index, row in pd.iterrows(): 596 | df.loc[index, 'cci'] = cci 597 | ``` 598 | 599 | ### 3.2.4. **程序设计** 600 | 601 | **总共设计了4个类如下**: 602 | 603 | - `CCIAnalyze(object)`        //  CCI分析类 604 | - `analyze_all(self)`     //  分析所有股票 605 | - `analyze_one(self)`     //  分析一只股票 606 | - `test_buy(self)`       //  测试购买(策略一:在下文说明) 607 | - `test_buy_2(self)`      //  测试购买(策略二:在下文说明) 608 | - `CCICalculate(object)`      //  根据[3.2.3. **公式**](#323-公式)中的公式二计算CCI 609 | - `CCICalculate_2(object)`    //  根据[3.2.3. **公式**](#323-公式)中的公式一计算CCI 610 | - `BuyInfo(object)`        //  购买辅助类 611 | 612 | ### 3.2.5. **参数说明** 613 | 614 | id | param | type | default | mean | demo | necessary 615 | :--: | :--: | :--: | :--: | :--: |:--: | :--: 616 | 1 | `file_path_prefix` | `str` | `None` | 日线数据文件目录前缀 | `'F:\\files\\sharesDatas\\kline\\'` | `True` 617 | 2 | `cci_path_prefix` | `str` | `None` | CCI数据将要保存的目录前缀 | `'F:\\files\\sharesDatas\\cci\\'` | `True` 618 | 3 | `code` | `str` / `int` | `None` | 股票代码 | `000001` | `False` 619 | 4 | `end_date` | `str` | `'0000-00-00'` | 最早的日期(截止日期) | `'2009-01-01'` | `False` 620 | 621 | > 项目地址: [https://github.com/CatsJuice/stock-cci](https://github.com/CatsJuice/stock-cci) 622 | 623 | 或者`clone`: 624 | 625 | ```bash 626 | git clone https://github.com/CatsJuice/stock-cci 627 | ``` 628 | 629 | ### 3.2.6. **测试结果** 630 | 631 | 在进行测试购买时, 采用的策略有2种,如下: 632 | 633 | **策略一**: 634 | 635 | 对应`CCIAnalyze(object)`中的`test_buy(self)`方法, 当`CCI`向下突破`-100`时, 后一交易日**买入**, 等到`CCI`向上突破`100`时, 后一交易日**卖出**(由于计算出当日的CCI, 当日已不可**买入/卖出**,所以计算后一交易日**买入/卖出**) 636 | 637 | **策略二**: 638 | 639 | 对应`CCIAnalyze(object)`中的`test_buy_2(self)`方法, 当`CCI`向下突破`-100`时, 继续观察, 等到向下达到第一个峰值时, 后一交易日**买入**,等到`CCI`向上突破`100`时, 继续观察, 等到向上达到第一个峰值时, 后一交易日**卖出**(和策略一一样, 计算出`CCI`后只能后一日买入, 而策略二不同的是, 要判断达到第一个峰值, 必须确定峰值后一日CCI降低, 所以测试时, 购买的是峰值的后`第2个`交易日) 640 | 641 | 经过若干次测试,分别使用的数据是`2019-01-01 ~ 2019-04-26`, `2018-01-01 ~ 2019-04-26`, `2017-01-01 ~ 2019-04-26`, 测试的结果, 购买策略一的收益率大概为`56%`, 可见这个指标有一定依据, 但是盈利的几率不够高; 而策略二的收益率大概为`57%`, 较策略一高一点, 但是依旧无法将其作为购买的唯一指标, 以下是某次运行结果的部分截图: 642 | 643 | ![CCI指标测试截图](./assets/imgs/201905031521.jpg "CCI指标测试截图") 644 | 645 | ## 3.3. **《胡立阳股票投资100招》** 由“价量关系”来为个股打分数 646 | 647 | ### 3.3.1. **概念** 648 | 649 | 胡立阳根据股票的`价量关系`对股票进行打分(第21招), 而其打分的依据如下: 650 | 651 | > **当日个股表现:** 652 | > 653 | >(1)价涨量增 `+2` 分 654 | > 655 | >(2)价涨量缩 `+1` 分 656 | > 657 | >(3)价跌量增 `-2` 分 658 | > 659 | >(4)价跌量缩 `-1` 分 660 | > 661 | > 每日累计评分。你只要连续计算一个星期,以最高分或者是评分稳定增加的作为你投资的第一选择,因为那只个股具备了“价量配合”的上涨条件 662 | 663 | ### 3.3.2. **程序设计** 664 | 665 | 根据以上打分标准, 不难计算每只股票某日的得分, 然后将所有得分排序即可, 这样能够得到某一天的所有股票打分, 而需要验证每只股票是否盈利, 这里我简单地判断后一天收盘价是否比当天高,所以能够得出每只股票是否盈利, 计算出当天得分前`n`只股票的盈利与否, 再用 盈利股票的只数 / n 即当天的盈利率; 666 | 667 | 以此类推`m`天可得出m天这一策略的盈利几率 668 | 669 | 程序流程图如下: 670 | 671 | ![StockScore_2.py简易流程图](./assets/imgs/mind201904281842.jpg "StockScore_2.py简易流程图") 672 | 673 | [点击此处查看流程图原图](./assets/imgs/mind201904281842.jpeg) 674 | 675 | 参数详情如下表 676 | 677 | id | param | type | mean | demo 678 | :--: | :--: | :--: | :--: | :--: 679 | 1 | `prefix` | str | 网易财经日线数据文件前缀 | `'F:\\files\\sharesDatas\\kline\\'` 680 | 2 | `date_now` |str| 最新数据的第一个日期, 对应爬取的最新数据表第一行的日期 | `'2019-04-26'` ; Format( `yyyy-mm-dd` ) 681 | 3 | `days` | int | 加分的天数 | `5` 682 | 4 | `calculate_days` | int | 要统计的天数 | `20` 683 | 5 | `best_num` | int | 选出的最佳的天数 | `10` 684 | 685 | ### 3.3.3. **结果** 686 | 687 | ![胡立阳打分标准盈利率](./assets/imgs/201904281250.png "胡立阳打分标准盈利率") 688 | 689 | > **键值说明:** 690 | > 691 | > `date`: 统计的日期 692 | > 693 | > `rate_low`: 打分最低的盈利几率 694 | > 695 | > `rate_high`: 打分最高的盈利几率 696 | 697 | 在分别统计了每个分数的股票的盈利率, 和排名靠前的股票的盈利率来看, 胡立阳的打分欠缺科学性, 盈利率不稳定, 不建议做参考; 698 | 699 | ### 3.3.4. **Source Code** 700 | 701 | 项目地址: [https://github.com/CatsJuice/stock-price-num-score](https://github.com/CatsJuice/stock-price-num-score) 702 | 703 | 直接`clone`: 704 | 705 | ```bash 706 | git clone https://github.com/CatsJuice/stock-price-num-score.git 707 | ``` 708 | 709 | ## 3.4. **移动平均线分析** 710 | 711 | ### 3.4.1. **概念** 712 | 713 | > 移动平均线,`Moving Average`,简称 `MA`, `MA` 是用统计分析的方法,将一定时期内的证券价格(指数)加以平均,并把不同时间的平均值连接起来,形成一根 `MA` ,用以观察证券价格变动趋势的一种技术指标。 714 | 715 | 常见的均线有5日均线(MA5), 十日均线(MA10), 二十日均线(MA20), 三十日均线(MA30), 六十日均线(MA60) 716 | 717 | ### 3.4.2. **计算** 718 | 719 | 在这里, 我的计算方法是简单地计算 n 日内的 **收盘价** 的`算数平均值` 720 | 721 | ### 3.4.3. **程序设计** 722 | 723 | **基本思路如下**: 724 | 725 | - 定义要计算的几日(假设为n)均线数组, 进行遍历计算 726 | - 迭代文件列表 727 | - 打开某个文件, 选取 n 行, 计算这n行的 `收盘价` 总和 728 | - 迭代 `csv` 文件的每一行, 每次迭代, 将上述收盘价的总和减去首行, 追加新的一行 729 | - 计算 `ma` 并写入原文件 730 | 731 | 和之前计算cci不同, 这里不再做多余的迭代, 以此能大大提高效率 732 | 733 | ### 3.4.4. **参数说明** 734 | 735 | id | param | type | mean | demo | necessary 736 | :--: | :--: |:--: |:--: |:--: | :--: 737 | 1 | `file_path_prefix` |`str`| 日线数据文件目录前缀 | `'H:\\sharesDatas\\kline\\'` | `true` 738 | 2 | `code` | `int` / `str` |股票代码| `'000001'` | `false` 739 | 3 | `end_date` | `str` | 最早的日期(截止日期) | `'2019-01-01'` | `false` 740 | 4 | `all_n` | `Array` | 要计算的几日ma 数组 | `[5,10]` | `false` 741 | 742 | ### 3.4.5. **购买策略分析** 743 | 744 | #### 3.4.5.1. **策略一: '老太太选股法' 一根均线打天下** 745 | 746 | 购买的策略较为简单, 收盘价低于均线即买入, 将收盘价作为买入价格(假设第二个交易日开盘即买入), 收盘价高于均线即卖出, 同样将收盘价作为卖出价格 747 | 748 | #### 3.4.5.2. **策略二:'黄金交叉'和'死亡交叉'** 749 | 750 | **'黄金交叉'** 和 **'死亡交叉'** 的概念来自 **日均线** 的百度百科([https://baike.baidu.com/item/%E6%97%A5%E5%9D%87%E7%BA%BF/8784586?fr=aladdin](https://baike.baidu.com/item/%E6%97%A5%E5%9D%87%E7%BA%BF/8784586?fr=aladdin)) 751 | 752 | > 1、”黄金交叉” 753 | 当10日均线由下往上穿越30日均线,形成10日均线在上,30日均线在下时,其交叉点就是黄金交叉,黄金交叉是多头的表现,出现黄金交叉后,后市会有一定的涨幅空间,这是进场的最佳时机。 754 | > 755 | >2、”死亡交叉” 756 | 当10日均线由上往下穿越30日均线,形成30日均线在上,10日均线在下时,其交点称之为”死亡交叉”,”死亡交叉”预示空头市场来临,股市将下跌此时是出场的最佳时机。 757 | 758 | ### 3.4.6. **分析结果** 759 | 760 | #### 3.4.6.1. **老太太选股法** 761 | 762 | 对于'老太太选股法', 我分别测试了5日均线和10日均线(由于20日数据较大, 电脑处理太慢, 暂时不考虑), 最终得到的结果为: 763 | 764 | `ma5` 的盈利几率为`63.3132%`; 而 `ma10` 的盈利几率为`67.0026%` 765 | 766 | 以下是某次运行的截图: 767 | 768 | ![老太太选股测试结果](./assets/imgs/201905072238.png '老太太选股测试结果') 769 | 770 | 运行结果中, 可以发现, 无论是盈利或是亏损, 金额基本都在1元以内, 可见这一策略 首先具有一定的科学性, 同时风险也不是很大, 但盈利金额较高的可能性很小; 771 | 772 | 对此, 我增加了结果判断, 统计亏损 / 盈利 超过 1 元的比例, 以下是结果: 773 | 774 | **对于 `ma5`:** 775 | 776 | ![ma5的详情结果](./assets/imgs/201905072303.png 'ma5的详情结果') 777 | 778 | **对于 `ma10`:** 779 | 780 | ![ma10的详情结果](./assets/imgs/201905072311.png 'ma10的详情结果') 781 | 782 | **对于 `ma20`:** 783 | 784 | ![ma20的详情结果](./assets/imgs/201905081102.png 'ma20的详情结果') 785 | 786 | **对于 `ma30`:** 787 | 788 | ![ma30的详情结果](./assets/imgs/201905081112.png 'ma30的详情结果') 789 | 790 | **对于 `ma60`:** 791 | 792 | ![ma60的详情结果](./assets/imgs/201905081409.png 'm60的详情结果') 793 | 794 | 从更详细的结果可以看到, 无论盈利或亏损, 超过 1 元的概率都不大, 但是亏损的时候超过 1 元的概率比盈利大; 更有趣的是, 当 ma的计算天数越多, 盈利的几率越大, 由于一般看盘软件中仅提供了上述这些均线(`MA5`, `MA10`, `MA20`, `MA30`, `MA60`), 所以这里不再多更高的天数进行测试; 虽然天数越大时, 盈利几率越高, 但是从更细节数据可以看到, 盈利的情况大于1元的概率始终在 `10% ~ 15%`, 而亏损时超过 1 元的概率却表现出和天数正相关的趋势, 并且从 `24%` 跳跃到高达 `50%` 795 | 796 | #### 3.4.6.2. **'黄金交叉'和'死亡交叉'** 797 | 798 | 运行结果如图: 799 | 800 | !['黄金交叉'和'死亡交叉'结果](./assets/imgs/201905081642.png?20190508 '"黄金交叉"和"死亡交叉"结果') 801 | 802 | 对于这个结果的确是非常出乎意料, 这个盈利率低得感觉好像可以作为一个反向指标使用; 803 | 804 | 对于这个结果, 首先应该怀疑是自己的代码逻辑出现了问题, 于是我检查了关键代码如下: 805 | 806 | ```py 807 | # 前一天 ma30 > ma10 , 今天ma10 >= ma30 808 | if prev_row is not None and prev_row['ma30'] > prev_row['ma10'] and row['ma10'] >= row['ma30']: 809 | # 买入 810 | 811 | ... 812 | ... 813 | 814 | # 前一天 ma30 < ma10 , 今天ma10 <= ma30 815 | if prev_row['ma30'] < prev_row['ma10'] and row['ma10'] <= row['ma30']: 816 | # 卖出 817 | ``` 818 | 819 | 关键代码部分好像并没有什么逻辑问题, 但是不排除其他部分出现问题, 由于这个指标的预期过于不符, 我试着尝试了交换 **'黄金交叉'**和**'死亡交叉'**, 修改上述关键代码如下(其实就是把所有大小判断符号反置): 820 | 821 | ```py 822 | # 前一天 ma30 < ma10 , 今天ma10 <= ma30 823 | if prev_row is not None and prev_row['ma30'] < prev_row['ma10'] and row['ma10'] <= row['ma30']: 824 | # 买入 825 | 826 | ... 827 | ... 828 | 829 | # 前一天 ma30 > ma10 , 今天ma10 >= ma30 830 | if prev_row['ma30'] > prev_row['ma10'] and row['ma10'] >= row['ma30']: 831 | # 卖出 832 | ``` 833 | 834 | 以下为运行结果: 835 | 836 | !['黄金交叉'和'死亡交叉'反向结果](./assets/imgs/201905081711.png?20190508 '"黄金交叉"和"死亡交叉"反向结果') 837 | 838 | 这时候盈利率可以说是马马虎虎还算过得去了, 但是盈利率却还是不如 ‘老太太选股法’ 839 | 840 | ### 3.4.7. **Source Code** 841 | 842 | 项目地址:[https://github.com/CatsJuice/line-of-ma](https://github.com/CatsJuice/line-of-ma) 843 | 844 | 直接 `clone` : 845 | 846 | ```bash 847 | git clone https://github.com/CatsJuice/line-of-ma.git 848 | ``` 849 | 850 | ## 3.5. **分时数据 成交手分析** 851 | 852 | ### 3.5.1. **基本概念** 853 | 854 | > 成交手指的是每笔买卖流动的股票数量,现行股票交易所用`手`方便表示成交数量,一手相当于股票一百股,各类炒股软件中的成交量一般用`手`表示 855 | 856 | ### 3.5.2. **分析的形态** 857 | 858 | 当某日开盘初出现集中的大量 买入/卖出 , 即成交手出现连续峰值的情况(大概如下图所示情形), 分析该股在当日的趋势 859 | 860 | ![形态示例](./assets/imgs/20190516102436.png "形态示例") 861 | 862 | ### 3.5.3. **程序设计** 863 | 864 | 设计的关键, 是为了找出某日开盘时的集中峰值, 在这里我首先设定分界线, 默认 `10` 点前为开盘初, 统计全天的换手量平均值,以及开盘初的换手量平均值, 当开盘初的换手量大于全天的某倍数(默认为2)时, 即认定当日开盘初的换手量为集中峰值; 865 | 866 | 但将今日的换手量平均值作为比较, 在实际运用中可能无法实施, 所以另一策略是统计 前一日 的平均换手量作为参考(在此尚未实现) 867 | 868 | ### 3.5.4. **参数说明** 869 | 870 | no. | param | type | mean | format | default | necessary | demo 871 | :---|--------------------|---------------|----------------------|--------------|--------------|-----------|------------------------------------------------ 872 | 1 | `tick_file_prefix` | `str` | 分时数据文件目录前缀 | / | `none` | `true` | `"F:\\files\\sharesDatas\\tushare_tick_data\\"` 873 | 2 | `end_date` | `str` | 终止日期 | 'yyyymmdd' | `'00000000'` | `false` | `'20190426'` 874 | 3 | `end_time` | `str` | 开盘初的终止时间 | `'hh:mm:ss'` | `'10:00:00'` | `false` | `'11:00:00'` 875 | 4 | `multiple` | `int`/`float` | 设定倍数 | / | `2` | `false` | `2.5` 876 | 877 | ### 3.5.5. **结果及分析** 878 | 879 | 以下为不区分买盘或卖盘, 倍数为 2 时, 当天前后均价变化是否上涨的结果: 880 | 881 | ![3.5.5](./assets/imgs/201905181224.png "3.5.5结果") 882 | 883 | 而只考虑买盘时, 这个几率为34%, 只考虑卖盘时几率为47%, 可见开盘初集中的成交量不一定会导致今日价格走上升的趋势,但在这个部分的程序设计中, 分析得不是很到位, 首先实际中没法考虑当天后面的成交量情况, 所以更稳妥的方法应该是计算 **前一交易日的平均成交量** , 而在判断这这股票是否处于上涨的趋势时, 简单判断今日的前后均价也不是最不合理的。 884 | 885 | ### 3.5.6. **Source Code** 886 | 887 | 项目地址为:[https://github.com/CatsJuice/stock-volume-analyze](https://github.com/CatsJuice/stock-volume-analyze) 888 | 889 | 直接 `clone`: 890 | 891 | ```bash 892 | git clone https://github.com/CatsJuice/stock-volume-analyze.git 893 | ``` 894 | 895 | ## 3.6. **MACD** 896 | 897 | ### 3.6.1. **基本概念** 898 | 899 | #### 3.6.1.1. **MACD** 900 | 901 | 百度百科的解释: 902 | 903 | > `MACD` 称为异同移动平均线,是从双指数移动平均线发展而来的,由快的指数移动平均线( `EMA12` )减去慢的指数移动平均线( `EMA26` )得到快线 `DIF` ,再用 `2 ×(快线DIF-DIF的9日加权移动均线DEA)` 得到 **MACD柱** 904 | 905 | #### 3.6.1.2. **MACD 金叉** 906 | 907 | > `MACD` 指标是股票技术分析中一个重要的技术指标,由两条曲线和一组红绿柱线组成。两条曲线中波动变化大的是 `DIF` 线,通常为**白线**或**红线**,相对平稳的是 `DEA` 线(MACD线),通常为**黄线**。当 `DIF` 线上穿 `DEA` 线时,这种技术形态叫做 **`MACD金叉`**,通常为 **买入信号** 908 | 909 | #### 3.6.1.3. **MACD 死叉** 910 | 911 | > `DIF` 由上向下突破 `DEA`,为**卖出信号** 912 | 913 | ### 3.6.2. **程序设计** 914 | 915 | #### 3.6.2.1. **数据计算** 916 | 917 | 【MACD公式】 918 | 919 | 以下为通达信的公式: 920 | 921 | ```js 922 | DIF:EMA(CLOSE,SHORT)-EMA(CLOSE,LONG); 923 | DEA:EMA(DIF,MID); 924 | MACD:(DIF-DEA)*2,COLORSTICK; 925 | ``` 926 | 927 | 需要的变量参数为 `SHORT` , `LONG` , `MID`, 在通达信中默认分别为 `12` , `26` , `9`; 928 | 要计算 `MACD` ,关键在于求 `EMA`(指数移动平均值), 其公式如下: 929 | 930 | ![EMA公式](./assets/imgs/20190520111714.png "EMA公式") 931 | 932 | 其中, `α` 为平滑指数, 一般取 `2 / ( N + 1 )` 933 | 934 | 该公式是依赖于前一日的递归的计算,最大的问题便是第一天的 `EMA[yesterday]` 无法求得, 在程序设计时, 我将它设置为当日`收盘价`, 935 | 再求 `DIF`, 第一天的 `DIF` 就变成了 `0` (当日收盘价 - 当日收盘价), 而求 `DEA` (即 DIF 的 EMA) 时,第一天所需的 `DEA[yesterday]` 同样不知道, 将其设置为 `DIF` ( 即 0 )。 936 | 937 | 【性能优化之多线程】 938 | 939 | 由于数据量较大, 在这里我尝试使用 Python 的多线程进行分析, 添加了一个 `calculate_all_by_thread` 的方法, 接收 `1` 个参数(thread_num)即需要的线程数, 然后根据线程数动态创建线程, 将文件划分为等分的块分别计算, 创建线程部分的代码如下: 940 | 941 | ```py 942 | def calculate_all_by_thread(self, thread_num): 943 | file_list = os.listdir(self.file_prefix) 944 | file_count = len(file_list) 945 | offset = file_count / thread_num 946 | offset = math.ceil(offset) 947 | threads = [] 948 | for i in range(thread_num): 949 | start = i * offset 950 | end = (i+1) * offset if (i+1) * offset < file_count else -1 951 | thread = threading.Thread(target=self.calculate_block, args=(start, end)) 952 | threads.append(thread) 953 | for t in threads: 954 | t.setDaemon(True) 955 | t.start() 956 | t.join() 957 | ``` 958 | 959 | 这里我使用的 2 个线程进行计算, 实际测试速度虽然不是单线程的 2 倍,但是计算的时间上是有所优化的。 960 | 961 | 【数据存储】 962 | 963 | 在了解公式后, 便可迭代文件进行带入计算, 计算结果这里我采用的是将其写入原文件, 在列末尾追加新的 5 列: 964 | 965 | - `EMA26` (26根据传参而定) 966 | - `EMA12` (12根据传参而定) 967 | - `DIF` 968 | - `DEA` 969 | - `MACD` 970 | 971 | 【数据验证】 972 | 973 | 完成计算后, 有必要对计算结果进行验证, 这里, 我简单写了一个输出来进行简单验证, 该部分代码如下: 974 | 975 | ```py 976 | def verify_calculate(self, code): 977 | try: 978 | df = pd.read_csv(self.file_prefix + str(code) + '.csv', encoding='gbk') 979 | except: 980 | print('文件%s.csv打开失败' % code) 981 | return 982 | df = df[df.日期 > self.end_date] 983 | df = df[::-1] 984 | mid = [] 985 | dates = [] 986 | difs = [] 987 | deas = [] 988 | macds = [] 989 | color_macd = [] 990 | for index, row in df.iterrows(): 991 | mid.append(0) 992 | dates.append(row['日期']) 993 | difs.append(row['DIF']) 994 | deas.append(row['DEA']) 995 | macds.append(row['MACD']) 996 | if row['MACD'] > 0: 997 | color_macd.append('red') 998 | else: 999 | color_macd.append('green') 1000 | # 绘制图表 1001 | fig = plt.figure(dpi=128, figsize=(100, 6)) 1002 | plt.plot(dates, mid, c='blue') 1003 | plt.plot(dates, difs, c='yellow') 1004 | plt.plot(dates, deas, c='black') 1005 | plt.bar(dates, macds, color=color_macd) 1006 | plt.xticks(fontsize=5) 1007 | plt.xlabel('', fontsize=5) 1008 | fig.autofmt_xdate() 1009 | plt.show() 1010 | ``` 1011 | 1012 | 在对股票 `'000002'` 进行验证, 验证结果如下(上图为通达信MACD截图, 下图为程序输出的图片, 时间为`2018-01-01` ~ `2019-04-26`): 1013 | 1014 | ![2018-01-01 ~ 20019-04-26, 000002 macd验证](./assets/imgs/20190520.jpg "2018-01-01 ~ 20019-04-26, 000002 macd验证") 1015 | 1016 | 可以看到图形基本一致, 但是同样对股票 `000001` 进行验证, 结果如下: 1017 | 1018 | ![2018-01-01 ~ 20019-04-26, 000001 macd验证](./assets/imgs/201905201329.jpg "2018-01-01 ~ 20019-04-26, 000001 macd验证") 1019 | 1020 | 此时, 两图形基本没有重合, 原因是因为计算 `MACD` 时, 第一天的 `EMA`并不是前一天计算的,同样 `DEA` 也是, 而这里数据只计算了 `2018-01-01 ~ 2010-04-26`, 所以前面基本一致的时候, 是因为第一日刚好相近导致后面计算偏差不大, 对此, 应该不设置截止日期以保证数据的可靠性, 我将时间设置到了 `2014-01-01`, 重新验证 `000001` 得到如下: 1021 | 1022 | ![2018-01-01 ~ 20019-04-26, 000001 macd验证(修改后)](./assets/imgs/201905211027.jpg "2018-01-01 ~ 20019-04-26, 000001 macd验证(修改后)") 1023 | 1024 | 然后再随机抽取一直股票进行验证, 如下为 `600702` 的结果 1025 | 1026 | ![2018-01-01 ~ 20019-04-26, 600702 macd验证](./assets/imgs/201905211033.jpg "2018-01-01 ~ 20019-04-26, 600702 macd验证") 1027 | 1028 | #### 3.6.2.2. **数据分析** 1029 | 1030 | 这里主要是对 `MACD` 的分析, 所以以上计算的数据实际上只要用到 `MACD` , 对 `MACD` 柱满足以下形态的股票进行分析: 1031 | 1032 | ![MACD形态](./assets/imgs/20190521151217.png "MACD形态") 1033 | 1034 | 该形态需满足以下特点: 1035 | 1036 | - 出现连续的红色块(MACD > 0) 1037 | - 紧接着出现连续蓝色块(MACD < 0) 1038 | - 蓝色块小于第一个红色块 1039 | - 蓝色块后面跟着一个红色块, 且后一红色块大于前一红色块 1040 | 1041 | 在程序设计时, 使用的是迭代数据行, 通过 `if` 判断, 来定位上述的 3 个块, 在第三块大于第一块时即为符合条件的形态;大致思路是, 定义 3 个变量来标记 3 块的合计值: 1042 | 1043 | - red_1 1044 | - green_1 1045 | - red_2 1046 | 1047 | 判断三个块的条件分别为: 1048 | 1049 | - 块 1 :`green_1 == 0 and red_2 == 0` 1050 | - 块 2 :`red_1 != 0 and red_2 == 0` 1051 | - 块 3 :`red_1 != 0 and red_2 != 0 and green_1 != 0` 1052 | 1053 | ### 3.6.3. **参数说明** 1054 | 1055 | no. | param | type | mean | format | default | necessary | demo 1056 | :---|--------------------|---------------|----------------------|--------------|--------------|-----------|------ 1057 | 1 | `file_prefix` | `str` | 日线文件前缀 | / | `None` | `True` | `'F:\\files\\sharesDatas\\kline\\'` 1058 | 2 | `end_date` | `str` | 截止日期 |`yyyy-mm-dd` | '0000-00-00' | `False` | `'2019-01-01'` 1059 | 3 | `short` | `int` | 短期的天数 | / | `12` | `False` | `12` 1060 | 4 | `long` | `int` | 长期的天数 | / | `26` | `False` | `26` 1061 | 5 | `mid` | `int` | 计算`DEA`时, `DIF`的`EMA`天数| / | `9` | `False` | `9` 1062 | 6 | `count_max` | `int` | 判断后面的多少天涨跌情况| / | `5` | `False` | `10` 1063 | 7 | `count_border` | `int` | 设置最大天数内至少多少天涨才符合 | / | `3` | `False` | `6` 1064 | 1065 | ### 3.6.4. **function注释** 1066 | 1067 | - `calculate_noe` 1068 | - 计算单只股票的 `MACD` 、 `DIF` 、 `EMA` 、 `DEA` 1069 | - 需要参数: 1070 | - `code`: 股票的代码 1071 | - 返回值: 1072 | - `None` 1073 | - `calculate_all_by_thread` 1074 | - 通过多线程计算所有股票 1075 | - 需要参数: 1076 | - `thread_num`: 线程数量 1077 | - 返回值: 1078 | - `None` 1079 | - `calculate_block`: 1080 | - 计算指定代码块的股票 1081 | - 需要参数: 1082 | - `start`:块下标开始 1083 | - `end`: 块下标结束 1084 | - 返回值: 1085 | - `None` 1086 | - `verify_calculate` 1087 | - 验证计算的结果 1088 | - 需要参数: 1089 | - `code`: 股票的代码 1090 | - 返回值: 1091 | - `None` 1092 | - `analyze_macd_one`: 1093 | - 分析单只股票 的 `macd` 1094 | - 需要参数: 1095 | - `code`: 股票的代码 1096 | - 返回值: 1097 | - `None` 1098 | - `analyze_macd_by_thread`: 1099 | - 通过多线程分析所有股票 1100 | - 需要参数: 1101 | - `thread_num`: 线程数量 1102 | - 返回值: 1103 | - `None` 1104 | - `analyze_block`: 1105 | - 分析指定代码块的股票 1106 | - 需要参数: 1107 | - `start`:块下标开始 1108 | - `end`: 块下标结束 1109 | - 返回值: 1110 | - `None` 1111 | - `show_res`: 1112 | - 输出分析结果并写入相关文件 1113 | - 需要参数:`None` 1114 | - 返回值: `None` 1115 | 1116 | ### 3.6.5. **结果分析** 1117 | 1118 | 【某次结果截图】 1119 | 1120 | ![MACD分析结果截图](./assets/imgs/20190521155326.png "MACD分析结果截图") 1121 | 1122 | 计算 MACD 时候的传参均为默认, 即通达信公式中的默认值, 对上述情况进行分析得到的结果是, 后 10 天内至少 6 天比符合条件时涨了的比例约为 55% , 而如果将参数调整为 5 天内至少 3 天, 则比例降低到约47%, 而如果不是 MACD 的值计算有误的话, 可见这个 `MACD` 的指标并不是很可靠, 但可以调整计算 `MACD` 的参数的值 1123 | 1124 | ### 3.6.6. **Source Code** 1125 | 1126 | 项目地址: [https://github.com/CatsJuice/MACD-Analyze](https://github.com/CatsJuice/MACD-Analyze) 1127 | 1128 | 直接 clone: 1129 | 1130 | ```bash 1131 | git clone https://github.com/CatsJuice/MACD-Analyze.git 1132 | ``` 1133 | --------------------------------------------------------------------------------