发明者量化交易入门--从基础到实战

Author: , Created: 2019-06-25 15:48:58, Updated: 2023-10-31 21:01:08

价格自上而下跌破下轨,即跌破支撑线时,我们认为空方力量正在走强,一波下跌趋势已经形成,卖出开仓信号产生。 img 图4-20

如果买入开仓后,价格又重新跌回到了布林线中轨,我们认为多方力量正在走弱,或者空方力量正在加强,卖出平仓信号产生;如果卖出开仓后,价格又重新涨回到布林线中轨,我们认为空方力量正在走弱,或者多方力量正在加强,买入平仓信号产生。

买卖条件

多头开仓:如果无持仓,并且收盘价大于上轨,并且时间非14:45 空头开仓:如果无持仓,并且收盘价小于下轨,并且时间非14:45 多头平仓:如果持多单,并且收盘价小于中轨,或者时间是14:45 空头平仓:如果持空单,并且收盘价大于中轨,或者时间是14:45

策略代码实现

要想实现策略,首先需要考虑我们需要什么数据?通过什么API去获取?然后如何计算交易逻辑?最后通过哪些方式下单方式去交易?接下来,让我们一步一步来实现吧:

第一步:使用CTA策略框架

所谓的CTA策略框架是由发明者量化官方推出的一套标准框架,使用该框架可以不必考虑开发量化交易策略的琐碎问题,直接把精力放在编程交易逻辑上。比如,如果不使用该框架的话,在下单的时候,需要考虑换月移仓、下单买卖价格、下单不成交时撤单或追单等等问题… img 图4-21

上图就是使用发明者量化工具的CTA策略框架。这是一个固定的代码格式,所有的交易逻辑代码从第3行开始编写。在使用中除了需要修改品种代码外(浅黄色),其他地方不用任何修改。

需要注意的是,上图中的品种代码是“rb000/rb888”它代表的意思是信号的数据使用的是“rb000”,交易数据使用的是“rb888”,并且自动换月移仓。当然你也可以指定具体的品种代码,比如把品种代码“rb1910”,就是信号数据和交易数据都使用“rb1910”。

FMZ内置了JavaScript的商品期货交易类库,直接在策略编辑界面点击引用就可以在代码中使用: img

第二步:获取各种数据

仔细想下,都需要哪些数据呢?从我们的策略交易逻辑中发现:首先需要获取当前的持仓状态,然后比较收盘价与布林带指标上中下轨的相互关系,最后判断行情是不是即将收盘。那么接下来让我们一以获取这些数据吧。

获取K线数据

首先就是获取K线数组和上根K线收盘价,因为有了K线数组,才能计算出布林带指标。用代码写出来是这样的: img 图4-22

如上图所示: 第4行:获取K线数组,这是一个固定的格式。 第5行:过滤K线的长度,因为我们计算布林带指标用的参数是20,当K线小于20根的时候,是无法计算布林带指标的。所以这里要过滤下K线的长度,如果K线少于20根,就直接返回,继续等待下一根K线。 第6行:从获取的K线数组中,先获取上根K线的对象,再从该对象中获取收盘价。获取一个数组的倒数第二个元素,就是这个数组的长度减2(r[r.length - 2]);K线数组里面的元素都是一个个对象,对象包含了开盘价、最高价、最低价、收盘价、成交量、时间,要获取收盘价就直接在后面加上“.”和属性名就可以了(r[r.length - 2].Close)。

获取K线时间数据

因为我们是日内策略,需要在收盘前平掉仓位,所以要判断当前K线是不是临近收盘,如果是临近收盘的K线就平掉仓位,如果不是临近收盘的K线就可以开仓,用代码写出来是这样的: img 图4-23

如上图所示: 第8行:获取当根K线的时间戳属性,然后创建一个时间对象(new Date(时间戳))。 第9行:根据时间对象,分别计算小时和分钟数,并判断当根K线的时间是不是14:45。

获取持仓数据

持仓信息是量化交易策略中一个很重要的条件,当交易条件成立时,还需要通过持仓状态和持仓数,来判断是否下单。比如:当买入开仓交易条件成立时,如果有持仓,就不必在重复下单了;如果无持仓,就可以下单。用代码写出来是这样的: img 图4-24 如上图所示: 第11行:获取当前的持仓状态。如果有多单,则值是1;如果有空单,则值是-1;如果无持仓,则值是0。

获取布林带数据

接着就需要计算布林带指标上轨、中轨、下轨的数值了。那就要先获取布林带数组,在从数组中获取上中下轨的数值。在发明者量化工具中,获取布林带数组还很简单,直接调用布林带的API就可以了,难的是获取上中下轨的数值,因为布林带数组是一个二维数组。

二维数组其实很好理解,它就是数组中的数组,那么获取的顺序就是:先获取数组中指定的数组,然后在从指定的数组中获取指定的元素,如下图所示: img 图4-25

如下图,第13行~19行就是用代码获取布林带上轨、中轨、下轨的数值。其中第13行是直接使用发明者量化工具的API,直接获取布林带数组;第14行~16行是先分别获取二维数组中的上轨数组、中轨数组、下轨数组;第17行~19行是分别从上轨数组、中轨数组、下轨数组中获取上根K线的布林带上轨、中轨、下轨数值。 img 图4-26

第三步:下单交易

有了以上数据,就可以编写交易逻辑以及下单交易的代码了。格式也非常简单,最常用到的是“if语句”,用文字可以描述为:如果条件1和条件2成立,下单;如果条件3或条件4成立,下单。如下图所示: img 图4-27

上图中,第21行~24行就是交易逻辑以及下单交易的代码。从上往下分别是:平多、平空、开多、开空。

以开多单(第23行)为例,这是一个“if语句”,在该语句中如果只执行一行代码,花括号“{}”是可以省略的。该语句翻译成文字是:如果当前持仓是0,并且收盘价大于上轨,并且K线时间不是14:45,就“return 1”

细心的你可能会发现,这几行有“return 1”和“return -1”,这是一个固定的格式,意思就是:如果是买入的就写“return 1”;如果是卖出的就写“return -1”。开多和平空都是买入,所以写“return 1”;开空和平多都是卖出,所以写“return -1”。

完整的策略代码

至此一个完整的策略代码就写完了,如果把交易框架、交易数据、交易逻辑、下单买卖等分开来写是不是很简单呢,以下就是这个策略的整个代码: img 图4-28

有两个地方需要注意:尽量(但不是必须)把策略逻辑写成当根K线条件成立,下根K线发单,或者上根K线条件成立,当根K线发单,这样回测的结果与实盘的结果相差不大。不这样写也可以,但是要注意策略逻辑是否正确。一般而言,把平仓的逻辑写在开仓逻辑的前面,这样做的目的是,尽量让策略逻辑符合你的预期。比如:如果策略逻辑刚好赶上反手的时候,反手的规则是,先平仓再开新仓。而不是先开新仓,再平仓。如果我们直接把平仓逻辑写到开仓逻辑前面,就不会出现这种问题。

总结

以上我们学习了开发一个完整的日内量化交易策略的每个步骤,包括:策略简介、布林带指标计算方法、策略逻辑、买卖条件、策略代码实现等。通过这个策略案例,不仅熟悉发明者量化工具的编程方法,还可以根据这个模板改编成不同的策略。

量化交易策略无非是主观交易经验或系统的总结,如果我们在写策略之前,把主观交易中用到的经验或系统,分别写出来,然后再一条一条翻译成代码,你会发现写策略就会容易很多。试试吧!

下节预告

在量化交易策略开发中,如果只能选用一种编程语言的话,那么毫不犹豫,一定是选择Python,从数据获取到策略回测再到交易,Python已经覆盖了整个业务链。在金融量化投资领域占据了重要位置,下节课程我们将学习Python语言入门知识。

课后习题

1、试着用本节的知识,动手实现一个双均线策略。 2、试着用发明者量化工具中的JavaScript语言实现KDJ指标算法。

4.3 Python 语言快速入门

摘要

在量化交易策略开发中,如果只能选用一种编程语言的话,那么毫不犹豫,一定是选择Python,从数据获取到策略回测再到交易,Python已经覆盖了整个业务链。在金融量化投资领域占据了重要位置,本节课程我们将学习Python语言入门知识。

为什么要学习这么多编程语言

回顾之前的课程,一路走来,我们一共学习了:麦语言、可视化语言、JavaScript语言,包括本节要学习的Python语言。可能有小伙伴会有疑问,我是来学习量化交易的,为什么要学习这么多编程语言呢?

其实,每个编程语言都有自己的语言特性,这些语言也没有孰优孰劣之分,更多的是要看策略更适合哪一种编程语言,以及这个编程语言是否符合你自己。所以有句话讲,只有亲自试过才知道。这也就是我们铺开这么多的篇幅,讲编程语言的原因,工欲善其事,必先利其器。

同时我们也致力于为大家打开量化的大门,普及各种编程语言知识,量化并没有我们想象中的高深莫测和遥不可及,相信未来量化会普及并平民化。

量化交易为什么要选择Python

量化交易的流程无非是获取数据、分析计算数据、处理数据等,在数据分析方面,没有其他语言能像Python一样,既精于计算又保持性能。特别是在时间序列分析数据(K线就是时间序列数据)处理,Python有更加简单便捷的优势。另外,比起其他编程语言,Python更简洁易学,阅读好的Python程序感觉就像阅读英语。

选择Python的五大原因

1. 量化运用广泛:

美国的Quantopian与国内的发明者量化都可以用Python语言。

2. 简单易学:

Python的设计哲学是以用户为中心,属于方便调试的解释型语言。

3. 免费开源:

无使用成本,开源代码共享,加强学习与使用效率。

4. 丰富的库:

数据处理、数据运算、可视化、统计分析、技术分析、机器学习…

5. 应用接口:

各大平台数据获取存储调用与实时行情链接下单的接口。

完整策略

为了帮助大家快速理解本节的重点知识,在介绍发明者量化JavaScript语言快速入门之前,先对本节名词概念有个初步了解。我们就用最简单的双均线策略为例:

多头开仓:如果当前没有仓位,并且5周期均线大于20周期均线。 空头开仓:如果当前没有仓位,并且5周期均线小于20周期均线。 多头平仓:如果当前持有多单,并且5周期均线小于20周期均线。 空头平仓:如果当前持有空单,并且5周期均线大于20周期均线。

如果用Python语言代码编写出来,就是这样的: img 图4-29

上图中的代码就是用Python语言写的一个完整的量化交易策略。可以实盘运行,并且自动下单交易。从代码量上看,Python语言比JavaScript语言更多一些,那是因为我们并没有使用CTA交易框架。

但是整个策略的设计流程几乎是一样是:设置行情品种、获取K线数据、获取持仓信息、计算交易逻辑、下单买卖。也就是说,虽然编程语法是不一样的,但写出来的策略逻辑是一样的,那么接下来,让我们学习Python的基础语法吧!

版本选择

Python有两个版本,即:Python2和Python3,曾经有一个段子,说Python就像一个双管枪,但是每次只能用一个管发射子弹,但永远也不知道究竟哪个更准。所以如果你是Python新手,建议直接学习Python3,因为它是最新的,并且Python社区一直在维护。我们的课程也是用Python3讲解的。

标识符

标识符也就是变量的名字,如下图的test、Test、test10、demo等。Python中的一切(变量、函数名和操作符)都区分大小写,也就是说变量名test和变量名Test是两个不同的变量。标识符(变量、函数、属性、函数参数的名字)的第一个字符必须是字母、下划线(),后面的字符还可以是数字,如下图所示: img 图4-30

注释

注释就是对一行代码的翻译或者解释,其规则非常简单,释包括单行注释和块级注释。单行注释以井号(#)开头,块注释以三个单引号(’’’)或以三个双引号(""")开头,以三个单引号(’’’)或以三个双引号(""")结尾,如下图所示: img 图4-31

行与缩进

Python最具特色的就是使用缩进来表示代码块,不需要使用大括号 {} 。 缩进的空格数是可变的,但是同一个代码块的语句必须包含相同的缩进空格数。如下图:在这个案例中,程序会报错。就算if条件是成立的,也不会输出“True”,因为Python在代码运行之前,会自动检测代码语法是否正确,如果代码格式错误,程序将不会运行。原因是第5行代码并没有统一代码的缩进格式。四个空格缩进是Python的固定格式,需要大家多熟悉。 img 图4-32

变量

变量可以保存任何类型的数据,直接写变量的名字就是创建变量,但是当创建变量的时候需要同时设置变量的值,否则程序会报错。等号(=)运算符左边是一个变量名,等号(=)运算符右边是存储在变量中的值。如下图所示:name2就是变量名,“发明者量化”就是变量的值。如果不重新给name2设置新的值,那么name2的值始终是“发明者量化”。 img 图4-33

数据

Python有六个数据类型,其中有3个不可变数据,和3个可变数据。顾名思义不可变数据一旦创建完毕,它的值是不能被改变的,在内存中的地址是唯一的;可变数据是内存中地址的引用,如果它的值改变,其内存地址不变。 不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组); 可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。 img 图4-34

数字

Python的数字类型支持 int(整型)、float(浮点型)、bool(布尔型)、complex(复数)。内置的 type() 函数可以用来查询变量所指的对象类型。如下图: img 图4-35

运算符

像大多数语言一样,Python的数学运算都是很直观的。无论是算术运算符、比较运算符还是逻辑运算符都与我们在学校里面的知识一样。其中算术运算符就是加减乘除的数学运算,比较运算符可以比较两个值是否小于或者小于,逻辑运算符主要有:逻辑与、逻辑或、逻辑非。【交易策略中有哪些常用的字符串可以简单说一下】比如我们在交易策略中,最常用到的字符串就是品种代码了,比如:“rb1910”、“MA1910”。 img 图4-36

需要注意的是:“and”是逻辑与,代表“并且”的意思。“or”是逻辑或,代表“或者”的意思。“!”是逻辑非,代表“否”的意思: “and”是所有条件都为“true”的时候,最终条件才为“true”; “or”是所有条件中,只要有任何一个条件为“true”,最终条件就为“true”。

优先级

如果有一个100*(10-1)/(10+5)表达式,程序是先计算哪一步?中学数学告诉我们:①如果是同一级运算,一般按从左往右依次进行计算。②如果既有加减、又有乘除法,先算乘除法、再算加减。③如果有括号,先算括号里面的。④如果符合运算定律,可以利用运算定律进行简算。麦语言的优先级也是如此,如下图: img 图4-37

布尔值

布尔型代表真假,通常用在条件判断和循环语句中。Python 定义了两个常量“True”和“Flase”代表真假。 其实任何对象都可以转成布尔类型,也可以直接用于条件判断,如下图所示: img 图4-38

字符串

字符串就是文字,在设置品种代码的时候会经常用到字符串比如“if1905”。Python中的字符串用单引号 ’ 或双引号 " 括起来。加号 + 是字符串的连接符。可以根据索引值获取字符串中的某个字符,如下图: img 图4-39

列表

列表是Python中使用最频繁的数据类型,你可以把列表想象成一个容器,只不过容器中的元素是从左往右有序排列的,第一位的元素是0,第二位的元素是1,以此类推。另外Python的列表可以存放任何数据类型,如下图所示: img 图4-40

函数

Python中的函数跟我们中学学的函数没有本质的区别,你可以理解为传进去什么,通过函数的计算,输出什么,如下图所示: img 图4-41

if语句

if语句经常出现在我们生活当中,比如:如果今天下雨,我就打伞。也就是只有当指定条件为 True 时,该语句才会执行代码。注意,注意代码的缩进格式,否则会生成Python错误!如下图所示: img 图4-42

if…else语句

if…else语句也是常用的语句,比如:如果今天下雨,我就打伞;否则,我就不打伞。else语句是if语句的延伸,也就是当指定条件为False时,else后面的语句才会执行代码。如下图所示: img 图4-43

elif语句

由于python并不支持switch语句,所以在多个条件判断时,Python只能用elif语句来实现。比如:如果是阳线,我就看多;否则如果是阴线,我就看空;否则我就观望。如下图所示: img 图4-44

for循环

有时候我们需要获取最近几天的K线数据,就需要从K线数组中,根据K线数据的位置依次获取,那么使用for循环是很方便的,如下图所示: img 图4-45

while循环

我们都知道行情是在不断变化的,如果你想获取最新的K线数组,就得不断的去一遍又一遍地运行相同的代码,那么使用whilex循环,只要指定条件为true,循环就可以一直获取最新的K线数组。 img 图4-46

break语句和continue语句

循环是有前提条件的,只有这个前提条件为“true”的时候,循环才会开始重复的做某些事,直到这个前提条件为“false”的时候,循环才会结束。但是break语句可以在循环执行的过程中立刻跳出循环;continue 语句可以中断某一次循环,然后继续下一次循环。如下图所示: img 图4-47

return语句

return语句会终止函数的执行并返回函数的值。return语句只能出现在函数体内,出现在代码中的其他任何地方都会造成语法错误! img 图4-48

策略架构

策略架构你可以理解为策略的固定格式,发明者量化工具采用轮询模式,以下是经典的商品期货策略架构。

其中第4行~第7行是整个程序的主入口函数,也就是说,计算机是从第4行开始执行代码的;紧接着直接执行第5行,就进入了无限循环;然后在无限循环里面一直执行策略逻辑函数(onTick)和休眠函数(Sleep);onTick函数也就是第1行的代码,你可以在第2行编写策略逻辑;我们知道,在循环中,程序的执行速度是非常快的,那么使用休眠函数(Sleep)可以让程序暂停一会,下面的代码Sleep(500)就是每循环一次,就休眠500毫秒。 img 图4-49

总结

以上就是Python语言快速入门的内容,虽然只是简单的基础知识,但用来写一个简单的量化交易策略还是没问题的。如果需要编写更加复杂的策略,可以参考发明者量化工具Python语言API文档。

下节预告

在技术分析领域的趋势类策略中,均线和通道突破无疑是两大门派。虽然目的都是为了抓住价格走势的趋势,但是这两类策略的交易哲学以及风险特征截然不同。学习了本节Python语言入门,下节我们将带大家手把手编写一个通道突破的量化交易策略。

课后习题

1、试着用发明者量化工具中的Python语言获取历史K线数据。 2、试着写下本节开头的策略代码,并写上注释。

4.4 如何使用Python语言实现策略交易

摘要

上篇我们学习了Python语言的简介、基础语法、策略框架等等。虽然内容很枯燥,但这是你实现交易策略的必备技能,也是必须要学会的。那么本篇我们将趁热打铁,继续上篇的Python基础知识,从一个简单的策略入手,边学边用,一步一步帮助大家实现一个可行的量化交易策略。

策略简介

在众多交易策略中,唐奇安通道策略应该是最为经典的突破类策略之一,早在1970年就已经大名远扬,当时国外有家公司专门对主流的程序化交易策略进行模拟测试和研究,结果表明,在所有策略测试中,唐奇安通道策略最为成功。

后来,在美国又发生了一件交易历史上最著名的“海龟”交易员培训,造就了巨大的成功。当时“海龟们”的交易方法是保密的,但过了十几年,《海龟交易法则》公之于众,人们才发现“海龟们”用的正是改进版的唐奇安通道策略。

突破型交易策略适应于走势比较流畅的交易品种,最常见的突破交易方式就是,利用价格与支撑和阻力的相对位置关系,来判断具体交易买卖点位。本节的唐奇安通道策略也正是基于这个原理。

唐奇安通道策略规则

唐奇安通道属于趋势型指标,它的外表与信号与布林带指标有点相像。但是唐奇安的价格通道是根据一定期间内的最高价格与最低价格构建的。比如:在计算最近50根K线最高价的最大值,形成上轨;计算最近50根K线最低价的最小值,形成下轨。 该指标由3条不同颜色的曲线组成的,默认是20个周期内的最高价和最低价来显示市场价格的波动性,当其通道窄时表示市场波动较小,反之通道宽则表示市场波动比较大。

如果价格升破上轨时,就是买入信号;反之,如果价格跌破下轨时,就是卖出信号。由于其上轨和下轨是用最高价和最低价计算出来的,所以一般情况下,价格很少同时升破和跌破上下通道线。大多数情况下,价格是沿着上轨或下轨单边运动,或者在上轨和下轨之间运动的。

唐奇安通道计算方法

在发明者量化工具中,唐奇安通道的计算方法很简单,直接使用获取指定周期内的最高价或最低价就可以了,如下图所示:第5行就是获取50周期最高价的最大值,第6行就是获取50周期最低价的最小值。 img 图4-50

策略逻辑

唐奇安通道的使用方法有很多,可以单独使用,也可以和其他指标结合在一起使用。本节课程我们将采用最简单的使用方法。即:当价格自下而上突破上轨,即突破上方压力线时,我们认为多方力量正在走强,一波上涨行情已经形成,买入开仓信号产生;当价格自上而下跌破下轨,即跌破支撑线时,我们认为空方力量正在走强,一波下跌趋势已经形成,卖出开仓信号产生。 img 图4-51

如果买入开仓后,价格又重新跌回到了唐奇安通道中轨,我们认为多方力量正在走弱,或者空方力量正在加强,卖出平仓信号产生;如果卖出开仓后,价格又重新涨回到唐奇安通道中轨,我们认为空方力量正在走弱,或者多方力量正在加强,买入平仓信号产生。

买卖条件 多头开仓:如果无持仓,并且收盘价大于上轨 空头开仓:如果无持仓,并且收盘价小于下轨 多头平仓:如果持多单,并且收盘价小于中轨 空头平仓:如果持空单,并且收盘价大于中轨

策略代码实现

实现策略的第一步是先获取数据,因为数据是组成交易策略的前提部分,想象一下,我们都需要哪些数据呢?以及如何获取这些数据?然后再根据这些数据计算设计交易逻辑;最后就是配合交易逻辑买卖下单交易。具体步骤如下:

第一步:使用交易类库

你可以把交易类库想象成一个功能模块,使用交易类库的好处是,可以让你把精力放到编写策略逻辑上面。举个例子:当我们使用交易类库时,开平仓的时候,直接使用交易类库中的下单API就行了;但如果不使用交易类库,开平仓的时候,需要获取盘口价格、需要考虑报单却不成交的问题、需要考虑撤单的问题等等。 img 图4-52

上图就是使用发明者量化工具的CTA策略框架。这是一个固定的代码格式,所有的交易逻辑代码从第4行开始编写。其他地方不用任何修改。

JavaScript的模板类库是内置的,Python需要复制保存这个模板:https://www.fmz.com/strategy/24288 。然后在策略编辑页面点选引用。 当然也可以不用模板类库完成策略。

img

第二步:获取各种数据

仔细想下,都需要哪些数据呢?从我们的策略交易逻辑中发现:首先需要获取当前的持仓状态,然后比较收盘价与布林带指标上中下轨的相互关系,最后判断行情是不是即将收盘。那么接下来让我们一以获取这些数据吧。

获取K线数据

首先就是获取K线数组和当前K线收盘价,因为有了K线数组,才能调用获取N周期最高价或最低价的API。用代码写出来是这样的: img 图4-53 如上图所示: 第4行:获取K线数组,这是一个固定的格式。 第5行:过滤K线的长度,因为我们计算N周期最高价或最低价,用的参数是50,当K线小于50根的时候,是无法计算的。所以这里要过滤下K线的长度,如果K线少于50根,就跳过本次循环,继续等待下一根K线。 第6行:我们用代码“records[len(records) - 1]”先获取到K线数组的最后一个数据,也就是最新的K线数据。这个数据是一个对象,里面包含:开盘价、最高价、最低价、收盘价、成交量、时间等数据,既然它是一个对象,那么我们就直接用“.Close”就是获取最新K线收盘价。

获取持仓数据

持仓信息是量化交易策略中一个很重要的条件,当交易条件成立时,还需要通过持仓状态和持仓数,来判断是否下单。比如:当买入开仓交易条件成立时,如果有持仓,就不必在重复下单了;如果无持仓,就可以下单。这次我们直接把持仓信息封装成一个函数,只需要调用这个函数就可以使用了: img 图4-54

如上图所示: 这是一个获取持仓信息的函数,如果是空仓就返回0;如果持多单就返回1;如果持空单就返回-1。注意看上面的代码: 第2行:创建一个函数,名字是mp,这个函数并没有参数。 第3行:获取持仓数组,这是一个固定的格式。 第4行:判断持仓数组的长度,如果它的长度等于,那肯定是空仓,所以就返回0 第6行:使用for循环,开始遍历这个数组,接下来的逻辑就已经很简单了,如果持多单,就返回1;如果持空单,就返回-1。 第18行:调用刚才写的获取持仓信息函数mp。

获取最近50根K线的最高价和最低价

在发明者量化工具中,直接使用“TA.Highest”和“TA.Lowest”函数就能直接获取,而不用再自己写逻辑计算了。并且“TA.Highest”和“TA.Lowest”函数返回的结果是具体的数值而不是数组。这一点非常方便,不止如此,官方内置了上百个指标函数。 img 图4-55

如上图所示: 第19行:调用TA.Highest”函数,获取50周期最高价的最大值 第20行:调用“TA.Lowest”函数,获取50周期最低价的最小值 第21行:根据50周期最高价的最大值和50周期最低价的最小值,计算出平均值

第三步:下单交易

有了以上数据,就可以编写交易逻辑以及下单交易的代码了。格式也非常简单,最常用到的是“if语句”,用文字可以描述为:如果条件1和条件2成立,下单;如果条件3或条件4成立,下单。 img 图4-56

如上图所示: 第22行:使用交易类库,这是一个固定的格式 第23、24行:这是一个平多单的语句,其中用到了我们之前学过的“比较运算符”和“逻辑运算符”,意思是如果当前持多单,并且收盘价小于中轨,就平掉所有仓位。 第25、26行:这是一个平空单的语句,其中用到了我们之前学过的“比较运算符”和“逻辑运算符”,意思是如果当前持空单,并且收盘价大于中轨,就平掉所有仓位。 第27行:判断当前持仓状态,如果持空仓,才进行下一步。 第28、29行:判断收盘价是否大于上轨,如果收盘价升破上轨,就买入开仓。 第30、31行:判断收盘价是否小于下轨,如果收盘价跌破下轨,就卖出开仓。

总结

以上我们学习了用Python开发一个完整的量化交易策略的每个步骤,包括:策略简介、唐奇安通道的计算方法、策略逻辑、买卖条件、策略代码实现等。本节只是一个简单的策略,作为一个抛砖引玉,方法不止一个,你可以根据自己的交易系统,叠加不同的交易方法,从而形成属于自己的量化交易策略。

下节预告

在量化交易策略开发中,站在编程语言执行速度的角度看,如果说哪个语言最快,那只能是C++莫属不可。特别是在衍生品和高频交易领域,C++独特的语言特定,C++在数值计算上有优势,与JavaScript和Python相比速度能提高几个量级,如果将来你想往衍生品和高频交易领域发展,这将是你不容错过的课程。

课后习题

1、从临摹开始,动手实现本节的策略。 2、试着给本节的策略增加一个均线指标,减低交易频率。

第五章 策略回测、调试及改进

5.1 回测的意义和陷阱

摘要

回测是量化交易与传统交易最不同的地方,根据历史上已经发生过的真实行情数据,快速模拟策略信号触发和撮合交易,得出一段时间内的绩效报告等数据。对国内、国外的股票、商品期货、外汇等市场都是策略开发最重要的组成部分之一。

回测的意义

前面的章节我们学习了主流编程语言的基础部分,以及教大家如何利用这些编程基础,写一些简单的交易策略,可以说万里长征已经走了一大半了。但是,一个策略编写完,肯定不是直接就可以实盘的,它还需要不断的回测——调试——回测——调试——等等,直到策略能够完整的实现模型内容,并且能够顺畅运行。

从量化交易逻辑的角度讲,策略其实就是建立在对市场上的一系列认知和假设,回测可以高效率确定这些假设是否成立和稳定。在历史不稳定时期,可能会带来什么样的损失,以及为预防这些损失辅助作出决策。

另外,从量化交易运行的角度讲,回测可以帮助检测策略逻辑中的bug,如未来函数、偷价、多度拟合等等。为策略可以用于实盘交易提供可靠的证据。

  • 验证交易信号的准确度。
  • 验证交易逻辑和你的想法是否可行。
  • 发现交易系统中的缺陷,并改进原始策略。

因此,回测的的意义是通过历史数据,尽可能真实的还原实际的交易过程,对策略有效性的进行验证,避免为错误的策略付出昂贵的代价,并帮助我们筛选、改进、优化交易策略。

回测的陷阱

回测陷阱之信号闪烁:

交易策略在回测时是基于静态的历史数据。而真实的交易的数据是动态的。举个例子:如果最高价大于昨天的收盘价就买入开仓。这个开仓条件在实盘中,如果K线还未走完,那么最高价就是动态的,交易信号就有可能来回闪烁。而在回测时,回测引擎是基于静态的历史数据是可以模拟撮合成交的。

回测陷阱之未来函数:

未来函数是用到了未来的价格,也就是说当前的条件在未来可能会被修改,同样未来函数也能造成信号闪烁的原因。所以任何函数都具有未来函数特性,比如“之字转向函数”。

如下图:之字转向函数指示了波峰和波谷的转折点,它能根据最新的实时价格相应得调整自身取值,但是如果当前价格变化的时候,之字转向函数计算的结果也会随着改变。如果用了带有未来函数的函数,可能当前下单信号成立了并且下单,但过会儿可能这个信号又不成立了。 img 图5-1

回测陷阱之偷价

所谓偷价行为是指利用过去的价格去交易。举个例子:如果最高价大于某个固定价位即以开盘价买入。这个条件就是在偷价格,因为在实盘中,最高价大于某个价位时,价格已经高于开盘价一定距离了,这时用开盘价是买不到的。但在回测中,是有买入信号的,并且能成交。

还有一种情况,如果价格跳空高开与策略设定的固定价格,回测时可以以固定价格成交,但是在实盘中这个固定价格显然是买不到的。

回测陷阱之不可能成交的价格

不能成交的价格分为几种情况: 第一种:在实盘中,涨停时一般情况下是买不到的,反过来跌停也是如此。但是在回测中却是可以成交的。

第二种:交易所撮合机制是:价格优先、时间优先。有些品种盘口会经常有巨量订单,实盘时如果挂单买卖,需要等待盘口厚度,才能成交甚至不能成交。但是在回测时,挂单买卖是可以成交的。

第三种:如果套利类策略,那么回测利润是很高的,因为回测时每次都已经假设了抢到了这些价差。真实的情况下,很多价差都抢不到,或者只抢到了一条腿,一般来说肯定是不利于你的方向的那条先成交,那么就需要马上去补另一条腿,这时候滑点已经不是1、2个点了,而套利策略本身就赚这几个点的价差,这种情况是回测中无法模拟的。真实利润完全不如回测。

第四种:黑天鹅事件。如下图红圈处,在外汇瑞郎黑天鹅事件中,尽管表面上看有开盘价、最高价、最低价、收盘价,其实当天的极端行情中,中间的价格是真空,大量的止损单,造成踩踏事件,流动性为零,成交难度非常大,但是在回测中却能止损。 img 图5-2

回测陷阱之过度拟合

每次看到下面这张图,我的内心是:哈哈哈哈…通过下面这张图可以看到,一个荒谬的模型,只要足够复杂,是可以完美适应数据的。 img 图5-3

针对量化交易来说,回测是基于历史数据,但历史数据的样本是有限的,如果交易策略的参数过多,或者交易逻辑过于复杂,导致交易策略过多的适应历史数据。

量化策略的建模过程本质上就是一个从大量的貌似随机的数据中找寻局部非随机数据的过程,如果不借助统计学的知识,很容易落入过度拟合的陷阱。

所以,不要自欺欺人。如果发现样本外数据表现不好,又觉得丢掉模型太可惜或者不愿意承认自己这个模型不行,而对着样本外数据继续做模型优化,直到样本外数据上也表现得一样好,那最后受伤的一定是你的真金白银。

回测陷阱之幸存者偏差

华尔街流行着这样一个笑话:假设市场上有1000只参与投资的猴子,第一年,淘汰500只输给大盘的猴子。第二年再淘汰一半,剩下250只猴子。等到第三年末,剩下125只猴子。 img 图5-4

到了第九年,还剩下最后一个猴子。然后你看啊看,左看看右看看就觉得眼熟。最后看到财经杂志封面一下子想起来, “ 噢,这不就是巴菲特吗!”

当然这只是一个笑话,但是你有没有想过,如果有1000个基金经理,那么在10年后,大约有10个基金经理会连续10年跑赢大盘战胜市场。但这可能是随机和运气决定的,和基金经理们的技能没有关系。

就像下图左边那张回测绩效,相信绝大多数投资者都会眼前一亮。该投资策略有非常稳健的表现,而且几乎没有大幅度回撤。 img 图5-5

且慢,如右图所示,真实的情况就在里面。原来左边的回测曲线只是众多回测中表现最好的一只而已。也就是说在左边那个回测中,背后还有众多表现更差的情况。

回测陷阱之冲击成本

在真实的交易环境中,价格是一直在波动的,当你看好一个交易机会,下单的那一刻,可能价格就已经变化了。所以滑点问题,无论是在主观交易中,还是在量化交易中,都是不可避免的。

但是回测是基于在静态数据,很难模拟出真实的交易环境。举个例子:下单价格是1050买入,但实际成交价可能是1051。造成这种现象的原理有很多,比如:极端行情时流动性真空、网络延迟、软硬件系统、服务器响应等。

不加滑点的回测

img 图5-6

如上图,是一个不加滑点的回测,资金曲线比较好看,但在实盘交易中的实际成交价与策略回测的理想成交价存在差异。所以为了减小这种误差,在进行策略回测时,可以设置2个滑点,来提高买入价或降低卖出价。

加上滑点的回测

img 图5-7

如上图,同样的策略,如果加上2跳滑点后,回测的结果与不加滑点的回测结果,相差很大,那么也就代表这个策略需要改进或者淘汰换新。特别是交易频率比较高的策略,回测时加上1~2跳的滑点,可以使回测更接近于真实的交易环境。

总结

可能会有小伙伴问,既然量化交易可能会出现这么多的问题,那我应该怎么证明我的策略是没有问题的呢?其实答案很简单,在策略实盘之前一定要先仿真交易一段时间,如果仿真交易的成交价格与回测时的成交价格,相差无几,那么就证明这个策略是没有问题的,至少策略逻辑是没有问题的。

不管怎么说,对于一个有经验的交易系统开发者来说,回测是必须要做的。因为它能告诉你一个策略的想法在历史交易中是否能被验证有效。但是很多时候回测并不代表未来能盈利。因为回测里面有太多坑了,不用钱买点教训,你是不会明白的。而这些教训都是用真金白银堆出来的。我想读了本篇至少能让你少走很多量化的弯路和陷阱。

课后习题

1、什么是过度拟合,以及如何避免? 2、现实生活中有哪些是幸存者偏差?

5.2 如何做量化交易回测

摘要

回测的意义和重要性已毋庸置疑,在进行量化回测时,应该尽最大可能让策略处于历史的真实环境中,如果忽略历史环境中的细节,可能会导致整个量化回测是无效的。本篇将为大家讲解如何做量化交易回测。

回测就相当于数据回放,通过回放历史K线数据,并进行模拟真实的交易规则进行买卖,最终汇总一个时间段内的夏普比率、最大回撤率、年化收益率、资金曲线等数据。目前有很多软件都能做到回测,比如品种很全的文华财经、可以灵活定制的VNPY等等。

发明者量化作为一款商用量化交易软件,自带高性能回测引擎,采用for-loop(轮询)回测框架,进行向量化计算,速度更快。并且统一回测和实盘的代码,部分解决“回测易、实盘难”的困境。

回测界面介绍

我们以发明者量化的麦语言策略为例,打开发明者量化交易工具的官网(www.fmz.com)。依次点击控制中心、策略库、选择一个策略、模拟回测,进入到如下页面: img 图5-8

在回测配置界面,可以根据自己的实际需求定制。如:设置回测时间,K线周期,数据种类(模拟级别数据或实盘级别数据。相比之下模拟级别数据回测速度更快,实盘级别数据回测更精准)。另外,还可以设置回测时的手续费以及账户初始资金等等。

点击麦语言交易类库,首先是交易设置标签,发明者量化交易工具中的麦语言策略有两种回测执行方式,即:收盘价模型和实时价模型。收盘价模型指当前K线走完才执行模型,在下根K线开始的时候执行交易。实时价模型指的是每次价格变动都执行一次模型,当交易信号成立时,就立即交易。如下图: img 图5-9

默认开仓手数是指回测时开平仓数量,最大单次交易下单量就是单笔交易委托给回测引擎的最大开平仓数量。实盘的成交价位与预设的成交价位间出现偏移,这种偏移一般是向不利于交易者的方向移动,导致交易出现额外的损失,所以加入滑点是必须的,国内商品期货一般是加入1跳~2跳,甚至更多,来模拟真实的交易环境。

期货选项中填入要回测的合约品种,如rb000或rb888。实盘选项主要用于实盘交易,在回测中保持默认设置即可。如果自动恢复进度点击为true,那么当策略在实盘运行中停止机器人后,重启机器人会自动恢复之前的信号位置,而不用再重新计算信号。设置下单重试次数默认为20,当下单失败后,会尝试重新下单。网络轮询间隔就是机器人每隔段时间去执行一次策略代码。 img 图5-10

现货交易选项主要针对数字货币交易,在回测中保持默认设置即可。可以指定单笔交易量、最小交易量、定价货币精度、交易品种精度、手续费、账户同步时间、盈亏统计间隔等,另外对于个别数字货币交易所,还可以设置杠杆倍数以及其他相关设置。 img 图5-11

策略回测

在回测之前,先确定好你的交易策略,这里我们以恒温器 Thermostat 策略为例,这种策略会根据市场状态,在趋势行情中采用趋势策略,在震荡行情中采用震荡策略。源代码如下图(也可以到发明者量化官网的策略广场直接下载): img 图5-12 在模拟回测界面,配置好回测设置后,直接点击开始回测按钮,几十秒之后回测结果即刻呈现。在回测日志中,记录了回测用时多少秒,日志总数以及交易次数。其中账户信息打印了策略回测最终绩效结果:平均盈亏、持仓盈亏、保证金、手续费以及预估收益等。 img 图5-13

状态信息栏中则记录了交易品种、持仓量、持仓价格、最新价格、上次信号种类、持仓后的最高价和最低价、更新次数和时间以及资金信息。另外在浮动盈亏标签中,则展示了账户的详细资金曲线,还包括常用的绩效指标:收益率、年化收益率、夏普比率、年化波动率、最大回撤率,基本可以满足绝大多数的用户需求。

其中,最为重要的绩效指标就是:夏普比率。它是同时对收益与风险加以考虑的综合指标,也是衡量一个基金产品的重要参考指标,通俗来讲,就是你每挣1块钱承担了多少钱的风险,所以夏普比率的值是越高越好。

年化波动率顾名思义就是日波动率x了每年的交易日数,它是衡量基金的风险,但绝对不是全部风险。比如策略A波动率较大,但一直波动向上,收益率良好,策略B波动率很小,但一直横着不动,我们能说策略B优于策略A吗?如下图策略A: img 图5-14

最后,在日志信息栏中,详细记录了回测时每一笔交易的撮合情况,包括交易的具体时间、交易所、买卖以及开仓平仓类型、回测引擎撮合的成交价格、交易数量以及打印信息等等。 img 图5-15

回测之后

很多时候,甚至绝大多数情况下,回测的结果都会与自己的期望,相差甚远。毕竟一个长期持续稳定盈利的策略,不是那么容易就能得到的,这需要你对市场认知能力。

如果你的策略回测结果是亏钱的,也不要灰心,这其实是很正常的。先看一下策略逻辑是不是写错了,是不是采用了极端参数,是不是开平仓条件过多等等,必要时也可以从另一个角度重新审视自己的交易策略和交易理念。

如果你的策略回测结果非常好,资金曲线非常完美,夏普比率超过1甚至更多。也先别急着高兴,遇到这种情况,大部分是利用了未来函数、或者偷价、或者过度拟合、或者没有设置滑点等等,可以利用样本外数据和仿真实盘交易,来排除这些问题。

总结

以上就是整个交易策略回测的整个流程介绍,可以说已经具体到每一个细节。需要注意的是,历史数据回测毕竟是一个所有风险已知的理想环境。所以策略的回测时间最好是经历一轮牛熊市,有效的交易次数应当不低于100次,这样可以避免部分幸存者偏差。

市场永远是在变动和进化中的,历史回测好的策略并不代表未来就一定很优秀,不能只让策略应付回测环境中已知的风险,更要应对未来的未知风险。所以增加策略的抗风险能力和普适性是非常有必要的。

课后习题

1、试着复制本节中的策略,并回测绩效报告 2、根据自己的交易经验,尝试改进并优化本节中的策略

5.3 如何读懂策略回测绩效报告

摘要

当我们的策略回测完成之后,发明者量化交易工具会在网页中输出包含各种绩效指标、收益曲线图。但可能因为我们对这些指标的释义和内容不太熟悉,导致无法准群判断策略好坏,本篇将从主要的指标概念入手,帮助大家读懂策略回测绩效报告,分辨出策略的优劣。当然大部分量化交易工具都有这种回测绩效报告,其内容也大同小异,学会了本节内容,就算换做另一个交易工具也同样适用。

客观与完整的评价

无论是实盘交易数据的记录,还是采用历史数据进行回溯(Back-Testing)的回测报告,模型的优劣都是通过对交易情况的统计来进行评价。

而问题的关键在于,到底需要通过哪些统计数据进行比较?先来看一个例子:如下图,假设在同一时间周期的测试中得到以下两组数据,我们能从中判定哪一个模型表现更优秀么? img 图5-16

答案是,不能。评价体系的片面性将导致量化交易系统走向绝境。

交易系统必须能通过历史回测才可以投入使用。无法通过历史回测的交易系统不可能长期在实际交易中获利。历史回测是交易系统投入实盘的必要前置环节。

能通过历史回测的交易系统不一定是好用的交易系统,但不能通过历史回测,则一定不是好用的交易系统。一般而言,我们需要从稳定性、可持续性、判断是否正期望等角度去分析绩效报告。 img 图5-17

如上图,但凡接触过量化的交易者,可能见过这些连篇冗长、晦涩难懂的回测绩效各项数据术语,在这些绩效数据中,甚至有许多数据都是互相矛盾的。好多量化初学者,反而会疑惑,到底要着重看哪些数据?

上图中的绩效指标名词,一般可以分为几大类:绩效比率、周期分析、各种曲线、极端交易分析等等。就算严格站在基金产品的角度,大部分只是回测计算结果的展示,实际应用意义不大,比如:账户资金额度需求、持有收益、信心限度等等。甚至你只需要关注重要的几个就可以了。下面我就挑选在回测绩效指标中,最重要的几个作为详细讲解。

重要的绩效指标

最大资产回撤比率(Max Drawdown)

最大回撤计算公式如上,对于


Related

More

Hailhydra2 好文章啊!

悟空量化 mark