├── readme.md ├── chap 3.ipynb ├── preface.ipynb ├── chap1.ipynb └── chap2.ipynb /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 随着zillionare 1.0上线,本教程将基于zillionare 1.0重写。zillionare 1.0提供了出色的性能体验。根据测试,初次同步6年的数据(30分钟及以上k线),仅需12分钟左右(DELL 620机型,电信100M宽带)。 3 | 4 | 本教程使用Jupyter Notebook的格式(即ipynb文件)。为了获得更好的阅读体验,您可以: 5 | 6 | 1. 从[解语科技](http://www.jieyu.ai)官网阅读本教程 7 | 2. 您还可以[下载](http://www.jieyu.ai/products/)安装zillionare 1.0容器发行版。安装完成后,将自带本教程,且环境都已配置好,您不仅可以阅读本教程,还可以修改、运行相关代码。 8 | 9 | 10 | 这份教程结合了作者自己在投资和开发大富翁过程中的一些思考,现在发布出来,与大家共同探讨。教程既探讨了如何构建一个高性能、分布式交易系统这样的工程问题,也探讨了如何准备数据,建立AI模型这样的算法问题,希望能以此为出发点,与同样从事AI量化交易的同行们进行交流。 11 | 12 | -------------------------------------------------------------------------------- /chap 3.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "auburn-medicare", 6 | "metadata": {}, 7 | "source": [ 8 | "# 第二章 交易日历和时间计算" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "id": "chicken-mexican", 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "20050104~20230209\n", 22 | "20050107~20230209\n", 23 | "20050131~20230209\n" 24 | ] 25 | } 26 | ], 27 | "source": [ 28 | "from omicron.core.timeframe import tf\n", 29 | "\n", 30 | "print(f\"{tf.day_frames[0]}~{tf.day_frames[-1]}\")\n", 31 | "\n", 32 | "print(f\"{tf.week_frames[0]}~{tf.week_frames[-1]}\")\n", 33 | "\n", 34 | "print(f\"{tf.month_frames[0]}~{tf.month_frames[-1]}\")" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "technological-auditor", 40 | "metadata": {}, 41 | "source": [ 42 | "在上面的API中,我们定义了行情数据的起始和结束区间。但是,在量化交易中,我们常常需要知道某个区间包含多少条数据记录。比如,当我们要计算2020年12月5日这一天,某支股票的季线、月线和10日线时,更方便的使用方法是指定结束日期,和要获取的记录条数。至于这段时间的起点是哪一天,我们并不特别关心。\n", 43 | "\n", 44 | "由于存在节假日休市的情况,在上述场景下,要正确地计算出起始日期就更困难了。因此,Omicron提供了一个`timeframe`模块,来帮助做时间帧方面的计算。" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "id": "annoying-differential", 50 | "metadata": {}, 51 | "source": [ 52 | "timeframe模块以数组的形式,提供了所有的交易日、周线收盘日和月线收盘日。\n", 53 | "\n", 54 | "可以看出,大富翁提供的日线帧从2005年1月4日开始,到2023年2月9日结束。不过,对于还没有到来的日子,具体某一天是交易日还是休市日,都还不确定,这个数据我们会实时更新的。\n", 55 | "\n", 56 | "周线和月线帧的最后结束日并没有对齐,当然由于这一天还非常遥远,所以这里的数据也没有对错之分。\n", 57 | "\n", 58 | "在大富翁里,你会经常看到时间帧的概念。因为对交易数据来说,数据总是在固定的时间点进行汇总,所以不应该使用普通意义上的时间概念。比如2019年1月4日的10时35分,对于1分钟线和5分钟线是有意义的,对于其它周期则是意义的。我们把这个时间点称作5分钟(或者1分钟)的一个时间帧。\n", 59 | "\n", 60 | "timeframe模块提供了以下主要功能:\n", 61 | "\n", 62 | "- int2time/time2int/date2int/int2date\n", 63 | " \n", 64 | " 在进程间及不同的模块间传递时间数据时常常容易发生问题,比如,你无法直接往redis缓存里存入时间数据。所以,大富翁使用整数来存储日期/时间。比如,20050104代表2005年1月4日,200501041030代表2005年1月4日10时30分钟。使用这种表示,比较节省内存,同时时间之间仍然可以比较,并没有改变它们之间的次序。\n", 65 | " \n", 66 | "- shift函数及衍生的各种*_shift函数\n", 67 | "\n", 68 | " 给定一个时间,比如2019年1月4日,如果我们需要知道4个交易日前的那一天是哪一天,这时候就需要使用shift/day_shift函数。\n", 69 | " \n", 70 | "- count_*_frames 计算两个时间帧之间共有多少个时间帧。\n", 71 | "- is_trade_day 判断某天是否是交易日\n", 72 | "- is_open_time 判断某个时间点是否处于开盘期间\n", 73 | "- is_opening_call_auction_time 判断某个时间点是否属于早盘集合竞价时段\n", 74 | "- is_closing_call_auction_time 判断某个时间点是否属于尾盘集合竞价时段\n", 75 | "- floor 根据frame_type,将给定的时间对齐到最接近的上一个frame\n", 76 | "- ceiling 对应于floor\n", 77 | "- frame_len 对给定的分钟级别线,求一个交易日包含多少个周期\n", 78 | "- first_frame 不同的周期,每天开盘的第一个时间帧是不一样的。比如对分钟线,第一个时间帧是9:31,对5分钟线则是9:35分。这个函数用于获得指定日期的对应周期的第一帧\n", 79 | "- get_frames 获取给定的起始时间和结束时间间,指定的周期对应的时间帧\n", 80 | "- get_frames_by_count,类似于get_frames,但参数不一样\n", 81 | "- combine_time 将指定的日期与时间结合成一个新的datetime\n", 82 | "\n", 83 | "这些功能非常基础,也十分重要。当您开始获取数据、编写策略时,会越来越依赖于它们。" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "id": "comparable-norwegian", 89 | "metadata": {}, 90 | "source": [ 91 | "Aha! jq提供的交易数据都是起始于2005年1月4日的。因此,如果你要追忆老八股当年的盛况,还得使用其它数据源。不过,对我们短线量化而言,这个数据已足够充分了。实际上,过久的历史数据如果不能正确使用,反倒会让你得出错误结论。比如,一些股票退市了,会导致幸存者偏差(幸运的是,为了不让你们出这种错误,村里很少让股票退市!);这期间发生的重大的制度改革(比如股权分置改革就是从2005年起的),则会对某些分析方法产生影响。当然,对于短线而言,我们只关心股价,我们认为一切因素都反映在股价里。所以只要股本变动、除权除息这些事都已正确记录的话,几乎仅凭行情数据本身,我们仍然可以分析出正确结论。" 92 | ] 93 | } 94 | ], 95 | "metadata": { 96 | "kernelspec": { 97 | "display_name": "Python 3", 98 | "language": "python", 99 | "name": "python3" 100 | }, 101 | "language_info": { 102 | "codemirror_mode": { 103 | "name": "ipython", 104 | "version": 3 105 | }, 106 | "file_extension": ".py", 107 | "mimetype": "text/x-python", 108 | "name": "python", 109 | "nbconvert_exporter": "python", 110 | "pygments_lexer": "ipython3", 111 | "version": "3.8.5" 112 | }, 113 | "toc": { 114 | "base_numbering": 1, 115 | "nav_menu": {}, 116 | "number_sections": true, 117 | "sideBar": true, 118 | "skip_h1_title": false, 119 | "title_cell": "Table of Contents", 120 | "title_sidebar": "Contents", 121 | "toc_cell": false, 122 | "toc_position": {}, 123 | "toc_section_display": true, 124 | "toc_window_display": true 125 | } 126 | }, 127 | "nbformat": 4, 128 | "nbformat_minor": 5 129 | } 130 | -------------------------------------------------------------------------------- /preface.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "documented-insurance", 6 | "metadata": {}, 7 | "source": [ 8 | "股价的涨跌预测一直是一个令人众里寻他千百度的热点话题。财经大V,老师和各类骗子每天乐此不疲,为韭菜供给\"养分\"。那么,股价真的可以预测吗?\n", 9 | "\n", 10 | "开写《大富翁量化交易教程》,也必须回答好这个问题。如果股价能否预测是个伪命题,这个开题就没有必要;但是如果股价可以预测,为什么连证券公司的某首席科学家又一直在出错?为什么一些长期绩优的基金经理坚持说自己不做择时操作?\n", 11 | "\n", 12 | "我们认为,股价运动固然有其复杂性,但就象万物运动一样有其规律,也遵循这个世界的普遍自然规律和经济学原理。在某种程度上,它也是可以预测的:\n", 13 | "\n", 14 | "- 惯性定律\n", 15 | "\n", 16 | "最早人类认识到机械运动的惯性特性,大概是从伽俐略时代开始。后来牛顿通过三大定律,完美地解释了低速状态下刚体运行的规律,从而成了为行星描绘轨迹的人。\n", 17 | "\n", 18 | "![艾萨克.牛顿](http://images.jieyu.ai/images/2020-10/gettyimages-90733811.jpg){: style=\"width:200px\" align=left }\n", 19 | "\n", 20 | "三大定律中的第一定律,指出任何物体都要保持匀速直线运动或静止状态,直到外力迫使它改变运动状态。\n", 21 | "\n", 22 | "在证券交易领域,惯性定律也同样适用。交易大师利弗莫尔这样说过:趋势一旦形成,就不会轻易改变,股价总是沿阻力最小的方向前进。这句许多交易者都耳熟能详的话,包含了两个自然规律:一是**惯性定律**,即趋势一旦形成,就不会轻易改变。二是梯度下降法则。\n", 23 | "\n", 24 | "量化交易就是要去发现当前的趋势是什么,以及梯度的方向是什么。\n", 25 | "\n", 26 | " - 钟摆定律(周期运动律)\n", 27 | "\n", 28 | "自然世界中有很多运动都是周期往复的,包括地球的自转本身就是一种周期。为了让人们直观地观测到地球的自转,著名法国物理学家莱昂.傅科设计了如下的一个钟摆,至今还在法国先贤祠里展示:\n", 29 | "\n", 30 | "![傅科摆](http://images.jieyu.ai/images/2020-10/1000.jpg){: style=\"height:200px\" align=right}\n", 31 | "\n", 32 | "这也是钟摆与周期的一种直观演示。实际上几乎所有的运动的轨迹,都可以通过不同频率和相位的正弦波叠加出来,而正弦波就是一个围绕中心点、周期往复的运动。\n", 33 | "\n", 34 | "同样的,在经济领域,经济的周期律更是为大家熟悉,这方面有许多皇皇巨著。\n", 35 | "\n", 36 | "钟摆定律在证券交易中的体现之一是,在允许投机的市场,价格并不必然等同于价值,但必定以价值为中心点进行上下波动。价格离价值中心越远,回归价值中心的力量就越强,就象一个钟摆一样运动。\n", 37 | "\n", 38 | "从长期来看,我们可以把PE(市盈率)当作股票价值的中枢;从短期来看,平均交易成本(即各种均线)也是一个很好的价值中枢。\n", 39 | "\n", 40 | "- 混沌效应\n", 41 | "\n", 42 | "![蝴蝶效应](http://images.jieyu.ai/images/202103/2fdda3cc7cd98d106fb8c64c2c3fb80e7bec905b.png){: style=\"height:200px\" align=left}\n", 43 | "\n", 44 | "混沌效应又称为蝴蝶效应。蝴蝶效应一词来自一个比喻,“一只南美洲亚马逊河流域热带雨林中的蝴蝶,偶尔扇动几下翅膀,可以在两周以后引起美国得克萨斯州的一场龙卷风”。它的含义是指,在一个动力系统中,初始条件下微小的变化能带动整个系统的长期的巨大的连锁反应。\n", 45 | "\n", 46 | "证券价格沿时间线的变化构成时间序列,时间序列分布遵循分形分布(【资本市场的混沌和秩序:一种关于周期、价格和市场波动的新观点 】,Peters等,1996年)。在处于平衡态的时间序列上,小级别的分形形态改变,将可能引发大级别的趋势改变,也即混沌效应。\n", 47 | "\n", 48 | "在量化交易策略中,要特别注意小级别的分形形态的改变对大级别趋势的引领作用。比如,日线级别的下跌,可能是由30分钟级别的滞涨和拐头引起的;老股民所熟知的长上影线出现后,可能导致激烈的洗盘,其实就是在更小的级别上,出现了向下的趋势。及时捕捉到小级别上的变化并退出市场,就可以避免更大的损失。\n", 49 | "\n", 50 | "混沌效应也许是量化交易中我们惟一可以做“预测”的地方。小级别周期上的趋势一旦形成,系统会越来越远离平衡态,进而带动大级别周期上趋势的形成。直到周期定律将趋势扭转。而这种扭转,毫无疑问仍然是率先从小级别周期上发生的。\n", 51 | "\n", 52 | "- 测不准原理\n", 53 | "\n", 54 | "![海森堡](http://images.jieyu.ai/images/202103/20210320222942.png){: style=\"width:200px\" align=right}\n", 55 | "\n", 56 | "在量子力学里,测不准原理是指粒子的位置与动量不可同时被确定,位置的不确定性越小,则动量的不确定性越大,反之亦然。之所以会出现测不准的现象,是因为当我们进行观测时,必然要通过与被观测者的交互和交换才能获得信息,而在这个交换的过程中,也就改变了被观测对象。很多低等生物没有眼睛,不能靠光来观测周围的世界。他们依靠气味等等来观察世界。气味的感知实质上是一种不可逆的化学反应。\n", 57 | "\n", 58 | "在股市中,交易者也就是观测者。他们投入或者取出资金,价格是被观测对象,赚或者赔是他们得到的观测结果。然而,每一次观测,都在影响着市场。比如,对一支流动性不足的证券品种,即使只花很少的钱来买入,也足以拉高股价(改变了被观测对象),从而失去了继续买入的前提条件。\n", 59 | "\n", 60 | "- 羊群效应\n", 61 | "\n", 62 | "在市场中,改变惯性运动的外力从何而来?趋势究竟是如何形成的?\n", 63 | "\n", 64 | "在投资市场中,大众的资金总是被少数有领导力的资金带动。这些有领导力的资金有更好的消息渠道(合法或者不合法)。他们得到消息后,进行预判,并通过操作来影响市场大众的判断,从而最终影响股价的波动。这就象头羊带动羊群一样。因此,改变惯性运动的外力就是这些资金。比如在2021年初,A股的下跌,正是由于海外第一大资金抛售茅台和新能源车带动的。\n", 65 | "\n", 66 | "到此为止,左右股价运行的基本原理就介绍完毕。\n", 67 | "\n", 68 | "如果左右股价的基本原理都已发现,为什么到目前为止,仍然不能象欧几里德建立他的几何王国,牛顿预言行星的运动一样,预测股价的波动呢?原因也正在这些原理本身。\n", 69 | "\n", 70 | "首先,测不准原理告诉我们,一个好的策略一定是不为大众所知的。所以,即使有一个好的数学方法,一旦它得以公开,就基本失去了作用。一些经典的技术指标现在之所以用得越来越少,这是原因之一。\n", 71 | "\n", 72 | "第二,当新的消息(外力)出现时,股价会出现突变,从而构成数学上的不连续性。一个不连续的系统是不可微的,也难以使用经典的数学分析方法来分析。一个例外是近来比较流行的策略是动量策略,它本质上是对惯性定律的使用,也只在短时间内有效,需要根据行情的演进不断地修正预测。\n", 73 | "\n", 74 | "第三,在大数据和人工智能出现之前,预测股价还存在算力上的不可行。由于机器学习可以从数据中学习特征,因此可以及时跟上市场的变化。而传统的分析方式需要依靠人工观察市场变化,提取市场特征。一旦某种市场特征被观察到进入应用,很快又会因为测不准原理而失效,所以量化方法就难以大规模使用。牛顿曾经在投资南海公司失败后喟叹,我能计算出行星的轨迹,却无法计算出人心的疯狂。牛顿是微积分大师,他在投资上的失败,也说明经典的数学分析方法在股市上难以有所作用。但如果当年他就拥有大数据和人工智能加持,或许这位人类最伟大的科学家,造币厂的厂长,还会成为投资界的一个传奇吧?\n", 75 | "\n", 76 | "进入2021年,无论是A股的专业投资者,还是准专业投资者,都需要接触量化交易。因为A股正在放开涨跌停限制,交易制度也即将由T+1改为T+0。在新的交易制度下,留给投资者思考的时间更短,而程序交易将有先天优势。甚至对于业余投资者,也可能需要了解一些量化交易,因为量化交易平台将会越来越多,最先上车的投资者必将从中受益。\n", 77 | "\n", 78 | "在这部教程里,我们不光讲量化交易,而且讲如何通过最先进的人工智能来学习和理解市场变化,寻找适应于当下市场的最佳交易策略和模型。\n", 79 | "\n", 80 | "全部教程共分两个部分,第一部分是数据预处理,包括如何获得使用大富翁获得行情数据,如何使用基础的技术分析函数,如何将行情数据可视化。这一部分是所有的量化交易,无论是否基于人工智能,都需要掌握的基础。\n", 81 | "\n", 82 | "第二部分的重点是如何通过人工智能来学习交易策略。我们将首先介绍一些量化因子,然后是基础的机器学习算法:我们将使用sklearn机器学习算法库,并且给出一些经验证有效的模型。然后我们将进入深度学习的领域。我们将使用Pytorch和FastAI来构建算法模型,目前已安排的有基于CNN和Transformer两种架构的神经网络模型。\n", 83 | "\n", 84 | "作者正在构建自己的人工智能交易系统,所以用到的代码示例都来自于实战代码,因此这个教程的干货很多。这个教程另一个独特的地方是,作者除了会写代码之外,还有十多年的证券投资经验,所以在本教程中,你也会看到不少证券交易的经验之谈。离开领域知识谈技术,最终都是隔靴搔痒。\n", 85 | "\n", 86 | "现在,就请跟随我们一起去探索吧!" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "id": "elect-current", 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [] 96 | } 97 | ], 98 | "metadata": { 99 | "kernelspec": { 100 | "display_name": "zillionare", 101 | "language": "python", 102 | "name": "zillionare" 103 | }, 104 | "language_info": { 105 | "codemirror_mode": { 106 | "name": "ipython", 107 | "version": 3 108 | }, 109 | "file_extension": ".py", 110 | "mimetype": "text/x-python", 111 | "name": "python", 112 | "nbconvert_exporter": "python", 113 | "pygments_lexer": "ipython3", 114 | "version": "3.8.8" 115 | }, 116 | "toc": { 117 | "base_numbering": 1, 118 | "nav_menu": {}, 119 | "number_sections": true, 120 | "sideBar": true, 121 | "skip_h1_title": false, 122 | "title_cell": "Table of Contents", 123 | "title_sidebar": "Contents", 124 | "toc_cell": false, 125 | "toc_position": {}, 126 | "toc_section_display": true, 127 | "toc_window_display": true 128 | } 129 | }, 130 | "nbformat": 4, 131 | "nbformat_minor": 5 132 | } 133 | -------------------------------------------------------------------------------- /chap1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 证券列表、板块和K线数据" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "欢迎来到大富翁量化教程第一章。在这一章里,我们将学习如何获取市场证券列表和概念板块,以及获取某一支证券的K线数据。在文章最后部分,我们还将介绍一个有一定实用价值的交易策略。\n", 15 | "\n", 16 | "这些功能是编写交易系统的起点。如果您想要制定一个覆盖全市场的交易策略,您就需要知道如何获取所有的证券列表,并且一一获取它们的k线数据,进行运算,最后发出交易信号。\n", 17 | "\n", 18 | "此外,如果您觉得最近有值得关注的概念板块,您也可能只想关注这些概念板块里的证券品种,这是一种手工化的、但行之有效的优化。" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "## 初始化Omicron" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 95, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "from IPython.display import clear_output\n", 35 | "from omicron.core.types import FrameType\n", 36 | "from omicron.core.timeframe import tf\n", 37 | "import cfg4py\n", 38 | "from omega.config import get_config_dir\n", 39 | "\n", 40 | "cfg4py.init(get_config_dir())\n", 41 | "import omicron\n", 42 | "await omicron.init()\n", 43 | "clear_output()" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "首先,这段代码引入了omicron这个核心库。Omicron主要负责数据的读写,基础量化因子的计算,还提供了大富翁中的一些核心类型的定义,比如帧类型(FrameType),时间帧的相关计算(timeframe)等等。\n", 51 | "\n", 52 | "这里还出现了[cfg4py](https://pypi.org/project/cfg4py/)。Cfg4Py是一个非常好用的配置管理工具,提供了配置热更新、代码提示和自动完成、环境变量替换、多部署环境自适应、层级式配置管理(cascading)、配置模版等功能。\n", 53 | "\n", 54 | "Zillionare使用了Cfg4Py来管理配置。上面的第6行中,我们先对配置模块进行初始化。这让Omicron可以知道数据库和缓存的连接信息。关于这部分是如何工作的,请参见[TODO://diveintozillionare/configure](404.md)。如果您是使用我们提供的docker运行环境,那么您完全不用在意这些配置信息。只需要知道要使用Omicron,必须先进行配置初始化就可以了。" 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "然后我们通过`omicron.init()`来对omicron进行初始化。初始化完成以后,证券列表就加载到程序中,数据库、缓存的连接也就都建立好了。\n", 62 | "\n", 63 | "??? Tips\n", 64 | " 注意大富翁里很多函数都是异步的,您需要通过`await`关键字来进行调用 。" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "## 证券列表\n", 72 | "现在,让我们看看都有哪些证券品种。" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 96, 78 | "metadata": {}, 79 | "outputs": [ 80 | { 81 | "data": { 82 | "text/html": [ 83 | "
\n", 84 | "\n", 97 | "\n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | "
012345
0000001.XSHE平安银行PAYH1991-04-032200-01-01stock
1000001.XSHG上证指数SZZS1991-07-152200-01-01index
2000002.XSHE万科AWKA1991-01-292200-01-01stock
3000002.XSHGA股指数AGZS1992-02-212200-01-01index
4000003.XSHGB股指数BGZS1992-02-212200-01-01index
\n", 157 | "
" 158 | ], 159 | "text/plain": [ 160 | " 0 1 2 3 4 5\n", 161 | "0 000001.XSHE 平安银行 PAYH 1991-04-03 2200-01-01 stock\n", 162 | "1 000001.XSHG 上证指数 SZZS 1991-07-15 2200-01-01 index\n", 163 | "2 000002.XSHE 万科A WKA 1991-01-29 2200-01-01 stock\n", 164 | "3 000002.XSHG A股指数 AGZS 1992-02-21 2200-01-01 index\n", 165 | "4 000003.XSHG B股指数 BGZS 1992-02-21 2200-01-01 index" 166 | ] 167 | }, 168 | "execution_count": 96, 169 | "metadata": {}, 170 | "output_type": "execute_result" 171 | } 172 | ], 173 | "source": [ 174 | "import pandas as pd\n", 175 | "secs = await omicron.models.securities.get_security_list()\n", 176 | "pd.DataFrame(data=secs[:5])" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "返回值包括证券代码(如000001.XSHG),证券名称(如平安银行,上证指数等),证券简码(如PAYX),该证券的上市交易日,终止上市时间,以及证券类型。\n", 184 | "\n", 185 | "最后一栏是证券类型。大富翁支持的证券类型主要有股票(stock),指数(index),对于ETF基金(etf),此外还有分级(fja,fjb,fjm),场内交易货币基金和其它基金。目前大富翁只接入了聚宽一家数据源,聚宽是支持这些类型的,所以大富翁当下也因此支持这些类型定义。不过,这部分定义未来可能会有所更改。但是,对于`stock`和`index`的定义,会一直保持不变。\n", 186 | "\n", 187 | "这里提示一下关于上市交易日和终止上市时间的使用。在做短线交易时,我们并不需要获取那些已退市证券的数据,这时就要使用终止上市时间来进行过滤。有时候为了获取足够长的数据来进行演算,我们也需要使用上市交易日来过滤掉一些刚上市不久、数据还不够充分的数据。\n", 188 | "\n", 189 | "证券代码在不同的行情软件中,表示方法并不一致。上交所和深交所原始数据中,并没有上述代码中的\".XSHG\"这样的后缀,因此,000001这样的代码在不同的市场上可能都存在,只是含义不同。比如000001在上交所这边代表上证指数,而在深交所则代表平安银行。如果你拿到的是这样的数据,则需要先进行转码处理。在大富翁的数据中,我们使用了带交易所编号的全码,这样处理是比较恰当的。每个证交所都会保证自己的编码系统的惟一性,因此这个全码就惟一标识了一支证券品种。\n", 190 | "\n", 191 | "上面的代码中引入了pandas这个库。这里并不是必须的,我们在这里引用它,只是通过它可以使得输出更整洁美观一点。\n", 192 | "\n", 193 | "`omicron.models.securities.get_security_list()`返回的数据类型是numpy数组。在zillionare中,更广泛使用的数据结构是numpy的structured array,与dataframe相比,它在易用性、性能和内存占用上,都更加有优势。当然,这个对比仅限于行情数据处理这个场景。在其它场景下,也可能dataframe更有优势。" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "metadata": {}, 199 | "source": [ 200 | "我们常常通过Securities这个类来操作证券列表,而不是直接使用`get_security_list`这个接口。" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 97, 206 | "metadata": {}, 207 | "outputs": [ 208 | { 209 | "data": { 210 | "text/plain": [ 211 | "['000001.XSHG', '000002.XSHG', '000003.XSHG']" 212 | ] 213 | }, 214 | "execution_count": 97, 215 | "metadata": {}, 216 | "output_type": "execute_result" 217 | } 218 | ], 219 | "source": [ 220 | "from omicron.models.securities import Securities\n", 221 | "\n", 222 | "secs = Securities()\n", 223 | "secs.choose(['index'])[:3]" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "通过上面的代码,我们从全市场中选择了指数型标的。\n", 231 | "\n", 232 | "现在,让我们来看看如何以更简单的方式来访问证券的基本属性:" 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 98, 238 | "metadata": {}, 239 | "outputs": [ 240 | { 241 | "name": "stdout", 242 | "output_type": "stream", 243 | "text": [ 244 | "000001.XSHE 平安银行 1991-04-03 2200-01-01 PAYH\n" 245 | ] 246 | } 247 | ], 248 | "source": [ 249 | "from omicron.models.security import Security\n", 250 | "\n", 251 | "sec = Security('000001.XSHE')\n", 252 | "\n", 253 | "# 显示证券代码、名称、IPO日期,终止上市日期,拼音简称\n", 254 | "print(sec.code, sec.display_name, sec.ipo_date, sec.end_date, sec.name)" 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "metadata": {}, 260 | "source": [ 261 | "如果我们需要判断一支证券标的是否为次新股,那么可以通过`sec.days_since_ipo`来得到其信息:" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 99, 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "data": { 271 | "text/plain": [ 272 | "3944" 273 | ] 274 | }, 275 | "execution_count": 99, 276 | "metadata": {}, 277 | "output_type": "execute_result" 278 | } 279 | ], 280 | "source": [ 281 | "sec.days_since_ipo()" 282 | ] 283 | }, 284 | { 285 | "cell_type": "markdown", 286 | "metadata": {}, 287 | "source": [ 288 | "\n", 289 | "## 概念分类\n", 290 | "\n", 291 | "除了上述基本属性外,证券(股票)还会有自己的行业属性、地域属性(总部或者注册地),概念(题材)等属性。除此之外,象通达信软件,还会给每支股票打上风格属性,比如\"新股\"、\"近期强势\"、\"超跌\"等。\n", 292 | "\n", 293 | "???+ Tips\n", 294 | " 在A股,市场炒作气氛浓郁时,会发生炒地图(比如自贸区、成渝规划)、炒概念(比如2020年的免税、地摊)、炒行业(比如2020年下半年的炒作的光伏既是题材概念、也是行业景气概念。光伏景气是一个行业全产业链的景气)。对短线炒题材的选手来说,如何蹭到具有多个概念的股票,是很重要的选股策略。\n", 295 | "\n", 296 | " 大富翁在1.0中并未提供这些概念分类,因为我们的目标是为量化交易提供高性能的计算平台,基于优选级考虑,对性能要求不高,其它工具已经有的功能,就可能放在后面的版本来实现。但是,由于大富翁集成了jqdatasdk,jqdatasdk的这些功能,对您来说也是完全开箱即用的。\n", 297 | "\n", 298 | "这里我们以如何找出同时具有多个概念的个股为例,来讲解聚宽相关的API。\n", 299 | "\n", 300 | "假设我们要获取具有\"智能电网\"、\"物联网”概念属性的深圳本地股:" 301 | ] 302 | }, 303 | { 304 | "cell_type": "code", 305 | "execution_count": 100, 306 | "metadata": {}, 307 | "outputs": [], 308 | "source": [ 309 | "# 获取地域。这里要使用finance中的查询\n", 310 | "import os\n", 311 | "import jqdatasdk as jq\n", 312 | "\n", 313 | "account = os.environ['JQ_ACCOUNT']\n", 314 | "password = os.environ['JQ_PASSWORD']\n", 315 | "jq.auth(account, password)" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "首先,我们要引入jqdatasdk这个库,并且完成登录。\n", 323 | "\n", 324 | "完成登录需要提供您在聚宽平台上面注册的账号和密码。我们这里使用的方法是,通过环境变量设置您的聚宽账号和密码,然后通过`os.environ`来获取它们。这是一种出于安全考虑的技巧:即使您分享了您的策略,也不会意外泄露您的账号和密码。" 325 | ] 326 | }, 327 | { 328 | "cell_type": "code", 329 | "execution_count": 101, 330 | "metadata": {}, 331 | "outputs": [ 332 | { 333 | "data": { 334 | "text/html": [ 335 | "
\n", 336 | "\n", 349 | "\n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | "
display_namenamestart_dateend_datetypeprovincecity
000001.XSHE平安银行PAYH1991-04-032200-01-01stock广东深圳市
000002.XSHE万科AWKA1991-01-292200-01-01stock广东深圳市
000004.XSHE国华网安GHWA1990-12-012200-01-01stock广东深圳市
\n", 395 | "
" 396 | ], 397 | "text/plain": [ 398 | " display_name name start_date end_date type province city\n", 399 | "000001.XSHE 平安银行 PAYH 1991-04-03 2200-01-01 stock 广东 深圳市\n", 400 | "000002.XSHE 万科A WKA 1991-01-29 2200-01-01 stock 广东 深圳市\n", 401 | "000004.XSHE 国华网安 GHWA 1990-12-01 2200-01-01 stock 广东 深圳市" 402 | ] 403 | }, 404 | "execution_count": 101, 405 | "metadata": {}, 406 | "output_type": "execute_result" 407 | } 408 | ], 409 | "source": [ 410 | "from jqdatasdk import finance\n", 411 | "from jqdatasdk import query\n", 412 | "\n", 413 | "# 通过jqdatasdk获取证券列表\n", 414 | "securities = jq.get_all_securities()\n", 415 | "code = '000001.XSHE'\n", 416 | "rec = finance.run_query(query(finance.STK_COMPANY_INFO).filter(finance.STK_COMPANY_INFO.code==code).limit(1))\n", 417 | "\n", 418 | "#我们使用下面的函数,将前面获得的securities对象加上两列,即province和city\n", 419 | "def add_region_info(securities):\n", 420 | " company_infos = finance.run_query(query(finance.STK_COMPANY_INFO))\n", 421 | " for code in securities.index:\n", 422 | " rec = company_infos[company_infos['code'] == code]\n", 423 | " if len(rec) == 0:\n", 424 | " securities.loc[code, 'province'] = None\n", 425 | " securities.loc[code, 'city'] = None\n", 426 | " else:\n", 427 | " securities.loc[code, 'province'] = rec['province'].iat[0]\n", 428 | " securities.loc[code, 'city'] = rec['city'].iat[0]\n", 429 | "add_region_info(securities)\n", 430 | "securities[:3]" 431 | ] 432 | }, 433 | { 434 | "cell_type": "markdown", 435 | "metadata": {}, 436 | "source": [ 437 | "可以看到,与前面的输出信息相比,这里的输出多了公司所在地省市的信息。下面我们看看如何获取概念板块:" 438 | ] 439 | }, 440 | { 441 | "cell_type": "code", 442 | "execution_count": 102, 443 | "metadata": {}, 444 | "outputs": [ 445 | { 446 | "name": "stdout", 447 | "output_type": "stream", 448 | "text": [ 449 | "['300514.XSHE', '300044.XSHE']\n" 450 | ] 451 | } 452 | ], 453 | "source": [ 454 | "# 获取概念板块\n", 455 | "concepts = jq.get_concepts()\n", 456 | "\n", 457 | "def query_stock_by_concept(query_concepts, province=None, city=None):\n", 458 | " stocks = set()\n", 459 | " for name in query_concepts:\n", 460 | " concept = concepts[concepts['name'] == name]\n", 461 | " if len(concept) == 0:\n", 462 | " continue\n", 463 | " \n", 464 | " idx = concept.index[0]\n", 465 | " members = set(jq.get_concept_stocks(idx))\n", 466 | " if len(stocks) == 0:\n", 467 | " stocks = members\n", 468 | " else:\n", 469 | " stocks = stocks.intersection(members)\n", 470 | " \n", 471 | " results = []\n", 472 | "\n", 473 | " for code in stocks:\n", 474 | " if province and securities.loc[code, 'province'] != province:\n", 475 | " continue\n", 476 | " if city and securities.loc[code, 'city'] != city:\n", 477 | " continue\n", 478 | " \n", 479 | " results.append(code)\n", 480 | " \n", 481 | " return results\n", 482 | " \n", 483 | "#jq.get_concept_stocks('GN001')\n", 484 | "stocks = query_stock_by_concept(['智能电网','物联网'],'广东','深圳市')\n", 485 | "print(stocks)" 486 | ] 487 | }, 488 | { 489 | "cell_type": "markdown", 490 | "metadata": {}, 491 | "source": [ 492 | "经过查询,我们得到两只股票,300044.XSHE和300514.XSHE。如果我们通过这两个代码来构造Security对象,就可以得到它们的名字:" 493 | ] 494 | }, 495 | { 496 | "cell_type": "code", 497 | "execution_count": 103, 498 | "metadata": {}, 499 | "outputs": [ 500 | { 501 | "name": "stdout", 502 | "output_type": "stream", 503 | "text": [ 504 | "赛为智能\n" 505 | ] 506 | } 507 | ], 508 | "source": [ 509 | "print(Security('300044.XSHE').display_name)" 510 | ] 511 | }, 512 | { 513 | "cell_type": "markdown", 514 | "metadata": {}, 515 | "source": [ 516 | "好了!我们知道在A股题材炒作行情阶段,如果一个品种具有多个题材(概念),则更容易成为资金追逐的对象。现在,有了上面的方法,您也可以很轻松地寻找到同时具有多个热点概念的股票了!\n", 517 | "\n", 518 | "## 获取行情数据\n", 519 | "\n", 520 | "接下来,让我们看看如何获取行情数据:" 521 | ] 522 | }, 523 | { 524 | "cell_type": "code", 525 | "execution_count": 104, 526 | "metadata": {}, 527 | "outputs": [ 528 | { 529 | "data": { 530 | "text/plain": [ 531 | "array([(datetime.date(2020, 12, 1), 19.7 , 20.51, 19.4 , 20.05, 1.26371975e+08, 2.51601078e+09, 120.77),\n", 532 | " (datetime.date(2020, 12, 2), 19.93, 20.06, 19.52, 19.63, 8.89385290e+07, 1.75863919e+09, 120.77),\n", 533 | " (datetime.date(2020, 12, 3), 19.78, 19.86, 19.17, 19.54, 7.14452300e+07, 1.39308502e+09, 120.77),\n", 534 | " (datetime.date(2020, 12, 4), 19.47, 19.47, 18.97, 19.3 , 8.91347840e+07, 1.70763907e+09, 120.77)],\n", 535 | " dtype=[('frame', 'O'), ('open', ']" 629 | ] 630 | }, 631 | "execution_count": 107, 632 | "metadata": {}, 633 | "output_type": "execute_result" 634 | }, 635 | { 636 | "data": { 637 | "image/png": "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\n", 638 | "text/plain": [ 639 | "
" 640 | ] 641 | }, 642 | "metadata": { 643 | "needs_background": "light" 644 | }, 645 | "output_type": "display_data" 646 | } 647 | ], 648 | "source": [ 649 | "import matplotlib.pyplot as plt # matplotlib是常用的绘图库\n", 650 | "import numpy as np\n", 651 | "\n", 652 | "# 大盘走势,为便于比较,使用了涨跌幅\n", 653 | "\n", 654 | "plt.plot((np.cumsum(bars_sh['close'])/np.cumsum(bars_sh['close']>0))/bars_sh['open'][0])\n", 655 | "# 吉林森工的股价变化\n", 656 | "plt.plot(bars_jlsg['close']/bars_jlsg['close'][0])\n", 657 | "# 吉林森工的均价线\n", 658 | "plt.plot((np.cumsum(bars_jlsg['amount'])/np.cumsum(bars_jlsg['volume']))/bars_jlsg['open'][0])" 659 | ] 660 | }, 661 | { 662 | "cell_type": "markdown", 663 | "metadata": {}, 664 | "source": [ 665 | "上图中,黄色的线是个股的收盘分时线,绿色线是其均价线,蓝色线是大盘均价线。关于如何绘图,我们放在第二章讲。\n", 666 | "\n", 667 | "为了便于比较,我们将两个品种的数据都除以其开盘价,这样就将数值归一化到 $$[0.9, 1.1]$$ 的区间里。因此,从上图可以看出,指数是高开走低,午后小幅回升。而吉林森工则在大盘企稳之时,股价上穿分时均线,随后出现一波拉升,直至涨停。\n", 668 | "\n", 669 | "??? Tips\n", 670 | " 严格地说,在做归一化时,应该除以头一天的收盘价,这样才能得到 $$[0.9,1.1]$$ 的区间。这里做了简化。\n", 671 | "\n", 672 | "从图中可以看出,一开盘在大盘下探时,吉林森工股价就快速上涨,此后随大盘微跌,但均价线支撑有力。在午后确认大盘企稳后,主力快速拉升到涨停。\n", 673 | "\n", 674 | "## 分时寻龙策略\n", 675 | "\n", 676 | "现在,我们介绍教程的第一个策略,我们把它称为分时寻龙:\n", 677 | "\n", 678 | "如果股价上穿分时均线,且分时均线在区间内是向上的,就发出买入信号。如果同期指数是下跌的,则信号更强烈。\n", 679 | "\n", 680 | "这里的原理是,如果分时均线是向上的,说明买入量大于卖出量,拉动股价上涨。股价上穿均线是刚启动的信号,此时买入,成本较低。" 681 | ] 682 | }, 683 | { 684 | "cell_type": "markdown", 685 | "metadata": {}, 686 | "source": [ 687 | "我们判断分时线方向的方法是,先将其拟合成一条直线 $$y = ax + b$$ 然后看其斜率 _a_ 是正还是负。为此我们先定义拟合函数:" 688 | ] 689 | }, 690 | { 691 | "cell_type": "code", 692 | "execution_count": 108, 693 | "metadata": {}, 694 | "outputs": [], 695 | "source": [ 696 | "from sklearn.metrics import mean_squared_error as rmse\n", 697 | "def fit(ts):\n", 698 | " x = np.array(list(range(len(ts))))\n", 699 | " z = np.polyfit(x, ts, deg=1)\n", 700 | " p = np.poly1d(z)\n", 701 | " \n", 702 | " ts_hat = np.array([p(xi) for xi in x])\n", 703 | " error = rmse(ts, ts_hat, squared=True) / np.sqrt(np.mean(np.square(ts)))\n", 704 | " \n", 705 | " return error, z" 706 | ] 707 | }, 708 | { 709 | "cell_type": "markdown", 710 | "metadata": {}, 711 | "source": [ 712 | "首先我们从sklearn中引入均方差函数。在sklearn>0.22版本中,这个函数允许返回开方均方差,即rmse。\n", 713 | "\n", 714 | "然后我们使用numpy提供的一个多项式拟合函数`polyfit`来进行直线拟合,并且用rmse来表示拟合误差。实际上,`polyfit`可以直接返回拟合误差,这里我们自已计算拟合误差的原因是,我们希望得到的误差,是关于原系列的一个百分比误差,而不是绝对值差。只有这样,我们才能对不同的序列进行拟合后,对它们的系数进行比较。\n", 715 | "\n", 716 | "返回结果是拟合误差,以及直线系数 _(a, b)_ 。\n", 717 | "\n", 718 | "现在,我们来看一下这个拟合结果。" 719 | ] 720 | }, 721 | { 722 | "cell_type": "code", 723 | "execution_count": 109, 724 | "metadata": {}, 725 | "outputs": [ 726 | { 727 | "name": "stdout", 728 | "output_type": "stream", 729 | "text": [ 730 | "jlsg: error is 7.63815750419143e-08, a is 0.000024, b is 1.024830\n", 731 | "sh: error is 4.5160782622494896e-13, a is -2.2345848305912403e-09, b is 0.000296\n" 732 | ] 733 | } 734 | ], 735 | "source": [ 736 | "def price(bars):\n", 737 | " return np.cumsum(bars['amount'])/np.cumsum(bars['volume'])\n", 738 | "\n", 739 | "def price_cum_close(bars):\n", 740 | " return np.cumsum(bars['close'])/np.cumsum(bars['close']>0)/bars['open'][0]\n", 741 | "\n", 742 | "# 个股拟合\n", 743 | "ts = price(bars_jlsg)/bars_jlsg[0]['open']\n", 744 | "err, (a, b) = fit(ts[40:100])\n", 745 | "print(f\"jlsg: error is {err}, a is {a:04f}, b is {b:02f}\")\n", 746 | "\n", 747 | "# 大盘拟合\n", 748 | "ts_sh = price_cum_close(bars_sh)/bars_sh[0]['open']\n", 749 | "err_sh, (a_sh, b_sh) = fit(ts_sh[40:100])\n", 750 | "print(f\"sh: error is {err_sh}, a is {a_sh}, b is {b_sh:02f}\")\n" 751 | ] 752 | }, 753 | { 754 | "cell_type": "markdown", 755 | "metadata": {}, 756 | "source": [ 757 | "吉林森工对应的系数a为正数,所以分时均线在区间 _[40:100]_ 之间是向上的,这对应着10:10分到11:10分的情况。而这段时间大盘的拟合直线则是向下的。\n", 758 | "\n", 759 | "下面我们分别作图对比一下:" 760 | ] 761 | }, 762 | { 763 | "cell_type": "code", 764 | "execution_count": 110, 765 | "metadata": {}, 766 | "outputs": [ 767 | { 768 | "data": { 769 | "text/plain": [ 770 | "[]" 771 | ] 772 | }, 773 | "execution_count": 110, 774 | "metadata": {}, 775 | "output_type": "execute_result" 776 | }, 777 | { 778 | "data": { 779 | "image/png": "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\n", 780 | "text/plain": [ 781 | "
" 782 | ] 783 | }, 784 | "metadata": { 785 | "needs_background": "light" 786 | }, 787 | "output_type": "display_data" 788 | } 789 | ], 790 | "source": [ 791 | "x = [i for i in range(60)]\n", 792 | "\n", 793 | "p_jlsg = np.poly1d((a,b))\n", 794 | "y_jlsg = [p_jlsg(i) for i in x]\n", 795 | "\n", 796 | "p_sh = np.poly1d((a_sh, b_sh))\n", 797 | "y_sh = [p_sh(i) for i in x]\n", 798 | "\n", 799 | "plt.figure(figsize=(12, 3))\n", 800 | "plt.subplot(121)\n", 801 | "\n", 802 | "plt.plot(x, y_jlsg, color='red')\n", 803 | "plt.plot(x, ts[40:100], color='blue')\n", 804 | "\n", 805 | "plt.subplot(122)\n", 806 | "plt.plot(x, y_sh, color='red')\n", 807 | "plt.plot(x, ts_sh[40:100], color='blue')" 808 | ] 809 | }, 810 | { 811 | "cell_type": "markdown", 812 | "metadata": {}, 813 | "source": [ 814 | "直观看上去,个股的似乎误差还比较大。但是,这里的纵坐标是相对于开盘价的涨跌幅,所以其实股价的波动是在千分位上的波动,在60分钟的时间里,均价线上涨了约0.2%(从2.4%上涨到2.6%)。因此,该分时线拟合为一条上升的直线,是没有问题的。\n", 815 | "\n", 816 | "注意到个股在尾部出现了下跌的情况,所以,我们需要等待股价上穿均价线,此时作为买入时机。这里我们定义两条曲线相交的函数:" 817 | ] 818 | }, 819 | { 820 | "cell_type": "code", 821 | "execution_count": 111, 822 | "metadata": {}, 823 | "outputs": [], 824 | "source": [ 825 | "def cross(f, g):\n", 826 | " \"\"\"\n", 827 | " 判断序列f是否与g相交。如果两个序列有且仅有一个交点,则返回1表明f上交g;-1表明f下交g\n", 828 | " returns:\n", 829 | " (flag, index), 其中flag取值为:\n", 830 | " 0 无相交\n", 831 | " -1 f向下交叉g\n", 832 | " 1 f向上交叉g\n", 833 | " \"\"\"\n", 834 | " indices = np.argwhere(np.diff(np.sign(f - g))).flatten()\n", 835 | "\n", 836 | " if len(indices) == 0:\n", 837 | " return 0, 0\n", 838 | "\n", 839 | " # 如果存在一个或者多个交点,取最后一个\n", 840 | " idx = indices[-1]\n", 841 | "\n", 842 | " if f[idx] < g[idx]:\n", 843 | " return 1, idx\n", 844 | " elif f[idx] > g[idx]:\n", 845 | " return -1, idx\n", 846 | " else:\n", 847 | " return np.sign(g[idx - 1] - f[idx - 1]), idx" 848 | ] 849 | }, 850 | { 851 | "cell_type": "code", 852 | "execution_count": 112, 853 | "metadata": {}, 854 | "outputs": [ 855 | { 856 | "data": { 857 | "text/plain": [ 858 | "(1, 56)" 859 | ] 860 | }, 861 | "execution_count": 112, 862 | "metadata": {}, 863 | "output_type": "execute_result" 864 | } 865 | ], 866 | "source": [ 867 | "# 这里股价是bars_jlsg['close'],均价线是price(bars_jlsg)\n", 868 | "cross(bars_jlsg['close'][40:100], price(bars_jlsg)[40:100])" 869 | ] 870 | }, 871 | { 872 | "cell_type": "markdown", 873 | "metadata": {}, 874 | "source": [ 875 | "结果表明股价曾在位置56处上穿均价线,对应于时间11:06分。我们把这个交点可视化标注出来:" 876 | ] 877 | }, 878 | { 879 | "cell_type": "code", 880 | "execution_count": 113, 881 | "metadata": {}, 882 | "outputs": [ 883 | { 884 | "data": { 885 | "text/plain": [ 886 | "[]" 887 | ] 888 | }, 889 | "execution_count": 113, 890 | "metadata": {}, 891 | "output_type": "execute_result" 892 | }, 893 | { 894 | "data": { 895 | "image/png": "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\n", 896 | "text/plain": [ 897 | "
" 898 | ] 899 | }, 900 | "metadata": { 901 | "needs_background": "light" 902 | }, 903 | "output_type": "display_data" 904 | } 905 | ], 906 | "source": [ 907 | "plt.plot(bars_jlsg['close'])\n", 908 | "plt.plot(price(bars_jlsg))\n", 909 | "plt.plot(96, bars_jlsg['close'][96], 'x', color='red')" 910 | ] 911 | }, 912 | { 913 | "cell_type": "markdown", 914 | "metadata": {}, 915 | "source": [ 916 | "图中红叉的地方,就是买入点。如果在这一点您的交易系统发出买入信号,则当天可以赚接近8%,在此后的不到一个月内,股价从7.03元上涨到接近12元,几乎翻倍。而同期上证指先抑后扬,只录得小幅上涨,吉林森工大幅跑赢指数。这样,我们就通过分时寻龙策略,找到了一只潜力股。\n", 917 | "\n", 918 | "??? Tips\n", 919 | " 吉林森工现已更名为泉阳泉,主营变更为矿泉水生产和销售。由于主营业务发生变更,它的估值体系也随之发生变化,因此有了补涨的需求。进行生产经营分析是一件十分复杂的事,好在我们可以通过量化策略发现交易信号,而不用去深究其背后的原因。\n", 920 | " 一切消息,最终都将反映为价格。" 921 | ] 922 | }, 923 | { 924 | "cell_type": "markdown", 925 | "metadata": {}, 926 | "source": [ 927 | "## 结束语" 928 | ] 929 | }, 930 | { 931 | "cell_type": "markdown", 932 | "metadata": {}, 933 | "source": [ 934 | "做交易复盘十分重要。这里我们也对本章内容进行一下复盘。\n", 935 | "\n", 936 | "本章我们介绍了如何获取证券列表、概念板块,如何获取个股和指数的k线行情数据。通过本篇内容,您已经了解了,Omicron是大富翁的数据SDK,在使用之前,要通过`await omicron.init`进行初始化,然后获取数据主要是通过Securities和Security两个model类来完成。同时,`omicron.core`还提供了重要的类型定义,这些我们将在第三章陆续介绍。\n", 937 | "\n", 938 | "在文章最后,我们介绍了一个有一定实用性的分时寻龙策略。它的有效性是无庸置疑的,但是,您在使用时,也应该结合当前的大环境,来正确设置不同时间段的收益期望。当整个市场进入系统性下跌过程时,即使是实力的主力,也会提前收兵。\n", 939 | "\n", 940 | "最后我们讨论一下,运行上面的策略,所需要的数据量。\n", 941 | "\n", 942 | "假设我们从开盘后第60分钟起对全市场进行扫描。完成一次扫描,我们需要取得的数据量为:\n", 943 | "\n", 944 | "$$\n", 945 | "4000 x 60 = 24(万条)\n", 946 | "$$\n", 947 | "\n", 948 | "如果不使用离线缓存的话,我们就要每几分钟就向服务器请求这么大量的数据。显然,这会给服务器带来较大的压力,也使得我们的策略很难实时发出交易信号。此外,如果您使用的数据源有Quota限制的话,这样也很容易用尽Quota。\n", 949 | "\n", 950 | "使用大富翁后,象这样的扫描,已经取得的、已收盘的k线数据都被缓存起来,也就是如果您每分钟运行一次上述策略的话,也只会向服务器请求4000条数据。数据请求量低到之前的$1/60$。" 951 | ] 952 | }, 953 | { 954 | "cell_type": "markdown", 955 | "metadata": { 956 | "ExecuteTime": { 957 | "end_time": "2020-10-13T12:09:51.929361Z", 958 | "start_time": "2020-10-13T12:09:51.918790Z" 959 | } 960 | }, 961 | "source": [ 962 | "##### **声明:本教程中引用到的股票代码,仅为演示如何使用相关API之目的,并非荐股。相关个股引用期间距现在较远,对当前走势没有任何影响,对您当下的操作没有任何指导意义。下同。**" 963 | ] 964 | }, 965 | { 966 | "cell_type": "code", 967 | "execution_count": null, 968 | "metadata": {}, 969 | "outputs": [], 970 | "source": [] 971 | } 972 | ], 973 | "metadata": { 974 | "kernelspec": { 975 | "display_name": "zillionare", 976 | "language": "python", 977 | "name": "zillionare" 978 | }, 979 | "language_info": { 980 | "codemirror_mode": { 981 | "name": "ipython", 982 | "version": 3 983 | }, 984 | "file_extension": ".py", 985 | "mimetype": "text/x-python", 986 | "name": "python", 987 | "nbconvert_exporter": "python", 988 | "pygments_lexer": "ipython3", 989 | "version": "3.8.8" 990 | }, 991 | "toc": { 992 | "base_numbering": 1, 993 | "nav_menu": {}, 994 | "number_sections": true, 995 | "sideBar": true, 996 | "skip_h1_title": false, 997 | "title_cell": "Table of Contents", 998 | "title_sidebar": "Contents", 999 | "toc_cell": false, 1000 | "toc_position": {}, 1001 | "toc_section_display": true, 1002 | "toc_window_display": true 1003 | } 1004 | }, 1005 | "nbformat": 4, 1006 | "nbformat_minor": 4 1007 | } 1008 | -------------------------------------------------------------------------------- /chap2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 第二章 数据可视化" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "在上一章,我们已经使用了数据可视化功能。我们绘制了分时图,并在图上描绘了两条曲线的交叉点。\n", 15 | "\n", 16 | "可视化是量化交易研究中必备的技能。某种程度上,量化交易员的工作,就象数据科学家一样,起初我们不知道哪些特征隐藏在数据背后,于是我们打开Notebook,尝试一些算法,得到一些结果,并且将其直观地展示出来--即可视化。这当中有一些结果会有效,我们将其固定成为交易策略并重复使用;有一些被证明行不通,于是我们开始下一轮探索。这个过程,也被称之为探索式编程。\n", 17 | "\n", 18 | "现在,是时候来介绍一些基本的数据可视化方法了。" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "现在常用的图形库,基于js的有plotly, echarts。其中echarts是百度贡献的开源库,现在是Apache的顶级项目,可谓国货之光了。基于Python的主要是matplotlib。\n", 26 | "\n", 27 | "如果要绘制交互式的图形,几乎只能选择基于js的图形库。如果js图形库使用了WebGL加速,那么绘图速度还是相当快的。\n", 28 | "\n", 29 | "在这一章里,我们先简单介绍一下echarts的Python库,pyecharts的使用(注意pyecharts与echarts并不是同一个库),然后就把重点转向matplotlib。" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "## 使用pyecharts绘制交互式k线图" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 1, 42 | "metadata": {}, 43 | "outputs": [ 44 | { 45 | "ename": "ModuleNotFoundError", 46 | "evalue": "No module named 'omicron'", 47 | "output_type": "error", 48 | "traceback": [ 49 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 50 | "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", 51 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# 导入omicron及相关核心组件\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0momicron\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0momicron\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtimeframe\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtf\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0momicron\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtypes\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mFrameType\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0momicron\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmodels\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msecurity\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSecurity\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 52 | "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'omicron'" 53 | ] 54 | } 55 | ], 56 | "source": [ 57 | "# 导入omicron及相关核心组件\n", 58 | "import omicron\n", 59 | "from omicron.core.timeframe import tf\n", 60 | "from omicron.core.types import FrameType\n", 61 | "from omicron.models.security import Security\n", 62 | "import cfg4py\n", 63 | "from omega.config import get_config_dir\n", 64 | "\n", 65 | "import arrow\n", 66 | "\n", 67 | "import numpy as np\n", 68 | "from typing import List, Sequence, Union\n", 69 | "\n", 70 | "import pyecharts\n", 71 | "\n", 72 | "from pyecharts import options as opts\n", 73 | "from pyecharts.commons.utils import JsCode\n", 74 | "from pyecharts.charts import Kline, Line, Bar, Grid\n", 75 | "\n", 76 | "# 初始化omicron\n", 77 | "cfg4py.init(get_config_dir())\n", 78 | "await omicron.init()\n", 79 | "\n", 80 | "def moving_average(ts, win):\n", 81 | " return np.convolve(ts, np.ones(win)/win, 'valid')\n", 82 | "\n", 83 | "def left_padding(arr, count, obj = None):\n", 84 | " padded = [obj] * count\n", 85 | " padded.extend(arr)\n", 86 | "\n", 87 | " return padded\n", 88 | "\n", 89 | "end = arrow.now().date()\n", 90 | "\n", 91 | "# 取start为end前60个交易日\n", 92 | "start = tf.day_shift(end, -60)\n", 93 | "\n", 94 | "# 得到k线数据\n", 95 | "bars = await Security('000001.XSHG').load_bars(start, end, FrameType.DAY)\n", 96 | "\n", 97 | "# data must be sequence of int, float, str or other simple object, not numpy types\n", 98 | "ochl = [list(item.tolist()) for item in bars[['open', 'close', 'high', 'low']]]\n", 99 | "\n", 100 | "# datetime object is not supported\n", 101 | "dt = [str(d) for d in bars['frame']]\n", 102 | "\n", 103 | "\n", 104 | "mas = {}\n", 105 | "for win in [5, 10, 20]:\n", 106 | " # 对均线数据,向左填充None,使得它们在绘制时能对齐k线\n", 107 | " mas[f\"ma{win}\"] = left_padding(moving_average(bars['close'], win),\n", 108 | " win, None)\n", 109 | " \n", 110 | "k = (\n", 111 | " Kline()\n", 112 | " .add_xaxis(dt)\n", 113 | " .add_yaxis('kline', ochl)\n", 114 | " .set_global_opts(\n", 115 | " yaxis_opts=opts.AxisOpts(is_scale=True),\n", 116 | " xaxis_opts=opts.AxisOpts(is_scale=True),\n", 117 | " title_opts=opts.TitleOpts(title=\"K线图\"),\n", 118 | " datazoom_opts=[opts.DataZoomOpts()]\n", 119 | " )\n", 120 | ")\n", 121 | "\n", 122 | "for win in [5, 10, 20]:\n", 123 | " name = f\"ma{win}\"\n", 124 | " data = mas[name]\n", 125 | " line = Line()\n", 126 | " line.add_xaxis(dt)\n", 127 | " line.add_yaxis(name, data,\n", 128 | " label_opts=opts.LabelOpts(is_show=False),\n", 129 | " is_symbol_show=False)\n", 130 | "\n", 131 | " k.overlap(line)\n", 132 | " \n", 133 | "\n", 134 | "# 显示在notebook的cell中。如果要生成网页,一般调用render()\n", 135 | "k.render_notebook()\n" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "## Matplotlib\n", 150 | "\n", 151 | "下面我们来介绍基于matplotlib的数据可视化方法。\n", 152 | "\n", 153 | "matplotlib提供了可靠的Python接口,文档丰富,使用者众多,因此容易上手。matplotlib的主要不足是性能问题,在绘制k线图的过程中,绘制一张图可能需要2秒钟左右。如果我们在生产环境下,使用了matplotlib来制图(比如基于CNN的交易策略),显然就没有办法完成在很短的时间里,遍历全部证券品种。但是,在交易策略的探索过程中,以及我们的教程中,这个速度是足够了。" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "matplotlib是一个2D图形绘制库,使用Numpy作为数据接口,是Python下最常用的图形绘制库之一。\n", 163 | "\n", 164 | "matplotlib的绘制对象是Figure, 每个Figure下" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": 3, 170 | "metadata": {}, 171 | "outputs": [], 172 | "source": [ 173 | "%matplotlib inline\n", 174 | "\n", 175 | "import matplotlib.pyplot as plt\n", 176 | "import numpy as np\n", 177 | "import os\n", 178 | "from IPython import display\n", 179 | "import warnings\n", 180 | "warnings.filterwarnings('ignore')\n", 181 | "\n", 182 | "import jqdatasdk as jq\n", 183 | "\n", 184 | "# 请在环境变量中设置聚宽账号。账号可在jointquant.com上免费申请\n", 185 | "account = os.environ.get('JQ_ACCOUNT')\n", 186 | "password = os.environ.get('JQ_PASSWORD')\n", 187 | "jq.auth(account, password)\n", 188 | "securities = jq.get_all_securities()" 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "metadata": {}, 194 | "source": [ 195 | "尽管量化交易是机器执行的,我们仍然需要将数据可视化。比如,在使用CNN网络之前,我们需要把行情数据处理成图像数据(比如K线图);也有可能你调制了一个绝妙的指标,能够很好地发现买卖点--但是眼见为实,这么好的指标,你最好是把它标注在K线图上,人工复核几遍才能够放心。\n", 196 | "\n", 197 | "与交易相关的图中,可能最复杂的就是K线图了。对非定制化的、交互式的K线图,我们可以直接使用Pyecharts来绘制:" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": 222, 203 | "metadata": { 204 | "scrolled": false 205 | }, 206 | "outputs": [ 207 | { 208 | "data": { 209 | "text/html": [ 210 | "\n", 211 | "\n", 218 | "\n", 219 | "
\n", 220 | "\n", 221 | "\n" 1607 | ], 1608 | "text/plain": [ 1609 | "" 1610 | ] 1611 | }, 1612 | "execution_count": 222, 1613 | "metadata": {}, 1614 | "output_type": "execute_result" 1615 | } 1616 | ], 1617 | "source": [ 1618 | "import pyecharts\n", 1619 | "\n", 1620 | "import numpy as np\n", 1621 | "from pyecharts import options as opts\n", 1622 | "from pyecharts.charts import Line, Kline, Bar\n", 1623 | "\n", 1624 | "\n", 1625 | "def moving_average(ts, win):\n", 1626 | " return np.convolve(ts, np.ones(win)/win, 'valid')\n", 1627 | "\n", 1628 | "def left_padding(arr, count, obj = None):\n", 1629 | " padded = [obj] * count\n", 1630 | " padded.extend(arr)\n", 1631 | "\n", 1632 | " return padded\n", 1633 | "\n", 1634 | "fields = ['date', 'open', 'high', 'low', 'close', 'volume']\n", 1635 | "bars = jq.get_bars('000001.XSHG', 60, unit='1d', df=False, fields=fields)\n", 1636 | "\n", 1637 | "# data must be sequence of int, float, str or other simple object\n", 1638 | "ochl = [list(item) for item in bars[['open', 'close', 'high', 'low']]]\n", 1639 | "\n", 1640 | "# datetime object is not supported\n", 1641 | "dt = [str(d) for d in bars['date']]\n", 1642 | "\n", 1643 | "\n", 1644 | "mas = {}\n", 1645 | "for win in [5, 10, 20]:\n", 1646 | " # 对均线数据,向左填充None,使得它们在绘制时能对齐k线\n", 1647 | " mas[f\"ma{win}\"] = left_padding(moving_average(bars['close'], win),\n", 1648 | " win, None)\n", 1649 | " \n", 1650 | "k = (\n", 1651 | " Kline()\n", 1652 | " .add_xaxis(dt)\n", 1653 | " .add_yaxis('kline', ochl)\n", 1654 | " .set_global_opts(\n", 1655 | " yaxis_opts=opts.AxisOpts(is_scale=True),\n", 1656 | " xaxis_opts=opts.AxisOpts(is_scale=True),\n", 1657 | " title_opts=opts.TitleOpts(title=\"K线图\"),\n", 1658 | " datazoom_opts=[opts.DataZoomOpts()]\n", 1659 | " )\n", 1660 | ")\n", 1661 | "\n", 1662 | "for win in [5, 10, 20]:\n", 1663 | " name = f\"ma{win}\"\n", 1664 | " data = mas[name]\n", 1665 | " line = Line()\n", 1666 | " line.add_xaxis(dt)\n", 1667 | " line.add_yaxis(name, data,\n", 1668 | " label_opts=opts.LabelOpts(is_show=False),\n", 1669 | " is_symbol_show=False)\n", 1670 | "\n", 1671 | " k.overlap(line)\n", 1672 | " \n", 1673 | "# clean up PendingDeprecationWarning by pyechart\n", 1674 | "display.clear_output()\n", 1675 | "\n", 1676 | "# 显示在notebook的cell中。如果要生成网页,一般调用render()\n", 1677 | "k.render_notebook()\n" 1678 | ] 1679 | }, 1680 | { 1681 | "cell_type": "markdown", 1682 | "metadata": {}, 1683 | "source": [ 1684 | "但在量化交易中,我们并不太需要上面这种交互式的K线图。特别是在为神经网络训练准备可视化数据时,我们很可能并不想使用传统的K线图,而是自己定制的某种图。另外,作为探索式编程的一部分,我们常常需要在jupyter notebook中把指标和方案可视化。因此,我们需要掌握一些基本的绘图知识。\n", 1685 | "\n", 1686 | "下面,我们就以matplot绘图为例,介绍相关的绘制知识。\n", 1687 | "\n", 1688 | "您可能已经注意到,在各章节配套的notebook开头,我们都有这样的语句:" 1689 | ] 1690 | }, 1691 | { 1692 | "cell_type": "code", 1693 | "execution_count": 6, 1694 | "metadata": {}, 1695 | "outputs": [], 1696 | "source": [ 1697 | "%matplotlib inline\n", 1698 | "\n", 1699 | "import matplotlib.pyplot as plt" 1700 | ] 1701 | }, 1702 | { 1703 | "cell_type": "markdown", 1704 | "metadata": {}, 1705 | "source": [ 1706 | "在前面几章里,我们的进度有点快,这里我们放慢一点速度,对一些细节多提几句。\n", 1707 | "\n", 1708 | "第一行是jupyter notebook魔法,它使得我们通过matplotlib.pyplot绘制的图形可以在notebook中的cell中显示出来。与之对应的,在pyechart,我们则是调用render_notebook来实现的。\n", 1709 | "\n", 1710 | "第二行是导入matplot的python实现库pyplot。前面我们使用了pyplot中的这些方法:" 1711 | ] 1712 | }, 1713 | { 1714 | "cell_type": "code", 1715 | "execution_count": 42, 1716 | "metadata": {}, 1717 | "outputs": [ 1718 | { 1719 | "name": "stderr", 1720 | "output_type": "stream", 1721 | "text": [ 1722 | "/home/userroot/miniconda3/envs/alpha/lib/python3.8/site-packages/ipykernel/ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n", 1723 | " and should_run_async(code)\n" 1724 | ] 1725 | }, 1726 | { 1727 | "data": { 1728 | "image/png": "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\n", 1729 | "text/plain": [ 1730 | "
" 1731 | ] 1732 | }, 1733 | "metadata": { 1734 | "needs_background": "light" 1735 | }, 1736 | "output_type": "display_data" 1737 | } 1738 | ], 1739 | "source": [ 1740 | "# 指定绘图区的大小。这里figsize是一个元组,分别指定绘图区\n", 1741 | "# 的宽和高(inch单位)。如果dpi设置为80的话,则下面的语句\n", 1742 | "# 指定了一个宽720,高720的绘图区\n", 1743 | "\n", 1744 | "plt.figure(figsize=(9,9))\n", 1745 | "\n", 1746 | "# 设置子绘图时使用的窗格,必须为一个三位的数字,第一位是\n", 1747 | "# 行数,第二位是列数,第三位是子图窗格的索引,起始值为1\n", 1748 | "# 下面的语句绘制了一个九宫格,并在图正中指定了其子图索引\n", 1749 | "\n", 1750 | "# ``'.'`` point marker\n", 1751 | "# ``','`` pixel marker\n", 1752 | "# ``'o'`` circle marker\n", 1753 | "# ``'v'`` triangle_down marker\n", 1754 | "# ``'^'`` triangle_up marker\n", 1755 | "# ``'<'`` triangle_left marker\n", 1756 | "# ``'>'`` triangle_right marker\n", 1757 | "# ``'1'`` tri_down marker\n", 1758 | "# ``'2'`` tri_up marker\n", 1759 | "# ``'3'`` tri_left marker\n", 1760 | "# ``'4'`` tri_right marker\n", 1761 | "# ``'s'`` square marker\n", 1762 | "# ``'p'`` pentagon marker\n", 1763 | "# ``'*'`` star marker\n", 1764 | "# ``'h'`` hexagon1 marker\n", 1765 | "# ``'H'`` hexagon2 marker\n", 1766 | "# ``'+'`` plus marker\n", 1767 | "# ``'x'`` x marker\n", 1768 | "# ``'D'`` diamond marker\n", 1769 | "# ``'d'`` thin_diamond marker\n", 1770 | "# ``'|'`` vline marker\n", 1771 | "marks = ['.',',','o','^','<','>','1','s','p','*']\n", 1772 | "\n", 1773 | "for i in range(1, 10):\n", 1774 | " plt.subplot(int(f\"33{i}\"))\n", 1775 | " # 绘制文字\n", 1776 | " plt.text(2,2, str(i))\n", 1777 | " # 绘制标记\n", 1778 | " plt.plot(np.arange(5), np.arange(5), marks[i-1], color='r')\n", 1779 | " \n", 1780 | "# 当前指定的子图仍为第9号子图。在其上绘制实线line\n", 1781 | "plt.plot(np.arange(5), np.arange(5), color='b')\n", 1782 | "\n", 1783 | "# 绘制虚拟line\n", 1784 | "plt.plot(np.arange(5)[::-1], np.arange(5), '--')\n", 1785 | "\n", 1786 | "# 给子图之间增加间距\n", 1787 | "plt.subplots_adjust(hspace=0.3, wspace=0.3)" 1788 | ] 1789 | }, 1790 | { 1791 | "cell_type": "markdown", 1792 | "metadata": {}, 1793 | "source": [ 1794 | "如果不指定子图,则会当成只有一个子图的情况。以上就是我们之前使用过的全部绘图方法。下面,我们来看应该如何绘制k线图。\n", 1795 | "\n", 1796 | "K线(蜡烛)图是由一个实体和上下影线组成的。我们使用矩形(Rectangle对象)来绘制实体,线(Line2D)来绘制上下影线。绘制实际上很简单,只要给这些矩形和上下影线指定好参数,再添加到图形中就可以了。" 1797 | ] 1798 | }, 1799 | { 1800 | "cell_type": "code", 1801 | "execution_count": 291, 1802 | "metadata": {}, 1803 | "outputs": [], 1804 | "source": [ 1805 | "from matplotlib.collections import LineCollection, PatchCollection\n", 1806 | "from matplotlib.lines import Line2D\n", 1807 | "from matplotlib.patches import Rectangle\n", 1808 | "def candle_stick_plot(ax, bars, bw:float=0.6, lw:float=0.4, ma_groups=None):\n", 1809 | " # 上影线顶点坐标\n", 1810 | " vertex_top = np.zeros((len(bars), 2, 2))\n", 1811 | " # 下影线顶点坐标\n", 1812 | " vertex_bottom = np.zeros((len(bars), 2, 2))\n", 1813 | " \n", 1814 | " rects = []\n", 1815 | "\n", 1816 | " # 线和实体边框的颜色\n", 1817 | " edge_color = np.where(bars['close']>=bars['open'],'r', 'g')\n", 1818 | " # 实体的颜色,这里指定为白色,从而显示为空心矩形\n", 1819 | " face_color = ['w'] * len(bars)\n", 1820 | " \n", 1821 | " for i in range(len(bars)):\n", 1822 | " o,c,l,h = bars[i][['open', 'close', 'low', 'high']]\n", 1823 | " # 计算各上影线、下影线的绘制坐标\n", 1824 | " xi = i - lw/2.0\n", 1825 | " if o >= c:\n", 1826 | " vertex_top[i] = [[xi, o], [xi, h]]\n", 1827 | " vertex_bottom[i] = [[xi, l], [xi, c]]\n", 1828 | " else:\n", 1829 | " vertex_top[i] = [[xi, c], [xi, h]]\n", 1830 | " vertex_bottom[i] = [[xi, l], [xi, o]]\n", 1831 | "\n", 1832 | " # 设置K线实体矩形的参数\n", 1833 | " rect = Rectangle((i - bw/2.0 - lw/2.0, min(bars[i]['close'], \n", 1834 | " bars[i]['open'])),width=bw, lw=lw, \n", 1835 | " height=abs(bars[i]['open']-bars[i]['close']))\n", 1836 | " \n", 1837 | " rects.append(rect)\n", 1838 | "\n", 1839 | " for vertex in [vertex_top, vertex_bottom]:\n", 1840 | " line_collection = LineCollection(vertex, color=edge_color,linewidths=lw)\n", 1841 | " ax.add_collection(line_collection)\n", 1842 | "\n", 1843 | " rect_pc = PatchCollection(rects, facecolor=face_color, edgecolor=edge_color)\n", 1844 | " ax.add_collection(rect_pc)\n", 1845 | " \n", 1846 | " # 叠加均线\n", 1847 | " for i, win in enumerate(ma_groups or []):\n", 1848 | " ma = moving_average(bars['close'], win)\n", 1849 | " ma = left_padding(ma, win-1, None)\n", 1850 | " line = Line2D(np.arange(len(ma)), ma, color=f\"C{i}\", linewidth=lw)\n", 1851 | " ax.add_line(line)\n", 1852 | " \n", 1853 | " # 设置x,y轴显示范围\n", 1854 | " ax.set_ylim(min(bars['close'])*0.99, max(bars['close'])*1.01)\n", 1855 | " ax.set_xlim(-1, len(bars)+1)\n", 1856 | " \n", 1857 | " # 隐藏下边的x轴标签\n", 1858 | " ax.xaxis.set_tick_params(length=0)\n", 1859 | " ax.xaxis.set_tick_params(labelbottom=False)\n" 1860 | ] 1861 | }, 1862 | { 1863 | "cell_type": "code", 1864 | "execution_count": 292, 1865 | "metadata": {}, 1866 | "outputs": [], 1867 | "source": [ 1868 | "def draw_volume_bars(ax, bars, bw:float=0.6):\n", 1869 | " ax.bar(np.arange(len(bars)), bars['volume'], color=np.where(bars['close']>=bars['open'], 'r', 'g'), width=bw)\n", 1870 | " ax.set_xlim(-1, len(bars)+1)\n", 1871 | " ax.set_ylim(min(bars['volume'])*0.99, max(bars['volume']) * 1.01)\n", 1872 | " ax.spines[\"top\"].set_visible(False)" 1873 | ] 1874 | }, 1875 | { 1876 | "cell_type": "code", 1877 | "execution_count": 304, 1878 | "metadata": {}, 1879 | "outputs": [ 1880 | { 1881 | "data": { 1882 | "image/png": "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\n", 1883 | "text/plain": [ 1884 | "
" 1885 | ] 1886 | }, 1887 | "metadata": { 1888 | "needs_background": "light" 1889 | }, 1890 | "output_type": "display_data" 1891 | } 1892 | ], 1893 | "source": [ 1894 | "fig, (kax, vax) = plt.subplots(2,1,gridspec_kw={'height_ratios':[3,1]},figsize=(10,6))\n", 1895 | "plt.subplots_adjust(hspace=0.02)\n", 1896 | "candle_stick_plot(kax, bars, ma_groups=[5])\n", 1897 | "draw_volume_bars(vax, bars)" 1898 | ] 1899 | }, 1900 | { 1901 | "cell_type": "markdown", 1902 | "metadata": {}, 1903 | "source": [ 1904 | "这里出现了新的对象,即轴(ax)对象。到现在为止,我们见过了五个容易混淆的概念:plt, subplot, subplots, figure和ax。图上的每一个点和线,最终都是绑定到具体的轴(ax)的,每个ax下面还有xaxis和yaxis对象,但它们就不再拥有点、线这些绘图元素了。plt只是名字空间,它不拥有任何绘图元素;figure是绘图用的抽象画布,它下面有ax对象(即前面所说的子图)。subplot则是一个方法,用来指定当前使用哪一个子图(ax)来绘图。\n", 1905 | "\n", 1906 | "关于fig与ax的关系,我们可以参考下图:\n", 1907 | "\n", 1908 | "![](https://matplotlib.org/1.5.1/_images/fig_map.png)\n", 1909 | "\n", 1910 | "当我们调用plt.plot时,并没有指定任何特别的对象;pyplot在背后指定了一个全局的figure,它有一个子图对象(ax)。所以,我们可以这样创建fig和子图:" 1911 | ] 1912 | }, 1913 | { 1914 | "cell_type": "code", 1915 | "execution_count": null, 1916 | "metadata": {}, 1917 | "outputs": [], 1918 | "source": [ 1919 | "# 创建并返回两个ax对象\n", 1920 | "fig, (kax, vax) = plt.subplots(2,1)" 1921 | ] 1922 | }, 1923 | { 1924 | "cell_type": "markdown", 1925 | "metadata": {}, 1926 | "source": [ 1927 | "也可以这样:" 1928 | ] 1929 | }, 1930 | { 1931 | "cell_type": "code", 1932 | "execution_count": null, 1933 | "metadata": {}, 1934 | "outputs": [], 1935 | "source": [ 1936 | "fig, ax = plt.subplots()" 1937 | ] 1938 | }, 1939 | { 1940 | "cell_type": "markdown", 1941 | "metadata": {}, 1942 | "source": [ 1943 | "这里只创建并返回了一个ax对象。" 1944 | ] 1945 | }, 1946 | { 1947 | "cell_type": "markdown", 1948 | "metadata": {}, 1949 | "source": [ 1950 | "在上面的代码中,使用了LineCollection和PathCollection,这是性能优化的方法之一。上面的代码还有可以优化的地方,比如生成上下影线和实体矩形参数,是可以使用numpy来避免循环的。\n", 1951 | "\n", 1952 | "但这里真正的瓶颈是matplotlib本身。在我的笔记本电脑上,类似于上面的K线图,它每秒只能生成2~3幅。与之相比,我们上面提到的优化循环部分就显得无足轻重了。因为这个原因,为了易读性考虑,我保留了代码中的循环。\n", 1953 | "\n", 1954 | "如果只是为了进行一些探索,上面的函数提供的性能是能满足需要的;但当我们使用CNN来训练和预测交易时,上面的函数就显得力不从心了。那时候我们必须得寻求60fps以上的方案。这个性能其实并不难,只要使用opengl,就能轻松达到。\n", 1955 | "\n", 1956 | "如果我们需要保存图像到文件,我们需要使用 _figure.savefig_ 方法:" 1957 | ] 1958 | }, 1959 | { 1960 | "cell_type": "code", 1961 | "execution_count": 306, 1962 | "metadata": {}, 1963 | "outputs": [], 1964 | "source": [ 1965 | "save_to = '/tmp/test.png'\n", 1966 | "fig.savefig(save_to, dpi = 80)" 1967 | ] 1968 | }, 1969 | { 1970 | "cell_type": "markdown", 1971 | "metadata": {}, 1972 | "source": [ 1973 | "如果我们需要进一步处理图像数据,可以使用BytesIO来把图像直接读到内存:" 1974 | ] 1975 | }, 1976 | { 1977 | "cell_type": "code", 1978 | "execution_count": 308, 1979 | "metadata": {}, 1980 | "outputs": [ 1981 | { 1982 | "data": { 1983 | "text/plain": [ 1984 | "0" 1985 | ] 1986 | }, 1987 | "execution_count": 308, 1988 | "metadata": {}, 1989 | "output_type": "execute_result" 1990 | } 1991 | ], 1992 | "source": [ 1993 | "from io import BytesIO\n", 1994 | "\n", 1995 | "buf = BytesIO()\n", 1996 | "# 此时必须指定format\n", 1997 | "fig.savefig(buf, format='png')\n", 1998 | "# 必须,否则buf无法读出\n", 1999 | "buf.seek(0)" 2000 | ] 2001 | }, 2002 | { 2003 | "cell_type": "code", 2004 | "execution_count": null, 2005 | "metadata": {}, 2006 | "outputs": [], 2007 | "source": [] 2008 | } 2009 | ], 2010 | "metadata": { 2011 | "kernelspec": { 2012 | "display_name": "Python 3", 2013 | "language": "python", 2014 | "name": "python3" 2015 | }, 2016 | "language_info": { 2017 | "codemirror_mode": { 2018 | "name": "ipython", 2019 | "version": 3 2020 | }, 2021 | "file_extension": ".py", 2022 | "mimetype": "text/x-python", 2023 | "name": "python", 2024 | "nbconvert_exporter": "python", 2025 | "pygments_lexer": "ipython3", 2026 | "version": "3.8.5" 2027 | }, 2028 | "toc": { 2029 | "base_numbering": 1, 2030 | "nav_menu": {}, 2031 | "number_sections": true, 2032 | "sideBar": true, 2033 | "skip_h1_title": false, 2034 | "title_cell": "Table of Contents", 2035 | "title_sidebar": "Contents", 2036 | "toc_cell": false, 2037 | "toc_position": {}, 2038 | "toc_section_display": true, 2039 | "toc_window_display": false 2040 | } 2041 | }, 2042 | "nbformat": 4, 2043 | "nbformat_minor": 4 2044 | } 2045 | --------------------------------------------------------------------------------