Python算法交易实战

978-7-115-58266-9
作者: 塞巴斯蒂安·多纳迪奥(Sebastien Donadio)
译者: 刘江峰 瞿源
编辑: 胡俊英

图书目录:

详情

本书由浅入深地讲解了算法交易的相关知识,首先从基础知识和环境配置讲起,其次讲解如何通过编程完成交易信息的生成与交易策略的实施,随后介绍众多算法交易策略,以及如何管理算法策略中的风险,最后带领读者用Python建立自己交易系统,并迎接算法交易的深层挑战。 全书共分为10章,包括算法交易的基础原理、通过技术分析解读市场、通过基础机器学习预测市场、人类直觉驱动的经典交易策略、复杂的算法策略、管理算法策略中的风险、用Python构建交易系统、连接到交易所、在Python中创建回测器、适应市场参与者和环境。

图书摘要

版权信息

书名:E读版-Python算法交易实战-978-7-115-58266-9

ISBN:978-7-115-58266-9

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。


著    [法] 塞巴斯蒂安•多纳迪奥(Sebastien Donadio)

     [印] 苏拉夫•戈什(Sourav Ghosh)

译    刘江峰 瞿 源

责任编辑 胡俊英

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e58266”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。


Copyright @2019 Packt Publishing. First published in the English language under the title Learn Algorithmic Trading.

All rights reserved.

本书由英国PacktPublishing公司授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。

版权所有,侵权必究。


在现代社会,仅仅凭借比别人更快来获得显著的交易优势已越来越难,还需要依靠复杂的交易信号、预测模型和交易策略。本书基于Python讲解算法交易的相关知识和实践技巧,旨在引导读者深入了解现代电子交易市场和市场参与者的运作方式,构建有效的算法交易系统。

全书内容分为10章,从算法交易的基础原理、通过技术分析解读市场、通过基础机器学习预测市场、人类直觉驱动的经典交易策略、复杂的算法策略、管理算法策略中的风险、用Python构建交易系统、连接到交易所、在Python中创建回测器、适应市场参与者和环境几个方面介绍了算法交易中的核心知识点,并通过Python演示了具体编程实现。

本书适合软件工程师、金融交易员、数据分析师以及任何想开始“算法交易之旅”的读者阅读。


塞巴斯蒂安•多纳迪奥(Sebastien Donadio)是Tradair公司的首席技术官,负责技术指导。他具有丰富的专业技术从业经验,曾担任HC Technologies公司的软件工程负责人、高频FX公司的合伙人和技术总监、Sun Trading公司的定量交易策略软件开发者。他还拥有Bull SAS公司的研究经验,并且曾在法国兴业银行(Société Générale)担任IT信用风险经理。在过去的十年中,他曾在美国芝加哥大学、纽约大学和哥伦比亚大学教授过各种计算机科学课程。他的主要爱好是技术,除此之外,他还是一名潜水教练和经验丰富的攀岩运动员。

苏拉夫•戈什(Sourav Ghosh)在过去十年中曾在多家高频算法交易公司工作。他为世界各地的交易所建立和部署了极低延迟、高吞吐量的算法交易系统,涉及多个资产类别。他擅长统计套利做市策略,以及全球流动性最强的期货合约的配对交易策略。他在美国芝加哥一家贸易公司担任高级量化开发人员,拥有美国南加州大学的计算机科学硕士学位。他感兴趣的领域包括计算机结构、金融科技、概率论和随机过程、统计学习和推理方法,以及自然语言处理。


纳塔拉吉•达斯古普塔(Nataraj Dasgupta)是RxDataScience公司的高级分析副总裁。他从事IT行业超过20年,曾在菲利普•莫里斯(Philip Morris)公司、国际商业机器(IBM)公司、瑞银投资银行(UBS Investment Bank)和普渡制药(Purdue Pharma)公司的技术和分析部门工作。他在普渡制药公司领导数据科学团队,开发了该公司屡获殊荣的大数据和机器学习平台。在加入普渡制药公司之前,他在瑞银集团担任副总监,负责外汇交易部门的高频交易和算法交易技术的工作。除了在RxDataScience担任职务外,他还撰写了Practical Big Data Analytics,并与人合著了Hands-on Data Science with R,目前还供职于英国伦敦帝国理工学院。

拉坦拉尔•马哈坦(Ratanlal Mahanta)目前在bittQsrv担任量化分析师,bittQsrv是一家为投资者提供量化模型的全球量化研究公司。他在量化交易的建模和模拟方面有多年的经验,拥有计算金融学硕士学位,他的研究领域包括量化交易、最优执行和高频交易。他在金融行业有10多年的工作经验,擅长解决市场、技术、研究和设计交叉方面的难题。

吉里•皮克(Jiri Pik)是一位人工智能架构师和策略师,曾与大型投资银行、对冲基金等合作。他曾在众多行业中设计并交付了许多具有突破性的交易、投资组合和风险管理系统,以及决策支持系统。他的咨询公司Jiri Pik-RocketEdge可为客户提供经过认证的专业知识、判断力和快速执行力。


在现代社会,仅仅凭借比别人更快来获得显著的竞争优势已越来越难,还需要依靠复杂的交易信号、预测模型和交易策略。本书希望能为广大读者提供相关知识和可参考的实践经验,能够引导读者深入了解现代电子交易市场和市场参与者的运作方式,以及如何使用Python设计、构建实用并能带来赢利的算法交易业务所需的知识。

本书介绍算法交易和配置执行任务所需的环境。你将学习算法交易业务的关键组件,以及在着手构建自动化交易项目之前需要提出的问题。

通过阅读本书,读者能够学习如何开发量化交易信号和交易策略,掌握一些著名交易策略的运作和实施方法,还将了解、实施和分析更复杂的交易策略,包括波动率策略、经济发布策略和统计套利交易策略,以及学习如何使用算法从头开始构建一个交易机器人。

现在,请你准备好与市场建立联系,开始研究、实施、评估,并安全地在实际市场中操作算法交易策略。

本书的目标读者是软件工程师、金融交易员、数据分析师、企业家,以及任何想开始“算法交易之旅”的人。如果你想了解算法交易的工作原理、交易系统的所有组成部分、黑盒和灰盒交易所需的协议和算法,以及如何建立完全自动化且可带来赢利的交易业务,那么本书就是适合你的!

第1章“算法交易的基础原理”介绍什么是算法交易,以及算法交易与高频交易或低延迟交易之间的关系。本章将讨论从基于规则到人工智能的算法交易的演变,并将研究基本的算法交易概念、资产类别和工具。你将学习如何为算法决策打下基础。

第2章“通过技术分析解读市场”涵盖一些流行的技术分析方法,并展示如何将其应用于市场数据分析。本章将介绍如何利用市场趋势、支持和阻力进行基本的算法交易。

第3章“通过基础机器学习预测市场”介绍一些简单的回归和分类方法,并解释在交易中应用监督统计学习方法的优势。

第4章“人类直觉驱动的经典交易策略”探讨一些基本的算法策略(动量、趋势、均值回归),并解释它们的工作原理以及优缺点。

第5章“复杂的算法策略”通过研究更高级的方法(统计套利、配对交易)以及它们的优缺点来进一步介绍基本算法策略。

第6章“管理算法策略中的风险”解释如何衡量和管理算法策略中的风险(市场风险、操作风险和软件实施缺陷)。

第7章“用Python构建交易系统”描述基于前几章内容创建的算法支持交易策略的功能组件。本章将介绍用Python构建一个小型交易系统,并使用前几章中的算法构建一个能够进行交易的交易系统。

第8章“连接到交易所”介绍交易系统的通信组件,将介绍使用Python中的quickfix库将交易系统连接到真实的交易所。

第9章“在Python中创建回测器”介绍如何通过运行包含大量数据的测试来验证交易机器人的性能,从而改善交易算法。一旦实现模型后,就有必要测试交易机器人在交易基础设施中的行为是否符合预期。

第10章“适应市场参与者和环境”讨论为什么在实时交易市场中部署策略时,其执行效果不如预期,并提供如何在策略本身或基础假设中解决这些问题的例子。本章还将讨论为什么表现良好的策略在性能方面会慢慢衰退,并提供一些简单的示例来说明如何解决此问题。

在阅读本书之前,读者最好具备金融和Python的基础知识,结合本书在异步社区提供的代码和彩图资源,充分理解书中所讲的算法及交易知识,并参照相关示例进行实践。

本书中使用了许多文本约定。

CodeInText: 表示文本中的代码,如数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟URL、用户输入等。举例说明:“该代码将使用pandas_datareader包中的函数DataReader。”

代码块设置如下:

import pandas as pd
from pandas_datareader import data

当我们希望引起你对代码特定部分的注意时,相关的内容将以粗体显示:

if order['action'] == 'to_be_sent':
            #Send order
            order['status']='new'
            order['action']='no_action'
            if self.ts_2_om is None:

粗体:表示新术语,重要词或你在屏幕上看到的单词。例如,菜单或对话框中的单词会出现在文本中。下面是一个示例:“A mean reversion strategy that relies on the Absolute Price Oscillator (APO) trading signal indicator。”

警告或重要说明。

提示和技巧。


本书由异步社区出品,社区(https://www.epubit.com/)为您提供相关资源和后续服务。

本书提供配套资源,要想获得该配套资源,请在异步社区本书页面中单击,跳转到下载界面,按提示进行操作即可。注意:为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。

您还可以扫码右侧二维码, 关注【异步社区】微信公众号,回复“e58266”直接获取,同时可以获得异步社区15天VIP会员卡,近千本电子书免费畅读。

作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,点击“提交勘误”,输入勘误信息,点击“提交”按钮即可。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

扫描下方二维码,您将会在异步社区微信服务号中看到本书信息及相关的服务提示。

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/ contribute即可)。

如果您所在的学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值内容动力之源。

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT技术图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。

异步社区

微信服务号


在第1部分,本书将介绍算法交易的基础知识和如何配置执行本书任务所需的环境。在着手进行机器人交易项目之前,你将学习交易的关键组成部分以及需要提出的问题。

本部分包括以下内容。

 第1章 算法交易的基础原理


算法交易也称自动交易,旨在通过一个包含一套指令的程序来达到交易目的。与人类交易者相比,这种交易可以更快地产生利润和损失。在本章中,你或许将第一次接触到自动化交易。我们将带领你完成实现第一个交易机器人的不同步骤,你将学习交易世界及其背后的技术交易组成部分。本章还将详细介绍所使用的工具,在结束本章学习后,你将能够用Python编写自己的第一个本地交易策略。

本章将介绍以下主题。

 为什么要交易。

 介绍算法交易和自动化。

 算法交易系统的组成部分。

 配置你的第一个编程环境。

 实施你的第一个本地策略。

从“罗马时代”到今天,交易是人类社会固有的一部分。在价格低的时候购买原材料,在价格高的时候转卖,一直是许多文化的一部分。在古罗马,富有的罗马人利用罗马广场来交换货币、债券和进行投资。在14世纪,商人在威尼斯进行政府债务谈判。最早的证券交易所于1531年在比利时的安特卫普创建,商人们曾在此定期聚会以交换期票和债券。这个过程让人们付出了高昂的代价,但也带来了丰厚的回报。1602年,荷兰的投资者们参与了这个高潜在回报率的高昂项目。同一时期,一种著名的郁金香销往世界各地,为投资者和销售方创造了一个有利可图的市场。由于许多人参与这种花的价格的“投机”,因此,一种期货合约就这样产生了。

所有这些事件都有一个共同的根源:有钱人愿意赚更多的钱。如果我们想回答“我们为什么要交易?”这一问题,答案是为了赚更多的钱。然而,几乎所有前文列举的历史例子都以非常糟糕的结局收场。这些投资被证明是不良投资,或者说,在大多数情况下价值被高估了,交易者最终亏损了。对于本书的读者来说,这实际上是一个很好的教训。即使交易听起来是有利可图的,也要始终牢记赢利能力的短暂性,并且还要考虑投资带来的固有风险。

本节将介绍交易的基本知识,以及驱动市场价格和供求关系的因素。

正如1.1节中提到的,长期以来,交易就已经存在了,当时人们希望彼此交换商品,并在此过程中获利。现代市场仍然是由供求关系的基本经济原理驱动的。当需求大于供给时,商品或服务的价格可能会上涨,以反映商品或服务相对于需求的短缺。相反,如果市场上充斥着某一产品的大量卖家,价格可能会下降。因此,市场总是试图反映特定产品的可用供需之间的均衡价格。稍后我们将看到这是当今市场价格发现的基本驱动力。随着现代市场和可用技术的发展,价格发现变得越来越有效。

直观地讲,你可能会得出这样的结论:随着在线零售业务的发展,所有卖方的产品价格都变得越来越有效,而最好的报价始终是客户所购买的价格,因为信息(价格发现)是非常容易获得的。现代交易也是如此。随着技术和法规的进步,越来越多的市场参与者可以获取完整的市场数据,从而使得价格发现的效率比过去提高了很多。当然,市场参与者接收信息的速度,做出反应的速度,能够接收和处理数据的粒度,以及每个市场参与者从接收到的数据中得出交易见解的复杂程度,是现代交易的竞争所在,我们将在后文中介绍。但首先要介绍有关现代交易的一些基本概念。

在本小节中,我们将简单介绍什么是不同类型的市场部门,以及它们与资产类别有何不同。

市场板块是指可以进行交易的不同种类的基础产品。其中较受欢迎的市场板块是商品(金属、农产品)、能源(石油、天然气)、股票(不同公司的股票)、利率债券(用债务换取的息票,会产生利息,因此而得名)、外汇(与不同货币之间的现金汇率相关),如图1-1所示。

图1-1

资产类别是指在不同的交易所中可用于交易的不同种类的实际工具。比如在1.2.1小节中提到的股票、利率债券、外汇,我们可以拥有这些基础衍生品的金融工具。衍生品是建立在其他工具之上的工具,并且有一些额外的限制条件,我们将在本节中进行探讨。较流行的两种衍生品是期货和期权,它们在许多衍生品电子交易所中都有大量的交易。

我们可以拥有与标的物,如商品、能源、股票、利率债券、外汇等相关的期货合约,这些合约与标的物的价格相关,但有不同的特点和规则。对期货合约的简单理解是,它是买方和卖方之间的合约,卖方承诺在未来某个日期(也称到期日)出售一定数量的标的物,买方同意在特定日期以特定价格接受约定数量的标的物。

例如,黄油生产者可能希望保护自己免受未来可能出现的牛奶价格暴涨的影响,而黄油的生产成本直接取决于牛奶的价格,在这种情况下,黄油生产者可以与牛奶生产者签订协议,希望牛奶生产者在未来以一定的价格向他们提供足够的牛奶。相反,牛奶生产者可能会担心未来可能发生牛奶买家不足的情况,并可能希望通过与黄油生产者达成协议,希望黄油生产者在未来以一定的价格至少购买一定数量的牛奶来降低风险,因为牛奶是易变质的,所以销售不足意味着牛奶生产者将蒙受较大损失。这是一个非常简单的期货合约交易的例子,现代的期货合约要比这个例子中的复杂得多。

与期货合约类似,我们可以对标的物,如商品、能源、股票、利率债券、外汇等建立期权合约,这些合约与标的物的价格挂钩,但具有不同的特点和规则。与期货合约相比,期权合约的不同之处在于,期权合约的买卖双方可以选择拒绝在特定的金额、特定的日期、特定的价格的买卖。为了保障参与期权交易的交易双方,就有了溢价的概念。溢价是指买入或卖出期权合约所预先支付的最低金额。

如果相关产品的价格在到期前上涨,拥有看涨期权或购买权(而不是到期时的购买权)的一方就赚钱,因为现在这一方可以在到期时行使其期权,以低于当前市场价格的价格买入标的产品。相反,如果标的产品的价格在到期前下跌,这一方现在可以选择退出而不行使其期权,从而只损失他们支付的期权费。认沽期权与此类似,但它只赋予认沽合约的持有人在到期时卖出的权利,而没有卖出的义务。

本书不会太深入地研究不同的金融产品和衍生品,因为这不是本书的重点,但这个简短的介绍是为了说明这样一个概念:有很多不同的可交易金融产品,它们在规则和复杂性方面有很大的不同。

由于本书主要是为了介绍现代算法交易,因此本书将着重尝试讲解现代电子交易所是如何出现的。人们在交易所里互相大喊大叫,并打出手势来传达他们以一定价格买卖产品的意图的日子已经一去不复返了。这些仍然是电影中有趣的想法,但现代交易看起来却明显不同了。

当今大多数交易都是通过不同的软件以电子交易的方式完成的。市场数据提供程序(market data feed handlers)可以处理和理解由交易所传播的市场数据,以反映限价簿(limit book)和市场价格(出价和要约)的真实情况。市场数据以交易所和市场参与者事先商定的特定市场数据协议(market data protocol,如FIX/FAST、ITCH和HSVF)发布。然后,同样的软件可以将这些信息反馈给人们或者通过算法做出决定。接下来,这些决策又被类似的软件——订单输入网关(order entry gateways)传达给交易所,并通过发送特定的订单类型(GTD、GTC、IOC等),告知交易所我们对特定产品的兴趣,以及对以特定价格买入或卖出该产品的兴趣。这就需要了解市场和市场参与者事先约定的订单输入协议(FIX、OMEX、OUCH等)。

在与可用的市场参与者进行匹配后,该匹配通过订单输入网关再次回传给软件,并回传给交易算法或人们,从而完成交易,通常是完全电子化的。这种往返的速度根据市场、市场参与者和算法本身的不同而有很大差异,有时耗费的时长可以短至10ms以下,慢的话耗费的时长也可以控制在几秒内,稍后将详细讨论。

图1-2为描述性的视图,说明信息从电子交易所流向相关的市场参与者,以及信息回流到交易所的情况。

如图1-2所示,电子交易所维护着客户购买订单(出价)和客户要价订单(请求)的账本,并使用市场数据协议发布市场数据,向所有市场参与者提供账本的状态。客户端的市场数据提供处理程序对传入进行解码,并建立一个限价订单簿,以反映电子交易所看到的订单簿的状态。然后通过客户端的交易算法进行传播,再通过订单输入网关生成外发订单流。外发订单流通过订单输入协议传给电子交易所。这又会产生进一步的市场数据流,因此交易信息可持续循环。

图1-2 

本节将讲解很多新的概念,如交换订单簿(由市场参与者发出的不同种类的订单组成)、交换匹配算法、交换市场数据协议和交换订单输入协议等。接下来正式对这些概念进行更详细的讨论。

交换订单簿保存了客户下达的所有买入和卖出订单,它跟踪所有传入订单的属性——价格、合同或股票数量、订单类型和市场参与者标识。买入订单(或出价)从最高价(最好的价格)到最低价(最差的价格)排序。就匹配而言,价格较高的出价有较高的优先权。相同价格的出价的优先级取决于匹配算法。最简单的先进先出(First In First Out,FIFO)算法采用的是直观的规则,即按照相同价格的订单进来的顺序进行优先级排序。这在后面我们讨论复杂的交易算法如何利用速度和智能来获得更高的订单优先级,以及对赢利的影响时,将非常重要。卖出订单(或要价)从最低价(最好的价格)到最高价(最差的价格)排序。同样,对于相同价格的要价,匹配优先级的方法取决于交易所对特定产品采用的匹配算法,这部分我们将在后文更详细地阐述。市场参与者可以下达新的订单,取消现有订单,或者修改价格和股票或合约数量等订单属性。针对市场参与者发出的每一个订单,交易所都会生成公开的市场数据。利用交易所公开的市场数据,市场参与者可以准确地了解交易所的订单簿是什么样的(取决于交易所选择隐藏哪些信息,但我们暂时忽略这种细微差别)。

当收到的出价等于或高于最佳(最低价)的要价订单时,就会发生匹配。反之,当收到的要价等于或低于最佳(最高价)的要价订单时,则发生匹配。输入的进取订单将继续与账本中现有的被动订单进行匹配,直到满足这两个条件之一。要么是新的激进订单完全匹配,要么是剩余订单的价格比传入订单的价格更差,因此,匹配不能发生。这是因为一个基本规则,即订单的价格不能以低于其入市时的限价进行匹配。现在,就同一价位的订单而言,匹配的顺序是由交易采用什么匹配算法规则决定的。

1.先进先出匹配

前面简单介绍了先进先出算法,我们通过表1-1的例子来展开。假设当交易所竞价单A、B、C在该时间顺序以10.00美元(1美元合人民币6.8元左右)的价格输入时,订单簿的状态如下。那么,在同样的价格下,订单A的优先级高于订单B,订单B的优先级高于订单C,竞价订单D价格低至9.00美元。同样,在要价方面,订单X是以11.00美元的价格进入的,先于订单Y(价格也是11.00美元)。因此,订单X比订单Y有更高的优先权,然后问询订单Z是以更差的价格12.00美元进入的。

表1-1

竞价单

要价

Order A:以10.00美元购买1股

Order X:以11.00美元出售1股

Order B:以10.00美元购买2股

Order Y:以11.00美元出售2股

Order C:以10.00美元购买3股

Order Z:以12.00美元出售2股

Order D:以9.00美元购买1股

 

假设在先进先出模式下,4股以10.00美元的价格的入场卖单K将与1股的订单A、2股的订单B、1股的订单C依次匹配。匹配结束后,订单C仍有剩余的2股,价格为10.00美元,将拥有最高优先权。

2.按比例匹配

按比例匹配有各种不同的方式,通常实现方式也略有不同。在本书的范围内,我们提供了这种匹配算法背后的一些知识,并提供了一个假设的匹配方案。

按比例匹配的基本模式是,在相同的价格下,倾向于大单而不是小单,并且忽略订单的输入时间。这使市场的微观结构发生了相当大的变化,市场参与者倾向于输入较大的订单以获得优先权,而不是尽可能快地输入订单。

考虑一个如之前所示的市场状态。在表1-2这个例子中,假设的订单数量被提高了100倍。这里,买单A、B和C的价格也相同,均为10.00美元。然而,当一个数量为100的卖出订单以10.00美元的价格进入时,订单C得到了70份合约的成交量,订单B得到了20份合约的成交量,订单A得到了10份合约的成交量,这与它们在该级别的大小成正比。这是个过于简化的例子,不包括与部分匹配大小有关的复杂情况,也不包括相同大小的订单之间的打破平局相关的复杂性,等等。同样地,有些交易的所有者会按比例和先进先出的方式进行混合,一部分进场的激进订单使用按比例匹配,一部分按先进先出的顺序匹配。但这应该可以作为一个很好的例子来让我们对按比例匹配与先进先出匹配的不同进行基本理解。对按比例匹配及其影响的详细研究超出了本书的范围,这里不再详述。

表1-2

竞价单

要价

Order A: 以10.00美元购买100股

Order X: 以11.00美元出售100股

Order B: 以10.00美元购买200股

Order Y: 以11.00美元出售200股

Order C: 以10.00美元购买700股

Order Z: 以12.00美元出售200股

Order D: 以9.00美元购买100股

 

限价订单簿与交换订单簿在本质上非常相似。不同的是,限价订单簿是由市场参与者根据交易所公开的市场数据而建立的,以响应市场参与者向其发送订单。限价订单簿是所有算法交易中的核心概念之一,也是所有其他交易形式中经常出现的概念。其目的是以一种有意义的方式收集和安排出价和报价,以深入了解在任何特定时间在场的市场参与者,并深入了解均衡价格是多少。我们将在第2章深入研究技术分析时重新讨论这些问题。根据交易所决定通过公开市场数据向所有市场参与者提供的信息,市场参与者建立的限价订单簿可能与交易所匹配引擎的订单簿略有不同。

由于交换市场数据协议不是本书的重点,因此对这一主题的严格处理超出了本书的范围。市场数据协议是从交易所到所有市场参与者的外发通信流,这些通信流都有完善的文档,可供新的市场参与者建立他们的应用程序来订阅、接收、解码、检查错误和网络损失。这些协议的设计考虑到了延迟、吞吐量、容错、冗余和许多其他要求。

市场数据提供处理程序是市场参与者为与具体的交易所市场数据协议接口建立的软件。这些软件能够订阅、接收、解码、检查错误和网络损失,并在设计时考虑到了延迟、吞吐量、容错、冗余和许多其他要求。

大多数交易所支持从市场参与者那里接受各种订单,我们将在本小节讨论几种常见的类型。

1.IOC订单(立即或取消)

这些订单永远不会被添加到账本中。它们要么与现有的恢复订单进行匹配,以IOC订单量为上限,要么取消其余的输入订单。如果在IOC订单的价格上没有可以与之匹配的剩余订单,那么IOC订单将被全部取消。IOC订单的好处是不会停留在账本的匹配中,也不会在交易算法中造成订单管理的额外复杂性。

2.GTD订单(Good Till Day)

这些订单会被添加到账本中。如果它们与账本中现有的休眠订单完全匹配,那么它们就不会被添加,否则订单上的剩余数量(如果没有部分匹配,可以是整个原始数量)就会被添加到账本中,并作为休眠订单,让进场的订单可以与之匹配。GTD订单的好处是可以利用FIFO匹配算法,比刚出现在账本上的订单有更好的优先级,但在交易算法中需要更复杂的订单管理。

3.止损单

止损单是指在市场上以某一特定价格(称为止损价)成交之前不出现在账面上的订单,在成交后,它们将变成预先指定价格的常规GTD订单。这些订单作为退出单是很好的选择(无论是清算亏损的头寸还是实现赢利的头寸的利润)。在后文解释了什么是有亏损或赢利的头寸以及什么是退出头寸之后,将重新审视这些订单。

交换订单输入协议是指市场参与者的应用程序如何发送订单请求(新建、取消、修改)以及交易所如何回复这些请求。

订单输入网关是市场参与者的客户端应用程序,通过订单输入协议与交易所匹配引擎进行通信。这些应用程序必须以可靠的方式处理订单流,向交易所发送订单,修改和取消这些订单,并在这些订单被接受、取消、执行等情况下获得通知。通常情况下,市场参与者会运行订单输入网关的变体,这些变体只接收订单执行的通知,以检查与主要订单输入网关订单流的一致性,被称为drop-copy网关。

被执行的订单会使市场参与者以执行的金额和执行的价格在被执行的工具上拥有头寸(限价订单可以比输入的价格更好,但不会更差)。买方执行的称为“有多头头寸”,而卖方执行的称为“有空头头寸”。当完全没有头寸时,称为“平仓”。当市场价格高于头寸价格时,持有多头头寸买方就会赚钱;当市场价格低于头寸价格时,买方就会亏损。反之,空头则是当市场价格低于头寸价格时,持有空头头寸的卖方就会赚钱;当市场价格高于头寸价格时,卖方就会亏损。因此,也就有了众所周知的低买高卖、高买更高卖等观点。

多次买入执行,或多次卖出执行不同的金额和价格,导致总的头寸价格是执行价格和数量的成交量的加权平均值。这被称为仓位的成交量加权平均价格(Volume Weighted Average Price,VWAP)。未平仓的头寸要标明市场价格,以了解该头寸的未实现损益(Profit and Loss,PnL)是多少。这意味着将当前的市场价格与头寸的价格进行比较,市场价格上涨的多头头寸被认为是未实现利润,反之则被认为是未实现亏损。类似的术语也适用于空头头寸。当未平仓的头寸被平仓时,就实现了损益,也就是说你卖出平仓多头头寸,买入平仓空头头寸。在这一点上,PnL被赋予了术语实现PnL。任何时候的总PnL是迄今为止已实现的PnL和未平仓头寸的未实现PnL的总和(按市场价格)。

在这里,我们将讨论交易思想是如何产生的,以及如何将其转化为算法交易策略。从根本上来说,所有的交易想法在很大程度上都是由人类的直觉驱动的。如果市场一直在涨或跌,你可能凭直觉认为它将继续朝同一个方向发展,这就是趋势跟踪交易策略背后的基本理念。相反,你可能会认为,如果价格大幅上涨或下跌,那么价格可能会被错误定价并可能朝相反的方向发展,这就是均值回归交易策略背后的基本理念。直观上,你也可能会认为彼此非常相似的或者松散地相互依赖的工具会一起变化,这就是基于相关交易或成对交易背后的理念。由于每个市场参与者对市场都有自己的看法,所以最终的市场价格是大多数市场参与者的看法的反映。如果你的观点与大多数市场参与者的观点一致,那么在特定的情况下,该特定的策略就是能带来赢利的。当然,没有任何一个交易理念可以一直正确,一个策略是否能带来赢利,取决于这个理念正确的频率与不正确的频率。

从历史上看,人类交易者实施这种基于规则的交易来手动输入订单、持仓,并在一天中带来赢利或亏损。随着时间的推移和技术的进步,他们已经从在场上大喊大叫地与其他交易者一起执行订单,到打电话给经纪人并通过电话输入订单,再到拥有可以通过点击界面输入订单的图形用户界面(Graphical User Interface,GUI)应用程序。

这种人工方法有很多弊端,例如因为人们对市场的反应迟钝,所以他们会错过信息或对新信息反应迟钝,也不能很好地扩展规模或同时专注于多件事情。人们很容易犯错,他们会分心,会害怕亏损也会感受到赚钱的喜悦。这些缺点都会导致他们偏离计划的交易策略,从而严重限制交易策略的赢利能力。

计算机极其擅长基于规则的重复性任务。当设计和编程正确时,它们可以极快地执行指令和算法,并且可以在很多工具上无缝扩展和部署。它们对市场数据的反应速度极快,而且不会分心,也不会犯错(除非它们的程序不正确,这是软件错误,而不是计算机本身的缺点)。它们没有情绪,所以不会偏离它们的程序。所有这些优点使计算机自动交易系统在正确的情况下非常有利可图,这也是算法交易的起点。

让我们以一个简单的趋势跟踪交易策略为例,看看交易是如何从手动方式演变到全自动算法交易策略的。从历史上看,人类交易者习惯于使用简单的图表应用程序,以用来检测趋势何时开始或持续。这些可以是简单的规则,例如,如果一只股票在一周内每天都上涨5%,那么我们就应该买入并持有(持有多头头寸),或者如果股票的价格在2小时内下跌了10%,那么我们应该卖空并等待它进一步下跌。这在过去会是经典的手动交易。正如我们之前所讨论的,计算机非常擅长遵循重复性的规则算法。更简单的规则更容易编程,需要的开发时间也更少,但计算机软件几乎只受限于为计算机编程的软件开发人员所能处理的复杂性。在本章的最后,我们将讨论一个用Python编写的现实交易策略,但现在,我们将继续介绍在此之前需要的所有思想和概念。

下面是一些可实现趋势跟踪的伪代码,这是基于人类直觉交易的理念的。然后可以根据应用的需要将其翻译成我们所选择的任何语言。

可以使用趋势跟踪,也就是说,当价格在2小时内变化10%时进行买入或卖出。这个变量用于跟踪我们在当前市场上的头寸。

Current_position_ = 0;

这是头寸的预期利润阈值。如果头寸的利润高于这个阈值,我们就把头寸和未实现的利润“平掉”,使之变成实现的利润。

PROFIT_EXIT_PRICE_PERCENT = 0.2;

这是头寸的最大亏损阈值。如果一个头寸的亏损超过了这个阈值,我们就会将头寸平掉,并将未实现的亏损转化为已实现的亏损。如果头寸亏损,为什么要平仓呢?想法很简单,就是不要把所有的钱都赔在一个不良头寸上,而是要尽早减少损失,这样我们才有资本继续交易。当深入探讨风险管理实践时,我们将对此进行更多介绍。现在,我们定义一个参数,该参数是根据头寸的入场价与价格变化定义的最大头寸亏损。

LOSS_EXIT_PRICE_PERCENT = -0.1;

请注意,在我们看到的阈值中,期望在获利或赢利的头寸上赚的钱比期望在亏损的头寸上亏的钱多。这并不总是对称的,当我们在后文更详细地研究这些交易策略时,将讨论获利和亏损头寸的分布问题。这是一个方法或回调,在每次市场价格变化时都会被调用。我们需要检查根据我们的信号是否应入场,以及一个未平仓的头寸是否需要因为PnL被平仓。

def OnMarketPriceChange( current_price, current_time ):

首先,检查头寸是否持平以及价格是否上涨了10%以上。这是“做多”的入场信号,此时我们会发出买单并更新头寸。从技术上讲,在交易所确认订单匹配之前,我们不应该更新自己的头寸,但是为了简化伪代码,我们将忽略这种复杂性,并在后面解决它。

If Current_position_ == 0 AND ( current_price - price_two_hours_ago ) / current_price > 10%:
 SendBuyOrderAtCurrentPrice();
 Current_position_ = Current_position_ + 1;

现在,检查头寸是否持平以及价格是否已经下跌超过10%。这是“做空”的入场信号,此时我们会发出卖单并更新头寸。

Else If Current_position_ == 0 AND ( current_price - price_two_hours_ago ) / current_price < -10%:
      SendSellOrderAtCurrentPrice();
      Current_position_ = Current_position_ - 1;

如果目前的策略是做多,而且市场价格已经向有利的方向发展,请检查此头寸的赢利是否超过了预定的阈值。在这种情况下,我们就会发出卖单以平仓,将未实现的利润转化为已实现的利润。

If Current_position_ > 0 AND current_price - position_price > PROFIT_EXIT_PRICE_PERCENT:
  SendSellOrderAtCurrentPrice();
  Current_position_ = Current_position_ - 1;

如果目前的策略是做多,而市场价格已经对我们不利,请检查此头寸的损失是否超过了预定的阈值。在这种情况下,我们将发出卖单来平仓,并将未实现的损失转化为已实现的损失。

Else If Current_position_ > 0 AND current_price - position_price < LOSS_EXIT_PRICE_PERCENT:
  SendSellOrderAtCurrentPrice();
  Current_position_ = Current_position_ - 1;

如果目前的策略是做空,而市场价格已经向有利的方向发展,要检查此头寸的赢利是否超过了预定的阈值。在这种情况下,我们会通过买单来平仓,将未实现的利润转化为已实现的利润。

Else If Current_position_ < 0 AND position_price - current_price > PROFIT_EXIT_PRICE_PERCENT:
  SendBuyOrderAtCurrentPrice();
  Current_position_ = Current_position_ - 1;

如果目前的策略是做空,而市场价格已经对我们不利,请检查此头寸的损失是否超过了预定的阈值。在这种情况下,我们将通过买单来平仓,并将未实现的损失转化为已实现的损失。

Else If Current_position_ < 0 AND position_price - current_price < LOSS_EXIT_PRICE_PERCENT:
  SendBuyOrderAtCurrentPrice();
  Current_position_ = Current_position_ - 1;

在前文中,我们提供了整个算法交易设置的顶层视图,以及所涉及的许多不同组件。实际上,设置一个完整的算法交易分为两个部分,如图1-3所示。

 核心基础设施涉及面向交易所的市场数据协议集成、市场数据源处理程序、内部市场数据格式归一化、历史数据记录、工具定义记录和发布、交易所订单录入协议、交易所订单录入网关、核心侧风险系统、面向券商的应用、后台对账应用、解决合规要求等。

 算法交易策略组件涉及使用归一化的市场数据、建立订单簿、从传入的市场数据和订单流信息中产生信号、不同信号的聚合、建立在统计预测能力(alpha)之上的高效执行逻辑、策略内部的头寸和PnL管理、策略内部的风险管理、回测、历史信号和交易研究平台。

图1-3 

这些组件负责与发布标准化数据的馈送处理程序组件进行交互。这些标准化数据可以通过网络或使用本地馈送处理程序的各种进程间通信(Inter-Process Communication,IPC)机制来传递。我们在此不做详细介绍。在这方面,低延迟交付和可扩展性是主要的设计决策。

一旦交易策略得到标准化的市场数据,它就会使用这些数据来建立和维护每个工具的限价订单簿。根据限价订单簿的复杂程度,它可以简单到告诉我们每方有多少市场参与者,也可以复杂到跟踪市场参与者的订单优先级,以及跟踪我们自己在限价订单簿中的订单。

一旦限价订单簿建立起来,每次新的市场数据信息更新时,我们就会使用新的信息建立信号。信号的名称多种多样,例如信号、指标、预测器、计算器、特征、alpha等,但它们的含义大致相同。

交易信号是指从传入的市场数据信息、限价订单簿或交易信息中得出的定义明确的情报,它能使交易策略相对于其他市场参与者获得统计上的优势,从而提高赢利能力。这也是很多交易团队集中大量时间和精力的领域之一。其关键在于建立大量的信号,以便在竞争中占据优势,同时不断调整现有的信号并添加新的信号,以应对不断变化的市场条件和市场参与者。我们将在第2章中重新讨论这个问题,因为这是本书的重点之一。

通常情况下,算法交易系统结合了很多不同种类的信号,以获得比单一信号更大的优势。这种方法实质上是将不同的信号组合起来,这些信号在不同的市场条件下具有不同的预测能力或优势。有许多不同的方法来组合各种信号。你可以使用经典的统计学习方法来生成线性或非线性组合,以输出代表某个信号组合的分类或回归输出值。机器学习不是本书的重点,因此我们避免太深入地探讨这个话题,但会在后文中进行简要介绍。

算法交易的另一个关键组成部分是根据信号快速、有效地管理订单,从而在竞争中获得优势。重要的是以快速且智能的方式对不断变化的市场数据、不断变化的信号值做出反应。很多时候,速度和复杂度是两个相互冲突的目标,好的执行逻辑会试图以最佳的方式平衡这两个目标。向其他市场参与者掩饰我们的意图或才智也是极其重要的,这样我们才能获得最佳的执行力。

请记住,因为其他市场竞争者可以观察发送到交易所的订单,并评估它可能产生的潜在影响,所以这个组件需要足够智能,不能让人看出我们的交易策略是什么。就执行逻辑设计而言,滑点和费用也是非常重要的因素。

滑点是指交易的预期价格与实际执行的价格之间的差异,发生这种情况主要有两个原因。

 如果订单到达交易所的时间比预期的晚(延迟),那么它最终可能要么根本没有执行,要么执行的价格比你预期的要差。

 如果订单非常大,以至于它以多种价格执行,那么整个执行的VWAP可能与订单发出时观察到的市场价格有很大差异。

滑点显然会造成可能没有正确考虑到的损失,此外还会造成清算头寸困难。随着交易算法的头寸规模的扩大,滑点会成为一个更大的问题。

费用是高效执行订单的另一个问题。通常情况下,交易所费用和经纪人费用与订单规模和总交易量成正比。

同样,随着交易算法的头寸规模的扩大,交易量通常会增加,费用也会增加。很多时候,一个好的交易策略可能会因为交易量过大,积累了大量的交易费用而最终无利可图。同样,一个好的执行逻辑应寻求将支付的费用降到最低。

所有的算法交易策略都需要有效地跟踪和管理其头寸和损益。根据实际的交易策略,这通常会有不同的复杂性。

对于更复杂的交易策略,如配对交易(曲线交易是另一种类似的策略),你必须跟踪多个工具的头寸和损益,而且这些头寸和损益经常会相互抵消,并在确定真实头寸和损益方面引入复杂性或不确定性。我们将在第4章中详细讨论这些策略时,对这些问题进行探讨,但现在,我们不会太详细地讨论这个问题。

良好的风险管理是算法交易的基石。不良的风险管理会将潜在的可带来赢利的策略变成无利可图的策略。还有一个更大的风险是违反交易所的规章制度,这往往会导致法律诉讼和巨额罚款。最后,高速自动算法交易最大的风险之一是设计不当的计算机软件容易出现缺陷和错误。由于高速自动算法交易系统失控而导致整个公司倒闭的例子很多。因此,风险管理系统的建设需要有极强的健壮性、丰富的功能和多层冗余,还需要有非常高层级的测试、压力测试和严格的变更管理,以最大限度地降低风险系统失效的可能性。在本书的第6章中,我们将专门介绍最佳的风险管理实践,以便最大限度地提高交易策略的赢利能力,同时避免常见的可导致公司亏损或破产的陷阱。

在研究自动交易策略的预期行为时,一个好的算法交易研究系统的关键组成部分是一个好的回测器。回测器用于模拟自动交易策略行为,并根据历史记录的市场数据检索预期损益、预期风险敞口和其他指标的统计数据。基本思路是回答这样一个问题:给定历史数据,一个特定的交易策略会有什么样的表现?这是通过以下方式构建的:准确记录历史市场数据,具有可重新回放历史记录的框架,具有可以接受潜在交易策略的模拟订单流的框架,并可模拟交易所在历史市场数据中在指定的其他市场参与者面前如何匹配这个策略的订单流。通过回测可以尝试不同的交易策略,看看在部署到市场之前,哪些想法是可行的。

建立和维护一个高精度的回测器是建立算法交易研究系统中最复杂的任务之一。它必须准确地模拟诸如软件延迟、网络延迟、准确的订单FIFO优先级、滑点、费用等,在某些情况下,还必须模拟所考虑的策略的订单流对市场造成的影响(其他市场参与者在这个策略的订单流和交易活动存在的情况下可能做出的反应)。我们将在本章结尾处重新讨论回测问题,然后在本书后文中再次回顾。最后,我们将解释在设置和校准回测器时面临的实际问题,它们对算法交易策略的影响,以及哪种方法可以最大限度地减少不正确的回测造成的损失。

Python是世界上使用非常广泛的编程语言(约有1/3的新软件开发都使用这种语言),如图1-4所示。

图1-4 

这种语言非常简单、易学。Python是一种带有类型推断的解释型高级编程语言,与C/C++不同。在C/C++中,你需要关注内存管理和所使用的机器的硬件特性来编写代码,而Python仅关注内部的实现。因此,使用这种类型的语言将便于对编码交易算法的关注。Python是通用的,它几乎可以用于任何领域的任何应用开发。由于Python已经被广泛使用多年,程序员社区足够大,可以为你的交易策略获得许多关键的库,从数据分析、机器学习、数据提取、运行时到通信,开源库非常多。此外,在软件工程方面,Python还包括其他语言中使用的范式,如面向对象、函数式和动态类型。Python的在线资源几乎是无限的,大量的书籍将推动你在任何领域使用Python。Python不是交易中唯一使用的语言。我们最好使用Python(或最终使用R)来进行数据分析和创建交易模型。我们将在交易中使用C、C++或Java来编写代码,这些语言将把源代码编译成可执行代码或字节码,因此代码的运行速度将比Python或R代码的快很多倍。这3种语言比Python“快”,我们也会用它们来创建库。我们将把这些库封装起来,与Python(或R)一起使用。

在选择Python时,我们还需要选择语言的版本。2020年之后,Python 2.x将不再被维护。因此,如果你是一个新的程序员,建议学习Python 3而不是Python 2。

Python和R都是协助量化研究人员(或量化开发人员)创建交易算法的较流行的语言。它们为数据分析或机器学习提供了大量的支持库。在这两种语言之间进行选择,将取决于你在社区的哪一方。我们总是把Python和通用语言联系在一起,它的语法通俗易懂,简单明了。而R则主要以统计学家为终端用户,通过强调数据可视化来开发的。虽然Python也能给你同样的可视化体验,但R是为此而设计的。

和Python相比,R没有明显的更新。它是由两位创始人Ross Ihaka和Robert Gentleman在1995年发布的,而Python是由Guido Van Rossum在1991年发布的。现在,R主要用于学术和研究领域。

与其他许多语言不同,Python和R可以让我们用几行代码写出一个统计模型。一般不可能“二选一”,因为它们都有各自的优势,很容易互补使用。开发人员创建了众多的库,能够让人轻松地将一种语言与另一种语言结合使用而不会遇到任何困难。

虽然RStudio成了R的标准IDE(集成开发环境),但在PyCharm和Jupyter Notebook之间的选择则更具挑战性。首先,我们需要谈谈这两个IDE的特点。PyCharm由捷克JetBrains公司开发,是一个文本编辑器,提供代码分析、图形化调试器和高级单元测试器。Jupyter Notebook是一个开源软件,它为以下3种语言创建了一个基于Web的交互式计算环境:Julia、Python和R。这款软件通过给你一个基于Web的界面,让你可逐行运行Python代码,来帮助你编写Python代码。

这两款IDE的最大区别在于,PyCharm成了程序员们的参考IDE,因为版本控制系统和调试器是这款产品的重要组成部分。此外,PyCharm可以轻松处理大量的代码库,并且有大量的插件。

当数据分析是唯一的动机时,Jupyter Notebook是一个友好的选择,而PyCharm缺乏友好的用户界面,无法逐行运行代码进行数据分析。PyCharm提供的功能是Python编程世界中较常用的。

你现在可能觉得自己已经迫不及待地想赚钱了,你也可能在想什么时候可以开始赚钱呢?我们已经谈到了我们将在本书中解决的问题。在本小节中,我们将开始建立第一个交易策略,叫作“低买高卖”。

建立一个交易策略需要时间,并且要经过许多步骤。

(1)你需要一个原始的想法。这一部分将使用一个众所周知的赚钱策略:我们买入的资产价格低于我们将用来出售它的价格。为了说明这个想法,我们将使用谷歌股票。

(2)一旦有了想法,我们需要用数据来验证这个想法。在Python中,我们可以使用很多包来获取交易数据。

(3)然后,需要使用大量的历史数据来回测交易策略,假设这个规则:过去有效的东西在未来会有效。

在本书中,我们选择PyCharm作为IDE。我们将使用这个工具来完成所有的例子。

一旦PyCharm加载完毕,你将需要创建一个项目并选择一个解释器。正如我们之前所讨论的,你需要选择Python 3。在编写本书的时候,最新的版本是Python 3.7.0,但是你可以自由地从比这个版本更高的版本开始。当项目打开后,你需要创建一个Python文件,文件命名为buylowsellhigh.py。这个文件将包含你的第一个Python程序的代码。

很多库都可以帮助下载财务数据,不过我们选择的是使用pandas库。这个库以数据处理和分析而闻名。我们将使用DataReader函数,它能够连接到雅虎、谷歌等许多金融新闻服务器,然后下载本书例子中需要的数据。DataReader在本例中需要4个参数。

(1)第1个是你想用来分析的符号(我们的例子用GOOG代表谷歌)。

(2)第2个是指定检索数据的来源,然后你要指定获取数据的范围。

(3)第3个指定获取历史数据的起始数据。

(4)第4个也是最后一个参数,指定历史数据的结束数据。

# loading the class data from the package pandas_datareader
from pandas_datareader import data
# First day
start_date = '2014-01-01'
# Last day
end_date = '2018-01-01'
# Call the function DataReader from the class data
goog_data = data.DataReader('GOOG', 'yahoo', start_date, end_date)

变量goog_data是包含2014年1月1日至2018年1月1日谷歌数据的数据框。如果输出goog_data变量,你会看到以下内容。

print(goog_data)   
Date        High       Low            ... Volume    Adj Close
2010-01-04  312.721039 310.103088     ... 3937800.0 311.349976
2010-01-05  311.891449 308.761810     ... 6048500.0 309.978882
2010-01-06  310.907837 301.220856     ... 8009000.0 302.164703
2010-01-07  303.029083 294.410156     ... 12912000.0 295.130463

如果你想看到所有的列,则应该改变pandas库的选项来允许显示4个以上的列。

import pandas as pd
pd.set_printoptions(max_colwidth, 1000)
pd.set_option('display.width', 1000)
Date            High         Low          Open        Close       Volume      Adj Close
2010-01-04   312.721039   310.103088   311.449310   311.349976   3937800.0   311.349976
2010-01-05   311.891449   308.761810   311.563568   309.978882   6048500.0   309.978882
2010-01-06   310.907837   301.220856   310.907837   302.164703   8009000.0   302.164703
2010-01-07   303.029083   294.410156   302.731018   295.130463   12912000.0  295.130463

按照之前的输出,共有6列。

 High:该股票在该交易日的最高价。

 Low:该股票在该交易日的最低价。

 Open:该股票在交易日开始时的价格(前一个交易日的收盘价)。

 Close:该股票在收盘时的价格。

 Volume:有多少股票成交。

 Adj Close:该股票的收盘价,调整了公司行动的股票价格(简称股价),这个价格考虑到了股票分红和股息。

调整后的收盘价是我们在这个例子中使用的价格。事实上,由于它考虑到了分红和股息,我们将不需要手动调整价格。

交易策略(或交易算法)的主要部分是决定何时交易(买入、卖出证券或其他资产)。触发发送订单的事件称为信号。一个信号可以使用多种输入。这些输入可能是市场信息、新闻或社交网站。任何数据的组合都可以是信号。

以1.6.2小节的低买高卖为例,我们将计算连续两天的调整收盘价的差值。如果调整后的收盘价的数值为负数,说明前一天的价格比第二天的价格高,此时我们可以买入,因为现在的价格比较低。如果这个值为正,这意味着我们可以卖出,因为价格更高。

在Python中,我们将构建一个pandas数据框,来获得与包含数据的数据框相同的维度。这个数据框将被称为goog_data_signal。

goog_data_signal = pd.DataFrame(index=goog_data.index)

在创建这个数据框之后,我们将复制用来建立交易信号的数据。在这种情况下,我们将从goog_data数据框中复制Adj Close列的值。

goog_data_signal['price'] = goog_data['Adj Close']

根据交易策略,我们需要有一列daily_difference来存储连续两天的差值。为了创建这个列,我们将使用数据框对象中的diff函数。

goog_data_signal['daily_difference'] = goog_data_signal['price'].diff()

作为明智的检查,我们可以使用print函数来显示goog_data_signal的内容。

print(goog_data_signal.head())                
Date          price   daily_difference
2014-01-02  552.963501             NaN
2014-01-03  548.929749       -4.033752
2014-01-06  555.049927        6.120178
2014-01-07  565.750366       10.700439
2014-01-08  566.927673        1.177307

我们可以观察到,daily_difference列在1月2日有一个非数字值,因为它在这个数据框的第一行。

我们将根据daily_difference列的值来创建信号。如果该值为正,我们将给出1,否则,该值将保持为0。

goog_data_signal['signal'] = 0.0
goog_data_signal['signal'] = np.where(goog_data_signal['daily_difference']
>; 0, 1.0, 0.0)
Date          price daily_difference signal
2014-01-02  552.963501             NaN 0.0
2014-01-03  548.929749       -4.033752 0.0
2014-01-06  555.049927        6.120178 1.0
2014-01-07  565.750366       10.700439 1.0
2014-01-08  566.927673        1.177307 1.0

读取列信号,当我们需要买入的时候为0,当我们需要卖出的时候为1。

由于我们不想在市场不断下跌时继续买入,也不想在市场上涨时继续卖出,所以会通过限制自己在市场上的头寸数量来限制下单的数量。头寸就是你在市场上的股票或资产的存量。例如,买入一只谷歌股票,这意味着你在市场上有一只股票的头寸。如果卖出这只股票,你在市场上就不会有任何头寸。

为了简化例子和限制市场上的头寸,将不可能连续买入或卖出多于一次。因此,我们将对列信号应用diff函数。

goog_data_signal['positions'] = goog_data_signal['signal'].diff()
Date           price daily_difference signal  positions
2014-01-02  552.963501             NaN 0.0       NaN
2014-01-03  548.929749       -4.033752 0.0       0.0
2014-01-06  555.049927        6.120178 1.0       1.0
2014-01-07  565.750366       10.700439 1.0       0.0
2014-01-08  566.927673        1.177307 1.0       0.0
2014-01-09  561.468201       -5.459473 0.0      -1.0
2014-01-10  561.438354       -0.029846 0.0       0.0
2014-01-13  557.861633       -3.576721 0.0       0.0

我们将在1月6日以555.049927美元的价格买入一股谷歌的股票,然后以561.468201美元的价格卖出这股股票。这笔交易的利润是561.468201−555.049927=6.418274。

虽然创建信号只是建立交易策略过程的开始,但需要将策略的长期表现可视化。我们将通过使用Matplotlib库来绘制使用的历史数据的图表。这个库在Python世界里是很有名的,它可以让我们轻松地绘制图表。

 我们先导入这个库:

import matplotlib.pyplot as plt

 接下来,将定义一个包含图表的图形:

fig = plt.figure()
ax1 = fig.add_subplot(111, ylabel='Google price in $')

 现在,将在最初选择的天数范围内绘制价格:

goog_data_signal['price'].plot(ax=ax1, color='r', lw=2.)

 下一步,每买入一只谷歌的股票时,将绘制一个向上的箭头:

ax1.plot(goog_data_signal.loc[goog_data_signal.positions ==1.0].index,goog_data_signal.price [goog_data_signal.positions == 1.0], '^', markersize=5,color='m')

 接下来,每卖出一只谷歌股票时,将绘制一个向下的箭头:

ax1.plot(goog_data_signal.loc[goog_data_signal.positions ==-1.0].index, goog_data_signal.price [goog_data_signal.positions == -1.0], 'v', markersize=5,color='k')
plt.show()

这段代码将返回以下输出,如图1-5所示。

到此为止,我们介绍了交易思路,实现了触发买入和卖出订单的信号,还谈到了限制策略的方法(将头寸限制在市场上的一只股票)。当这些步骤都满意后,下面的步骤就是回测。

图1-5 

回测是一个关键阶段,以获得可反映交易策略有效性的统计数据。正如之前了解到的,回测依赖于过去预测未来的假设。这个阶段将提供你或你的公司认为重要的统计数据,如以下几个方面。

 赢利和亏损(P和L):应用该策略所赚的钱,不含交易费用。

 净利润和亏损(P和L的净额):应用该策略所赚的钱与交易费用。

 曝光率:投入的资金。

 交易次数:一个交易时段内的交易次数。

 年化收益率:一年的交易回报率。

 夏普比率:风险调整后的回报率。这个很重要,因为它会将策略的回报率与无风险策略进行比较。

虽然这部分内容将在后文详细介绍,但在本小节中,我们将讨论在给定的时间段内用初始资金测试策略。

为了进行回溯测试,将用一个仅包括一种股票的投资组合(债券和股票等金融资产的组合):谷歌(GOOG)。我们将以1000美元开始这个投资组合:

initial_capital = float(1000.0)

现在,我们将为头寸和投资组合各创建一个数据框:

positions = pd.DataFrame(index=goog_data_signal.index).fillna(0.0)
portfolio = pd.DataFrame(index=goog_data_signal.index).fillna(0.0)

接下来,我们将把GOOG的头寸存储在下面的数据框中:

positions['GOOG'] = goog_data_signal['signal']

然后,我们将投资组合的GOOG头寸的金额存储在这一个数据框中:

portfolio['positions'] = (positions.multiply(goog_data_signal['price'], axis=0))

接下来,我们将计算非投资资金(现金):

portfolio['cash'] = initial_capital_(positions.diff().multiply(goog_data_signal['price'], axis=0)).cumsum()

将头寸和现金相加,计算出总投资额:

portfolio['total'] = portfolio['positions'] + portfolio['cash']

如图1-6所示,可以很容易地确定我们的策略是可带来赢利的。

图1-6 

当创建一个交易策略时,我们有一笔初始资金(现金)。我们将用这笔现金(持有量)进行投资。这个投资的持有价值是基于其市场价值的。如果我们拥有一只股票,而这只股票的价格上涨,持有价值就会增加。当决定卖出时,我们就会把这次卖出对应的持有价值移到现金上。资产的总和就是现金和持股的总和。如图1-6所示,该策略是可带来赢利的,因为现金在最后是增加的。这样可以让你检查自己的交易思路是否能让你赚钱。

在这一章中,你已经了解了交易世界,也了解了人们为什么要进行交易,并有能力描述关键的行为和交易系统,在你作为一个算法交易设计师的一生中你将与之互动。你也接触到了将在本书中用来构建交易机器人的工具。最后,你遇到了算法交易的第一次实施,通过编写第一个交易策略,实现了低买高卖的经济理念。我们观察到,这个策略远不是一个可以带来赢利且安全的策略。

在第2章中,我们将讨论如何使策略更高级,如何与更复杂的交易思想相联系,同时用Python实现这些策略。

微信扫码关注【异步社区】微信公众号,回复“e58266”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。


相关图书

深度学习的数学——使用Python语言
深度学习的数学——使用Python语言
动手学自然语言处理
动手学自然语言处理
Web应用安全
Web应用安全
Python高性能编程(第2版)
Python高性能编程(第2版)
图像处理与计算机视觉实践——基于OpenCV和Python
图像处理与计算机视觉实践——基于OpenCV和Python
Python数据科学实战
Python数据科学实战

相关文章

相关课程