这是一个面向零编程基础的量化交易新手入门教程,力求让高中生知识水平的人都能学会量化交易最基本的知识,快速迈过第一道门槛,从而具备进一步自主深入学习的能力。
- 从零开始教编程。 靠谱的量化交易学习资源稀少,且具有不讲编程、代码较难、过多等不适合新手等问题,本教程中则会从零开始教编程,解决量化入门过难过编程门槛这一问题。
- **量化与编程相结合。**本教程不仅会教编程,而且会尽量结合量化情景,减少“我要做量化交易为什么要看这些用来培训程序员的东西”的愤懑。
- **简易精炼,快速入门。**尽量只讲最核心最常用的知识,助你快速摆脱想学习量化却处处陌生不知所措的茫然的新手阶段。
- 文后会有自测与自学,包括一些额外的延伸自学内容以及稍有难度的自测题目。
- 最最最基础的股票知识不会讲,比如交易量的含义、k线含义、每个股票都有六位的代码等。都很简单也很普及,遇到但不知道的话百度一下就能明白。
- 内容是前后连贯一体的,如果跳着读可能会遇到看不懂但其实前文讲过被你跳过的情况。
- 为了简易精炼难免不全面完备严谨。量化交易是同时涉及了金融、数学、计算机等多方面知识的,其内容繁多而高深,很多点展开讲了反而会引入更多更难的疑问。因此,学习过程中推荐先按部就班的学习一遍,实在心急好奇,不妨自己搜索下相关内容,毕竟自学是交易的必经之路。
- 目前,教程只规划做新手入门内容。已经会写策略的而只是想学用聚宽的人更应该去直接读API文档或量化课堂,如果还有疑惑可以在来查阅下本教程。
- 希望能多多分享与推荐给更多的量化爱好者:)
- 点击蓝色标题可直接跳转阅读。
- 初识量化交易
- 为什么需要量化交易?
- 何为量化交易?
- 量化交易的价值何在?
- 做量化交易需要准备什么?
- 聚宽是什么?
- 量化策略的基本框架
- 策略编写的基本框架及其实现
- 回测的含义及其实现
- 初步学习解决代码错误
- 周期循环的开始时间
- python基本语法与变量
- python是什么
- python的基础语法
- 变量与赋值
- Python 保留字符
- 打印 print
- 全局变量
- 基本数据类型-数字与字符串
- 算术运算
- 查看数据类型 type
- 数据类型-列表与字典
- 下单、函数、API
- 函数与API
- 函数使用方法
- 如何看API文档
- 自定义函数方法
- 常用的下单函数
- 获取context数据、条件判断
- context的含义
- context的结构
- context的读取方法
- 条件判断语句
- 止损的含义及其实现方法
- 循环、多股票策略
- 学习用list存储多个股票
- 学习使用for循环
- 学习写一个简单的多股票策略
- 获取典型常用数据
- 聚宽数据
- 获取指数成分股
- 获取股票行情数据
- 获取股票财务数据
- 综合之前所学写一个策略
- 灵感细化
- 逐步实现策略
- 调整与改进策略
- 策略评价与建立模拟
- 评价策略回测的指标
- 建立模拟交易
- 未来函数
- 运行过慢
- 过拟合
- 策略失效
- 投资研究功能
- 投资研究功能简介
- 新建notebook
- 单元格及其类型
- 命令模式与编辑模式
- 应用举例
- 成长指路
- 自学意识
- 之后去学什么
- 灵感来源
- 关于职业化
本文是量化交易零基础入门教程中的一篇,点击蓝字链接可查看该系列详情。
- 为什么需要量化交易?
- 量化交易是做什么?
- 量化交易的价值何在?
- 做量化交易需要什么?
- 聚宽是什么?
- 零基础如何快速入门量化交易?
- 自测与自学
- 它能让你的交易效率提高百倍,量化交易之于传统交易方法,如同大型收割机之于锄头镰刀,机枪大炮之于刀剑棍棒。
- 也就是是说,传统交易方法是这样的:
- 而量化交易是这样的:
- 在金融最为发达的美国,量化交易已大行其道,占据了70%以上的股市成交量。可以说量化交易是未来的趋势。当然,只言片语不能解释清楚,接下来,我们具体地介绍下量化交易。
-
量化交易是指借助现代统计学和数学的方法,利用计算机技术来进行交易的证券投资方式。便于理解的说,量化交易主要是做这样的事:
-
从一个灵感开始
-
灵感就是指那些你想验证的可能会盈利的方法,比如银行股可能是良好的投资品种、一旦跨过20日均线后股价会继续涨、流传许久的羊驼交易法等等。灵感获取的方式可以是阅读、听人说、自己悟等等。
-
这里我们以一个简单的情况为例进行讲解。比如你的灵感是这样的:
如果股价显著低于近几日的平均价,则买入 如果股价显著高于近几日的平均价,则卖出 -
现在,你想知道这样操作究竟会不会赚钱?
-
-
把灵感细化成明确的可执行的交易策略
-
一般灵感都很模糊,需要将其细化成明确的可执行的策略,目的是为了能得到确定的结果,以及为后续程序化准备。比如,你通过阅读了解到索罗斯的反身性概念,想将它应用到股市,这个反身性就很模糊,就需要明确什么条件下买卖,买卖什么品种,买卖多少量等,从而形成一个明确的交易策略,让不同人根据你的描述在相同情形下都能做出相同的操作。
-
继续以之前那个关于平均价的灵感为例:
如果股价显著低于近几日的平均价,则买入 如果股价显著高于近几日的平均价,则卖出 -
显然它是不够明确的。比如多低叫显著低于?多高叫显著高于?近几日究竟是几日?买入卖出是买卖多少?我们把它细化:
如果股价低于近20日平均价10%,则用全部可用资金买入 如果股价高于近20日平均价10%,则卖出全部所持的该股票
-
还有一点不明确的地方,买卖哪个股票呢?我们认为这个交易方法盈利与否应该跟交易哪个股票关系不大,但st股票除外(知道st股票是一类有风险特别大的股票就好,详情请百度),所以股票的选择范围是除st股外的国内A股的所有股票。所以我们进一步细化:
每个交易日监测是除st股外的国内A股的所有股票的股价 如果股价低于近20日平均价10%,则用全部可用资金买入该股票 如果股价高于近20日平均价10%,则卖出全部所持有的该股票 -
现在我们基本已经把之前的灵感细化成明确的可执行的交易策略。当然,可能还有些地方不够明确,也可能有些细节还不确定要改动,这些可以随时想到随时再改,不必一次做到完美。
-
-
把策略转成程序
-
就是把明确后的策略通过编程转成程序,好让计算机能根据历史数据模拟执行该策略,以及能根据实际行情进行反应并模拟交易或真实交易。
-
简言之,就是把刚刚的策略翻译成计算机可识别的代码语言,即把这个:
每个交易日监测是除st股外的国内A股的所有股票的股价 如果股价低于近20日平均价10%,则用全部可用资金买入该股票 如果股价高于近20日平均价10%,则卖出全部所持有的该股票 -
写成类似这样的代码(下面的代码并不完全符合,只是展示下大概的样子):
def initialize(context): g.security = ['002043.XSHE','002582.XSHE'] def handle_data(context, data): for i in g.security: last_price = data[i].close average_price = data[i].mavg(20, 'close') cash = context.portfolio.cash if last_price > average_price: order_value(i, cash) elif last_price < average_price: order_target(i, 0)
-
这样一来,就把刚才细化好策略转成了代码程序,计算机就能运行了。这个过程你可以理解成用计算机能听懂的语言(代码),把你的策略告诉给计算机了。
-
-
检验策略效果
- 现在计算机理解了你的策略,你现在可以借助计算机的力量来验证你的策略了。基本的检验策略方法有回测和模拟交易两种方法。
- 回测是让计算机能根据一段时间的历史数据模拟执行该策略,根据结果评价并改进策略。继续之前的那个均价的策略例子的话就是这样的:
- 设定初始的虚拟资产比如500000元、一个时期比如20060101到20160101,把这一时期的各种数据如估计股价行情等发给计算机,计算机会利用这些数据模仿真实的市场,执行你刚才告诉它的策略程序。最后计算机会给你一份报告,根据这个报告你就会知道,在20060101的500000元,按照你的策略交易到20160101,会怎样?一般包括盈亏情况,下单情况,持仓变化,以及一些统计指标等,从而你能据此评估交易策略的好坏。
- 如果结果不好,则需要分析原因并改进。如果结果不错,则可以考虑用模拟交易进一步验证。
- 模拟交易是让计算机能根据实际行情模拟执行该策略一段时间,根据结果评价并改进策略。与回测不同,回测是用历史数据模拟,模拟交易使用实际的实时行情来模拟执行策略的。举例就是这样:
- 设定初始的虚拟资产比如500000元,选择开始执行模拟交易的时间点,比如明天。那么从明天开始,股市开始交易,真实的行情数据就会实时地发送到计算机,计算机会利用真实的数据模仿真实的市场,执行你的策略程序。同时,你会得到一份实时更新的报告。这报告类似于回测得到的报告,不同的是会根据实际行情变化更新。同样你能据此评估交易策略的好坏。
- 可见,回测是用历史数据模拟执行策略,模拟交易是用未来的实际行情模拟执行策略。如果策略在回测与模拟交易的表现都非常好,你可以考虑进行完全真实的真金白银的实盘交易。
-
进行实盘交易并不断维护修正
- 实盘交易就是让计算机能自动根据实际行情,用真金白银自动执行策略,进行下单交易。注意,这时不再是用虚拟资产模拟交易,亏损和盈利都是真钱。实盘交易一般也会给出一份类似模拟交易的会不断更新的报告,从而不断要观察策略的实盘表现并及时调整与改进策略,使之持续平稳盈利。
- 量化交易的价值有很多,只提下最突出的价值所在。
- 可以利用大量历史数据检验策略,效率提升百倍。当我们想验证交易策略的时候,一个基本的想法是想知道它在历史上表现如何,这往往需要大量的历史数据与计算量,量化交易做一次回测可能几分钟就可以得到结果了,相比于传统人工做法效率的提升是成百倍的。
- 更科学更客观的衡量交易策略的效果。比如一个关于某技术指标的策略,人工的进行了10个交易日的验证,效果都不错,但这就能说明这指标不错吗?不,10次太少了,你需要更多的验证,比如1000个交易日,人工验证不可行,量化交易则又快又准。而且量化交易还可以利用数学与统计学自动给出客观的结果,比如年化收益率、最大回撤率、夏普比率等。
- 全市场实时捕捉交易机会。当你知道一个盈利条件,当股价一旦满足这条件,你就可以操作盈利。问题是,市场几千个股票,股价时时刻刻都在变动,你能盯住几个,你会错失多少个机会。但量化交易可以利用计算机全市场实时盯盘,可以不错过任何交易机会,加倍你的盈利能力。
- 更多的盈利机会。量化交易可以利用计算机对海量数据分析得到常人难以发现的盈利机会,而且有些机会只有量化交易才能利用。比如你发现一种交易方法,其特点是盈亏的额度相等,但盈利的概率是55%,亏损概率45%。首先这种小差距的概率规律,非量化交易不能发现,其次,要利用这个规律盈利需要大量次数的交易才能稳定盈利,这也非量化交易不可。
- 通常一个投资者做量化交易所需要做的准备,就如同让一个农民自己去造一个大型收割机,而且还是从挖矿开始做起,极度困难,所以量化交易最初在金融与科技最为发达的美国由少数顶级精英发起的。
- 要有各种数据。要有能方便使用的各种投资相关的数据。这要考虑到各种数据的收集、存储、清洗、更新,以及数据取用时的便捷、速度、稳定。
- 还要有一套量化交易的系统,要有能编写策略、执行策略、评测策略的系统。这要考虑到系统对各种策略编写的支持、系统进行回测与模拟的高仿真、系统执行策略的高速、系统评测策略的科学可靠全方面。
- 可能有人会问,做投资之前难道要学当程序员吗?曾经是,但现在量化交易的门槛已大大降低。
- 聚宽是一家量化投研平台,为投资者提供做量化交易的工具与服务,帮助投资者更好地做量化交易。也就是说,在聚宽量化投研平台,“大型收割机”已经为你准备好了,不需要你自己造了,你只需要学会使用它。
- 聚宽让做量化交易的成本极大降低
- 提供多种优质的便于取用的数据
- 提供投资研究功能,便于自由地统计、研究、学习等
- 提供多种的策略评价指标与评价维度
- 支持多种策略的编写、回测、模拟、实盘
- 聚宽让量化交易的成长之路更为平坦
- 在社区可以分享交流量化交易的心得与疑惑
- 在量化课堂可学习量化交易相关的各种知识
- 在策略擂台可以策略pk展现风采证明自己
- 在大赛专区可以获取社会量化比赛资讯
- 在策略商城可以上架策略供他人付费订阅
- 在基金经理孵化训练营则助力快速成长为一名职业基金经理
- 学习这个教程。确切的说,继续学习下一篇。
- 到 聚宽 先随便逛逛。
- 搜索了解下James Simons、DE.Shaw、Emanuel Derman等量化界名人。
本文是量化交易零基础入门教程中的一篇,点击蓝字链接可查看该系列详情。
- 策略编写的基本框架及其实现
- 回测的含义及其实现
- 初步学习解决代码错误
- 周期循环的开始时间
- 自测与自学
- 通过前文对量化交易有了一个基本认识之后,我们开始学习做量化交易。毕竟就像学游泳,有些东西讲是讲不懂,做过就会懂。
- 由于本教程是基于聚宽量化投研平台(www.joinquant.com),所以为了后续的学习,最好去注册一个聚宽量化投研平台的账号。
-
先看一个非常简单的交易策略:
每天买100股的平安银行。 -
为了让这个策略能让计算机执行,首先,要使策略符合“初始化+周期循环”框架,像这样:
初始化:选定要交易的股票为平安银行 每天循环:买100股的平安银行
- 为了将投资灵感高效地转化成计算机可执行的量化策略,必须基于一种模式来写,框架就是指这种模式。而此框架包含两个部分即初始化与周期循环:
- 初始化即指策略最开始运行前要做的事。比如,准备好要交易的股票。
- 周期循环即指策略开始后,随着时间一周期一周期地流逝时,每个周期要做的事。如例中,周期为天,周期循环的则是每天买100股的平安银行。
- 能帮助你理解这一框架的是,其实人本身日常做交易就是符合“初始化+周期循环”框架的,初始化就是已存在人脑的交易思想与知识,周期循环就是每天或每分钟地查看行情、判断、下单等行为。
- 通过编程将策略写成计算机可识别的代码,具体说,我们这里是用python这门编程语言。
- 另外可以用聚宽的向导式策略生成器,这种方法是不需编程的,但灵活性上难免是远不如写代码的。
-
这并非三言两语就能说清,尤其是对于没有编程基础的人。所以我们将通过后续的内容逐步地介绍。首先我们将学习“初始化+周期循环”框架代码的写法。
-
写法一
def initialize(context): 这里是用来写初始化代码的地方,例子中就是选定要交易的股票为平安银行 def handle_data(context,data): 这里是用来写周期循环代码的地方,例子中就是买100股的平安银行
-
写法二
def initialize(context): run_daily(period,time='every_bar') 这里是用来写初始化代码的地方,例子中就是选定要交易的股票为平安银行 def period(context): 这里是用来写周期循环代码的地方,例子中就是买100股的平安银行
-
代码应该往哪里写?
-
两种写法用哪个好?
- 写法一是从前的老写法,将逐步弃用,写法二是聚宽系统改进后的新写法,推荐使用写法二。
- def、context等都是什么意思?
- 其实是在调用聚宽提供好的函数,展开讲很复杂,不理解的话先记住,后面的学习内容会让你理解。
-
剩下的两行代码这么写。完全理解需要学习后续的内容,此处不要求理解。知道大概什么样子往哪里写即可。
-
选定要交易的股票为平安银行:
g.security = '000001.XSHE'
-
买100股的平安银行(市价单写法):
order(g.security, 100)
-
以写法二为例把剩下的代码补上后,完整代码为:
def initialize(context): run_daily(period,time='every_bar') g.security = '000001.XSHE' def period(context): order(g.security, 100)
- 是的。以写法二为例,如图把代码写到策略编辑区,设置好初始资金与起止时间(比如初始资金100000元,起止时间20160601-20161231),频率设置成天。点击编译运行,运行结束后就可以看到结果了。
- 可以看到,若你20160601有初始资金100000元,每个交易日尝试买100股的平安银行,到20161231,你的收益曲线将如图中蓝线般增长。图中红线是基准收益(默认是沪深300指数,代表整个市场增长水平)
- 接下来,点击运行回测,运行结束后就可以看到更为详细的结果,包括下单记录、持仓记录等。
-
首先注意,右上角的箭头按钮能展开运行日志。看到日志中,最后一行是错误的提示信息:
SyntaxError: invalid syntax 汉义是 语法错误:不合法的语法。
-
最后一行之前的是错误的位置信息,一般只看后面就行。
File "user_code.py", line 1 def initialize(context) ^
-
意思是文件user_code.py(就是你的策略代码)的第一行,“^”符号指向的位置有错。你到代码中的这个位置看下,会发现少个冒号。
-
为了顺利运行策略,需要耐心解决错误,但错误的原因极度的复杂多样(所以日志的报错信息也多种多样,不止图上一种),故在此只针对例子讲下新手容易犯的错误:
-
编程界往往把错误叫bug,而不断调试去除错误的过程叫debug,做量化时也是时常听到的说法,大家应该知道下。
-
而且debug通常就是要耗费不低于
写bug写代码的时间的,所以会debug是很重要的能力,大家平时debug的时候不妨多思考下,如何更有效率的debug。当然,我们后续也会介绍些debug的技巧。
- 像刚刚那样,用一段时间内的历史的真实行情数据,来验证一个确定的交易策略在这段时间表现如何,这个过程叫回测。
- 运行回测就是是字面意思,让计算机运行这次回测,运行后会告诉你策略在这段时间表现情况,比如收益率、年化收益率、最大回撤、夏普比率等指标,而且一般也会包括下单记录、持仓记录等。
- 编译运行其实也是让计算机运行这次回测,不过相比于点击运行回测,编译运行的结果比运行回测要简单,只有收益率等指标,因此也速度更快。所以,当还不必要得到详细的结果时,或只是想调试下策略的代码,看是否无误可运行时,编译运行就比运行回测更方便。
- 如果策略频率为天,是每个交易日开始生效,从9:30直到15:00(从股市开市到收市),所以例子中是每个交易日9:30开市循环就开始,一天一次地循环执行买入股票的操作。
- 如果策略频率为分钟,是每个分钟开始时执行,所以例子中的买入股票的操作是每个交易日从9:30:00开始,然后9:31:00,直到14:59:00。接着下一天9:30:00,如此一分钟一次地循环执行的。
- 虽然频率只有为分钟和每天可选,但通过不同的代码可以实现按周按月周期循环,而且分钟级别里下单时间也是可以自己选的,不过代码的写法则与写法一和写法二那样略有不同,后面会讲到。
- 按教程实践下。
- 通过搜索自学K线、bug、debug的含义。
本文是量化交易零基础入门教程中的一篇,点击蓝字链接可查看该系列详情。
- 灵感细化
- 逐步实现策略
- 调整与改进策略
- 自测与自学
- 通过前文基础知识的学习,本文将引导读者运用所学写成一个策略。如果发现某些知识忘了很正常,回头再看就行,用到什么去学什么学习的效率更高。
-
之前也提到过策略灵感的来源多种多样,可能是通过阅读、通过与人交流、或是通过自己感悟与研究等等。灵感最初可能只是模糊的感觉或疑问,比如“感觉低市盈率的股票好像长期收益更好”、“当股价一旦超过整百的时候会不会更容易继续涨一段”、“这个股票和那个股票的股价数据看起来好像符合某种统计规律”等等。验证灵感的一个基本方法是把灵感细化,写成策略做回测。
-
现在你听说了这样一件事,小市值股票过去很长一段时间内收益特别好,但最近不太行了。你觉得这件事比较有价值,想要写成策略来回测验证下。请思考下,应该写一个什么样的策略来验证这件事呢?
-
为了验证灵感,我们把灵感细化成内容如下的这样一个策略。
每天找出市值排名最小的前10只股票作为要买入的股票。 若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票。 买入要买入的股票,买入金额为当前可用资金的10分之一。 -
考虑到不一定要选10个股票,股票数量应该是个可以方便调节的变量,因此策略内容改成如下这样更好。
设定好要交易的股票数量stocksnum 每天找出市值排名最小的前stocksnum只股票作为要买入的股票。 若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票。 买入要买入的股票,买入金额为当前可用资金的stocksnum分之一。
-
因为最终目的是要写成代码交给计算机回测,因此要逐步把文字的意思用代码实现,首先要把这个策略放到之前讲过的初始化与周期循环的策略框架中,如下。
def initialize(context): run_daily(period,time='every_bar') # 代码:设定好要交易的股票数量stocksnum def period(context): # 代码:找出市值排名最小的前stocksnum只股票作为要买入的股票 # 代码:若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票。 # 代码:买入要买入的股票,买入金额为可用资金的stocksnum分之一 -
接下来,你只需要逐步的把策略的全部内容用代码实现出来,技巧是把复杂的内容拆分成多个简单的内容,逐步实现,对于不确定的东西print打印出来看看。往下读之前,建议自己独立实现下试试,基本都是用讲过的内容。遇到困难可以看下我下面给出提示,所有提示后面会给出参考代码。
-
提示
- 代码:设定好要交易的股票数量stocksnum。这句非常简单,需要注意的是要用到之前讲过的全局变量。
- 代码:找出市值排名最小的前stocksnum只股票作为要买入的股票。首先使用get_all_securities取其index得到股票列表。然后,使用获取财务数据的方法找出当前全市场股票中市值最小的前stocksnum个的股票代码。
- 代码:若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票。使用context数据获取当前持仓情况,用for循环语句与if判断语句判断股票是否在当前持仓中,用in判断是否一个元素在某list中,用下单API实现卖出操作。
- 代码:买入要买入的股票,买入金额为可用资金的stocksnum分之一。使用context数据获取当前可用资金总量,用for循环与下单API实现买入每个要买入的股票。
-
参考代码
def initialize(context): run_daily(period,time='every_bar') # 设定好要交易的股票数量stocksnum g.stocksnum = 10 def period(context): # 代码:找出市值排名最小的前stocksnum只股票作为要买入的股票 # 获取当天的股票列表 scu = get_all_securities(date= context.current_dt).index.tolist() # 选出在scu内的市值排名最小的前stocksnum只股票 q=query(valuation.code ).filter( valuation.code.in_(scu) ).order_by( valuation.market_cap.asc() ).limit(g.stocksnum) df = get_fundamentals(q) # 选取股票代码并转为list buylist=list(df['code']) # 代码:若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票。 # 对于每个当下持有的股票进行判断:现在是否已经不在buylist里,如果是则卖出 for stock in context.portfolio.positions: if stock not in buylist: #如果stock不在buylist order_target(stock, 0) #调整stock的持仓为0,即卖出 # 代码:买入要买入的股票,买入金额为可用资金的stocksnum分之一 # 将资金分成g.stocksnum份 position_per_stk = context.portfolio.cash/g.stocksnum # 用position_per_stk大小的g.stocksnum份资金去买buylist中的股票 for stock in buylist: order_value(stock, position_per_stk)
-
至此这已经是一个完整可运行的策略了,你可以试试看,回测结果应该已经可以一定程度上验证灵感了。不过虽然策略完成,我们却发现现在策略是每天进行一次选股并交易,我们觉得这太频繁了,希望能实现通过一个变量period控制操作的周期,即每period天进行一次选股并交易。
-
依然建议先试着自己做下,提示如下,提示之后是参考代码。
- 像stocksnum那样用全局变量的方式建立period变量
- 用一个变量记录策略运行天数
- 用取余运算配合if判断语句判断是否又经过period天
-
参考代码
def initialize(context): run_daily(period,time='every_bar') # 设定好要交易的股票数量 g.stocksnum = 7 # 设定交易周期 g.period = 13 # 记录策略进行天数 g.days = 0 def period(context): # 判断策略进行天数是否能被轮动频率整除余1 if g.days % g.period == 0: # 代码:找出市值排名最小的前stocksnum只股票作为要买入的股票 # 获取当天的股票列表 scu = get_all_securities(date= context.current_dt).index.tolist() # 选出在scu内的市值排名最小的前stocksnum只股票 q=query(valuation.code ).filter( valuation.code.in_(scu) ).order_by( valuation.market_cap.asc() ).limit(g.stocksnum) df = get_fundamentals(q) # 选取股票代码并转为list buylist=list(df['code']) # 代码:若已持有的股票的市值已经不够小而不在要买入的股票中,则卖出这些股票。 # 对于每个当下持有的股票进行判断:现在是否已经不在buylist里,如果是则卖出 for stock in context.portfolio.positions: if stock not in buylist: #如果stock不在buylist order_target(stock, 0) #调整stock的持仓为0,即卖出 # 代码:买入要买入的股票,买入金额为可用资金的stocksnum分之一 # 将资金分成g.stocksnum份 position_per_stk = context.portfolio.cash/g.stocksnum # 用position_per_stk大小的g.stocksnum份资金去买buylist中的股票 for stock in buylist: order_value(stock, position_per_stk) # 策略进行天数增加1 g.days = g.days + 1
- 策略初步写完,把g.period设为13,g.stocksnum设为7,初始资金设为100000,频率为天,回测起止日期为20150101-20180627,然后进行回测,回测结果如下:
- 可见15年到16年该策略表现貌似不错,但随后17年至今则表现平平。
- 自己实现下本文策略
- 思考g.period,g.stocksnum各自设为多少效果比较好?
- 思考此文中,虽然每次都等资金的买入,为何各股票的持仓价值其实还是不同,而且可能越差越大?
- 在本文策略中加入止损或止盈
- 试着在本文策略中选股时排除st股票、停牌股票、与涨停股票。这个问题可能会有些挑战,因为会涉及到简单但没讲过的内容,比较考察搜素与自学能力,但这是做投资交易最为重要的能力。
本文是量化交易零基础入门教程中的一篇,点击蓝字链接可查看该系列详情。
- 评价策略回测的指标
- 建立模拟交易
- 未来函数
- 运行过慢
- 过拟合
- 策略失效
- 收益与风险的取舍
- 自测与自学
- 在学习了如何编写策略后,我们将介绍下评价策略回测的指标,如何建立模拟交易,以及除回测之外还有哪些需要关注的方面。
- 如下图,一个策略回测后会给出一些指标,可以在API文档:风险指标查看这些指标的公式及基本说明。下文将补充介绍下几个重要指标。
- 策略收益。这是最基础的指标,衡量回测期间策略收益率的。
- 基准收益。基准默认是沪深300指数,所以此指标是回测期间基准收益率的。一般来说,基准收益代表市场整体的收益情况,所以如果策略收益长期低于基准收益,往往意味着策略是失败的。通过set_benchmark()这个API可以自定义基准。
- 年化收益率。年化收益率是一个衡量策略盈利能力的重要指标,越大越好。刚刚讲的策略收益这个指标是和回测时间长短强相关的,比如一个普通策略运行10年肯定比优秀的策略跑半年策略收益高,但这样就不利于比较策略的盈利能力。因此,通过数学方法,把策略收益统一互相化归为一年时间的收益率,比如10年的变为平均每年的收益率,半年的变为以这半年盈利能力运行一年的收益率,如此一来,让策略盈利能力在比较时有了一个大致等同的时间标准。
- 最大回撤率。最大回撤率是一个衡量策略风险的重要指标,越小越好。新手初见这个指标的时候可能会感到一点点的困难,其实这个指标是对应着一个很自然的想法的,比如,你现在要实盘用真钱去跟一个策略操作,而你现在是知道这个策略的过去一段时间的历史收益曲线的,你觉得你的最大亏损率估计是多少?建议读者自己随手画下几条曲线当做历史收益曲线,思考下这个问题。一个经典的回答就是最大回撤率的含义,它的思路是这样的,既然我们还在拿历史数据做回测,说明我们应当还是相信历史对未来有指导意义的,那么我现在实盘用真钱去跟策略操作,接下来我们假设策略收益的未来走势应当是跟历史走势相当的,历史走势有一直涨的时候,也有一直跌的时候,那么我实盘跟策略最大亏损率应该就是,我刚开始跟策略就开始走的跟历史走势中一直跌的那一段那样,而且是一直跌且跌的最多的那段,那么历史走势中一直跌且跌的最多的那段跌跌了多少呢?用人眼一般很容易找到是哪段,而且聚宽的回测图中也标出了,如下图。不过不妨进一步思考下怎么算出最大回撤率,然后看下文档中的公式说明,看你的结果是否正确。当然,初学者知道最大回撤率越小越好可能就够了,但有志者应该借机学习如何思考如何评估风险以及量化风险,因为难度相对不高。
- 交易次数。交易次数其实是一个可以初步衡量策略回测结果是否可靠的指标,过少往往意味着回测结果不可靠。试想这样一种情况,别人给你推荐一个策略,策略进行了10年历史数据的回测,年化收益非常高,最大回撤非常小,你很高兴,但仔细一看,交易次数只有2次,此时,你愿意用真金白银去使用这个策略吗?你难免会想可能只是这2次操作运气好而已,这样的回测结果虽好但是不可信不可靠。其实这基于一个简单统计学思想,样本过少,则统计结果不可靠,所以足够多的交易次数才能让回测结果有说服力。目前,回测结果中不能直接看到交易次数了,可以通过回测结果页面的其他指标中的盈利次数与亏损次数相加得到,也可以通过回测结果图表下面的每日买卖大致看出,位置如下图。
- Alpha(阿尔法)与Beta(贝塔)。在资本资产定价模型(CAPM)中,投资组合的收益被分为和市场系统风险相关与和市场系统风险无关的两部分,而Beta与Alpha这两个希腊字母则是该模型中的两个重要系数,分别代表这相关部分与无关部分。其实策略持有的股票可以看成一个投资组合,基准收益作为市场系统收益,Beta则是代表相关部分的策略收益相对市场波动的倍率,如Beta为2则代表市场涨1%,相关部分的策略收益波动涨大概2%(统计意义上并非实时精确),beta为负数代表与市场反向变动。而Alpha则代表独立于市场波动不受其影响的无关部分的策略收益,越大越好,所以如果策略年化收益为负但Alpha为正而且很大,说明策略有超过市场的盈利能力,不过策略整体盈利被与市场相关部分拉下来了。为了便于理解,Alpha与Beta的含义讲的很粗暴,建议数理基础不错的有志者有空去自学下Alpha与Beta的构造思路与过程。
- 夏普比率(Sharpe Ratio)。代表所承担的单位风险所带来的收益,越大越好。夏普比率是在资本资产定价模型进一步发展得来的,不展开讲。
- 之前讲过回测是用历史数据模拟执行策略,模拟交易是用未来的实际行情模拟执行策略,因此当策略完善的自以为差不多没什么问题时,建议建立一个模拟交易观察一段时间,当作进一步的检验。建立的模拟交易的方法很简单,点击回测结果界面,如下图,右上部红色模拟交易按钮,即可新建模拟交易。
- 建立模拟交易成功后,点击聚宽导航栏我的交易,可以看到创建的模拟交易,如下图。
- 点击右边的微信通知开关,将OFF调到ON,按照指示扫描二维码,绑定微信,就能微信接收交易信号了。当策略买卖操作,微信会收到信号提醒类似下图。自定义消息内容请看API send_message。
- 未来函数的前文讲过,即指策略利用了历史当时无法得到的信息,造成回测结果极大失真。未来函数排查方法一般是人工查看,重点看一切跟时间有关的地方,尤其注意各个API关于时间的默认处理方法。当然有时未来函数隐藏的很隐蔽,而更好但稍花时间的方法是用策略建立模拟交易,一般让模拟交易运行几天,多数未来函数问题都能被发现,因为模拟交易是不可能引入未来数据的,所以往往引入未来函数的策略无法成功运行模拟交易。
- 需要注意的是有时同一个代码的策略在模拟交易中是没有引入未来函数的,而是在历史回测中引入未来函数。此时会发现历史回测结果很好,模拟交易也能正常运行,但回测结果是失真的,而模拟交易运行时间长了往往也与回测相去甚远。一个具体的情况是,策略无意中引入了未来信息,导致策略选的股票过去一年中涨的最好的股票买,那么当然用过去一年做回测时效果会很好,但在模拟交易中可能就效果很差。
- 一条判断策略引入未来函数的经验法则是,当你发现策略回测收益极高,回撤又极低,而且各个时间段表现都特别好,感觉自己发现了自动印钞机式的交易策略时,则此策略大概率是引入未来函数了:)
- 策略的运行效率也是需要关注的问题,尽管新手几乎不会遇到,但需要简单了解下,有个意识。有时策略比较复杂,计算量会很大,极端时可能会造成交易延迟,延误买股票的时机,分钟级策略尤其需要关注下耗时问题,而相关函数就是enable_profile() API文档-性能分析
- 用法就是把enable_profile()这行代码复制粘贴放到策略代码的第一行。然后你成功回测后可以在回测详情页面查看性能分析的结果,如下图,从而可以查看哪行代码耗时比较多,从而有目的性的去改进。
- 过拟合(overfitting)常用于描述这样的情况。策略一般都有一些参数,如持股数量、交易频率等,选择不同的参数,固定的一份历史数据下,策略的回测结果好坏也不同,人们往往会选回测结果最好的参数作为策略的参数使用,但随后若换了一份历史数据(换一个时间段)做回测或随后用现实数据运行模拟或实盘,发现效果远不如之前的回测结果,此时很可能策略的参数过拟合了,或说之前选回测结果最好的参数这一行为使参数过拟合了。当参数多的时候,更容易发生。
- 过拟合的核心思想是,过度细致的解读样本数据,从而没有认识到本质的规律,从而使策略或系统失去了普适性,对原样本数据表现极其优异,但对非原样本数据外情况的有效性大大降低。
- 一个关于帮助理解过拟合的比喻是,老师拿一个试卷(样本数据)考学生(策略),学生成绩不理想,老师要教学生(调整参数),此时老师不是教学生学科原理,而是教学生背试卷的答案(过度拟合),当然结果会导致,当再考同一个试卷时学生肯定表现极度优异,但因为只背了答案而没理解原理,所以当换套题目或应用时学生就表现极差了。
- 因此在选择并优化策略的参数时,要考虑参数的鲁棒性,即策略好坏对参数变化的敏感性。对于参数优化与选择对应有复杂最优化理论与鲁棒性测试,对初学者在此问题建议是,控制参数数量,多测几组参数大致看下参数变化对策略的影响,另外考虑进行样本外测试,即用一份样本数据回测挑选参数,用另一份样本数据回测看选择的参数在样本外情况下表现如何。
- 策略一般是有时效的。当你的策略十分完善,并且模拟效果理想,实盘效果也很理想,不要以为策略就会像印钞机一样一直赚钱,策略可以失效的,比如当策略运行中出现历史上罕见的情形时往往就要警惕了,比如最大回撤创历史新高,策略收益率不再增加甚至减少等。如何判断策略是否失效以及找出失效的原因并无通法,但策略失效的原因可能有以下几种,可供参考。
- 策略生效的逻辑基础不再成立。比如策略的有效性是建立在涨跌停制度下的、或是建立在某行业不断成长前提下的、或是建立在全球某资源持续稀缺前提下的等,当这些制度或前提不再成立,如制度调整、新政发布、科技进步等,那么策略自然也就失效了。因此,理解策略有效的逻辑是十分重要的。
- 操作资金量过大。更大的操作资金,会导致更大的冲击成本,即使买入时价更高、卖出时价更低,而当操作资金过大使市场流动性不足承载时,冲击成本会极大的变高,大大降低利润,甚至导致亏损。所以策略是有资金容量的,建议逐步增大策略操作资金量。
- 市场上运行的相似策略过多。同类相似的策略都想赚市场上的同一份钱,然而这份钱是有限的,所以这些策略彼此间会竞争,导致策略赚钱变难,甚至完全失效赚不到钱。具体的表现可能是要买的股票买不到、想卖的股票卖不到理想价位等。因此,交易行业是非常注意保密且不适合分享的行业,而有志者则要注重培养自学能力。
- 市场出现了寄生策略。当你的策略被发现市场中的有心人发现并足够程度的监测时,他可以写出一个针对你策略的策略,从而寄生在你的策略上,比如在比你买之前买入,在你买后拉升股价后卖。这种针对你策略的寄生策略,往往会压缩你策略的盈利空间,使策略失效。
- 往往策略的收益能力与抗风险能力是互相制约不能兼顾的,两者之间如何取舍建议是,达到基本的收益能力后,极力追求低风险,理由是盈利水平往往可以通过增加资金量来提高。具体的讲就是,策略a是一个年化收益率300%,最大回撤率50%的策略,策略b是一个年化收益率30%,最大回撤率5%的策略,只要给策略b提供相当于策略a的10倍的资金量,两者盈利能力就是一样的,但很难让策略a有像策略b一样的抗风险能力。
- 尝试下建立模拟以及用微信接收交易信号。
- 到聚宽的策略擂台栏目看看他人的策略。
- 策略成功回测后,体验下归因分析这个新功能,位置如图。