Python-机器学习算法交易实用指南-一-

131 阅读1小时+

Python 机器学习算法交易实用指南(一)

原文:zh.annas-archive.org/md5/fcb09c483bdb21866eb6782158d1f8d5

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

多样化数据的可用性增加了对算法交易策略专业知识的需求。通过本书,您将选择并应用机器学习ML)到广泛的数据源,并创建强大的算法策略。

本书将首先介绍一些基本要素,如评估数据集、使用 Python 访问数据 API、使用 Quandl 访问金融数据以及管理预测误差。然后我们将涵盖各种机器学习技术和算法,这些技术和算法可用于使用 pandas、Seaborn、StatsModels 和 sklearn 构建和训练算法模型。然后我们将使用 StatsModels 构建、估计和解释 AR(p)、MA(q) 和 ARIMA(p, d, q) 模型。您将应用贝叶斯先验、证据和后验的概念,以区分使用 PyMC3 的不确定性概念。然后我们将利用 NLTK、sklearn 和 spaCy 为财经新闻分配情感得分,并对文档进行分类以提取交易信号。我们将学习设计、构建、调整和评估前馈神经网络、循环神经网络RNNs)和卷积神经网络CNNs),使用 Keras 设计复杂的算法。您将应用迁移学习到卫星图像数据,以预测经济活动。最后,我们将应用强化学习来获得最佳交易结果。

通过本书,您将能够采用算法交易来实现智能投资策略。

本书的受众

本书适用于数据分析师、数据科学家和 Python 开发人员,以及在金融和投资行业工作的投资分析师和投资组合经理。如果您想通过开发智能调查策略使用 ML 算法来执行高效的算法交易,那么这就是您需要的书!对 Python 和 ML 技术的一些理解是必需的。

本书内容

第一章,用于交易的机器学习,通过概述 ML 在生成和评估信号以设计和执行交易策略中的重要性来确定本书的重点。它从假设生成和建模、数据选择和回测到评估和执行在投资组合背景下的策略过程进行了概述,包括风险管理。

第二章,市场与基础数据,介绍了数据来源以及如何处理原始交易所提供的 tick 和财务报告数据,以及如何访问许多本书中将依赖的开源数据提供商。

第三章,金融替代数据,提供了评估不断增加的数据来源和供应商的分类和标准。它还演示了如何通过网站爬取创建替代数据集,例如收集用于第二部分书籍中的自然语言处理NLP)和情感分析算法的收益电话转录。

第四章,Alpha 因子研究,提供了理解因子工作原理以及如何衡量其绩效的框架,例如使用信息系数IC)。它演示了如何使用 Python 库离线和在 Quantopian 平台上工程化数据生成 alpha 因子。它还介绍了使用zipline库对因子进行回测和使用alphalens库评估其预测能力。

第五章,战略评估,介绍了如何利用历史数据使用zipline离线和在 Quantopian 平台上建立、测试和评估交易策略。它展示并演示了如何使用pyfolio库计算投资组合绩效和风险指标。它还讨论了如何处理策略回测的方法论挑战,并介绍了从投资组合风险角度优化策略的方法。

第六章,机器学习工作流,通过概述如何构建、训练、调整和评估 ML 模型的预测性能作为系统化工作流程,为后续章节做好铺垫。

第七章,线性模型,展示了如何使用线性和逻辑回归进行推断和预测,以及如何使用正则化来管理过拟合的风险。它介绍了 Quantopian 交易平台,并演示了如何构建因子模型并预测资产价格。

第八章,时间序列模型,涵盖了单变量和多变量时间序列,包括向量自回归模型和协整检验,以及它们如何应用于配对交易策略。

第九章,贝叶斯机器学习,介绍了如何制定概率模型以及如何使用马尔可夫链蒙特卡罗MCMC)采样和变分贝叶斯来进行近似推断。它还说明了如何使用 PyMC3 进行概率编程以深入了解参数和模型的不确定性。

第十章,决策树和随机森林,展示了如何构建、训练和调整非线性基于树的模型以进行洞察和预测。它介绍了基于树的集成模型,并展示了随机森林如何使用自举聚合来克服决策树的一些弱点。第十一章,梯度提升机,展示了如何使用库xgboostlightgbmcatboost进行高性能训练和预测,并深入审查了如何调整众多超参数。

第十一章,梯度提升机,演示了如何使用库xgboostlightgbmcatboost进行高性能训练和预测,并深入审查了如何调整众多超参数。

第十二章,无监督学习,介绍了如何使用降维和聚类进行算法交易。它使用主成分和独立成分分析来提取数据驱动的风险因素。它提出了几种聚类技术,并演示了如何使用层次聚类进行资产配置。

第十三章,处理文本数据,演示了如何将文本数据转换为数值格式,并将第二部分中的分类算法应用于大型数据集的情感分析。

第十四章,主题建模,应用贝叶斯无监督学习来提取能够总结大量文档的潜在主题,并提供更有效地探索文本数据或将主题用作分类模型特征的方法。它演示了如何将这一技术应用于第三章,金融替代数据,中来源的盈利电话交易摘要和向证券交易委员会SEC)提交的年度报告。

第十五章,词嵌入,使用神经网络学习形式的最新语言特征,即捕获语义上下文比传统文本特征更好的词向量,并代表从文本数据中提取交易信号的一个非常有前途的途径。

第十六章,下一步,是对所有前面章节的总结

第十七章深度学习,介绍了 Keras、TensorFlow 和 PyTorch,这是我们将在第四部分中使用的最流行的深度学习框架。它还介绍了训练和调整的技术,包括正则化,并提供了常见架构的概述。要阅读此章节,请访问链接www.packtpub.com/sites/default/files/downloads/Deep_Learning.pdf

第十八章循环神经网络,展示了 RNN 在序列到序列建模中的用途,包括用于时间序列。它演示了 RNN 如何在较长时间段内捕捉非线性模式。要阅读此章节,请访问链接www.packtpub.com/sites/default/files/downloads/Recurrent_Neural_Networks.pdf

第十九章卷积神经网络,涵盖了 CNN 在大规模非结构化数据分类任务中的强大性能。我们将介绍成功的架构设计,例如在卫星数据上训练 CNN,以预测经济活动,并使用迁移学习加速训练。要阅读此章节,请访问链接www.packtpub.com/sites/default/files/downloads/Convolutions_Neural_Networks.pdf

第二十章自编码器和生成对抗网络,介绍了无监督深度学习,包括用于高维数据非线性压缩的自编码器和生成对抗网络GANs),这是生成合成数据的最重要的最近创新之一。要阅读此章节,请访问链接www.packtpub.com/sites/default/files/downloads/Autoencoders_and_Generative_Adversarial_Nets.pdf

第二十一章强化学习,介绍了允许设计和训练代理程序以随着时间响应其环境优化决策的强化学习。您将看到如何构建一个通过 Open AI gym 响应市场信号的代理。要阅读此章节,请访问链接www.packtpub.com/sites/default/files/downloads/Reinforcement_Learning.pdf

要充分利用本书

本书所需的全部内容只需要基本的 Python 和机器学习技术的理解。

下载示例代码文件

您可以从 www.packt.com 的帐户中下载本书的示例代码文件。如果您在其他地方购买了本书,可以访问 www.packt.com/support 并注册,以便直接将文件发送到您的邮箱。

您可以按照以下步骤下载代码文件:

  1. www.packt.com 登录或注册。

  2. 选择 支持 选项卡。

  3. 点击“代码下载与勘误”。

  4. 在搜索框中输入书名并按照屏幕上的说明操作。

下载文件后,请确保使用最新版本的软件解压缩文件夹:

  • Windows 系统使用 WinRAR/7-Zip

  • Mac 系统使用 Zipeg/iZip/UnRarX

  • Linux 系统使用 7-Zip/PeaZip

本书的代码包也托管在 GitHub 上,网址为 github.com/PacktPublishing/Hands-On-Machine-Learning-for-Algorithmic-Trading。如果代码有更新,将在现有的 GitHub 仓库上进行更新。

我们还提供了来自我们丰富的图书和视频目录的其他代码包,可在 github.com/PacktPublishing/ 上获取。快去看看吧!

下载彩色图片

我们还提供了一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图像。您可以从这里下载:www.packtpub.com/sites/default/files/downloads/9781789346411_ColorImages.pdf

使用的约定

本书中使用了一些文本约定。

CodeInText:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 句柄。例如:“调用run_algorithm()函数后,算法继续执行,并返回相同的回测性能DataFrame。”

代码块设置如下:

interesting_times = extract_interesting_date_ranges(returns=returns)
interesting_times['Fall2015'].to_frame('pf') \
    .join(benchmark_rets) \
    .add(1).cumprod().sub(1) \
    .plot(lw=2, figsize=(14, 6), title='Post-Brexit Turmoil')

粗体:表示新术语、重要单词或屏幕上看到的单词。

警告或重要说明显示如下。

提示和技巧显示如下。

第一章:交易机器学习

算法交易依赖于执行算法的计算机程序,以自动化交易策略的某些或全部元素。算法是实现目标的一系列步骤或规则,可以采用许多形式。在机器学习ML)的情况下,算法追求学习其他算法的目标,即根据数据学习规则,例如最小化预测误差。

这些算法编码了组合经理的各种活动,组合经理观察市场交易并分析相关数据,以决定是否下达买入或卖出订单。订单的顺序定义了组合持有的投资组合,该投资组合的目标是随时间产生对资本提供者有吸引力的回报,考虑到他们对风险的偏好。

最终,主动投资管理的目标在于实现阿尔法,即超过用于评估的基准的回报。主动管理的基本法则将信息比率IR)应用于表达主动管理的价值,即投资组合回报超过基准回报(通常是指数)与这些回报的波动性之比。它将信息比率近似为信息系数IC)的乘积,信息系数衡量了预测的质量,即它们与结果的相关性,以及策略的广度,表达为赌注数量的平方根。

因此,产生阿尔法的关键是预测。成功的预测反过来又需要优越的信息或者对公共信息的优越处理能力。算法促进了整个投资过程的优化,从资产配置到构思、交易执行和风险管理。特别是利用机器学习进行算法交易,旨在更有效地利用传统和替代数据,以产生更好且更具可行性的预测,从而提高主动管理的价值。

从历史上看,算法交易曾被更狭义地定义为执行交易自动化以尽量降低成本,这是由卖方提供的,但我们将采用更全面的视角,因为算法的使用,尤其是机器学习,已经开始影响更广泛的活动,从构思和阿尔法因子设计到资产配置、头寸规模和策略的测试和评估。

本章探讨了如何将 ML 的使用作为投资行业竞争优势的关键来源,并将其纳入投资过程,以实现算法交易策略。

我们将在本章中涵盖以下主题:

  • 本书的组织方式及适合阅读本书的读者

  • 机器学习如何在算法交易中发挥战略作用

  • 如何设计和执行交易策略

  • 机器学习如何为算法交易策略增加价值

如何阅读本书

如果您正在阅读本文,那么您可能已经意识到机器学习已经成为许多行业,包括投资行业的战略能力。驱动机器学习兴起的数字数据爆炸对投资产生了特别强大的影响,这在处理信息方面已经有很长的历史了。跨资产类别的交易范围意味着除了曾经是分析工作重点的市场和基本数据之外,还可能涉及广泛的新型替代数据。

你可能也注意到,成功应用机器学习或数据科学需要个人或团队在统计知识、计算能力和领域专业知识方面的整合。换句话说,关键是提出正确的问题,识别和理解可能提供答案的数据,使用各种工具获取结果,并以能够做出正确决策的方式解释它们。

因此,本书从整体上探讨了将机器学习应用于投资和交易领域。在本节中,我们将介绍预期会发生什么,它如何实现其目标,以及您需要什么来实现自己的目标并在此过程中享受乐趣。

预期

本书旨在为您提供将机器学习应用于交易和投资过程中增加价值的战略视角、概念理解和实用工具。为此,它将机器学习作为流程中的重要组成部分而不是独立的练习。

首先,它涵盖了一系列有用于从与不同资产类别相关的多样化数据源中提取信号的监督、无监督和强化学习算法。它介绍了一个机器学习工作流,并专注于具有相关数据和大量代码示例的实际用例。然而,它还发展了数学和统计背景,以便调整算法或解释结果。

该书认识到投资者可以从第三方数据中提取的价值超过其他行业。因此,它不仅涵盖了如何处理市场和基本数据,还涵盖了如何获取、评估、处理和建模另类数据源,例如非结构化文本和图像数据。

它将机器学习的应用与研究和评估阿尔法因子、定量和基于因子的策略联系起来,并将投资组合管理作为部署结合多个阿尔法因子的策略的背景。它还强调了机器学习可以为除了与个别资产价格相关的预测之外的价值,例如资产配置,并解决了使用大型数据集开发交易策略时的错误发现风险。

这本书没有提供投资建议或现成的交易算法,这应该不足为奇。相反,它提供了识别、评估和组合适用于任何特定投资目标的数据集所需的基本构建模块,选择并应用 ML 算法到这些数据,以及基于结果开发和测试算法交易策略的方法。

谁应该阅读这本书

如果您是分析师、数据科学家或具有对金融市场的了解和对交易策略感兴趣的 ML 工程师,您应该会发现这本书很有价值。如果您是一名投资专业人士,希望利用 ML 做出更好的决策,您也应该会受益。

如果您的背景是软件和 ML,您可能只需浏览或跳过 ML 的一些入门材料。同样,如果您的专业是投资,您可能会熟悉一些或所有的金融背景。您可能会发现这本书最有用,因为它涵盖了关键算法、构建模块和用例的概述,而不是针对特定算法或策略的专业覆盖。然而,这本书假设您对继续学习这个非常动态的领域感兴趣。为此,它引用了许多资源来支持您朝着利用和建立基本方法和工具的定制交易策略的旅程。

您应该熟悉使用 Python 3 以及各种科学计算库,如numpypandasscipy,并有兴趣途中学习更多。一些 ML 和 scikit-learn 的经验可能会有所帮助,但我们简要介绍了基本的工作流程,并参考了各种资源来填补或深入研究。

书的组织结构

本书全面介绍了 ML 如何增加交易策略的设计和执行的价值。它分为四个部分,涵盖了数据采集和策略开发过程的不同方面,以及解决各种 ML 挑战的不同解决方案。

第一部分 - 框架 - 从数据到策略设计

第一部分提供了算法交易策略开发的框架。它重点介绍了驱动 ML 算法和本书讨论的策略的数据,概述了如何使用 ML 来推导交易信号,以及如何将策略部署和评估为投资组合的一部分。

本章剩余部分概述了 ML 如何成为投资的核心,描述了交易流程,并概述了 ML 如何增加价值。第二章,市场和基本数据,涵盖了源头以及如何使用原始交易所提供的 tick 和财务报告数据,以及如何访问我们在本书中将依赖的众多开源数据提供者。

第三章,金融的另类数据,提供了评估不断增加的来源和提供者的类别和标准。它还演示了如何通过网站抓取来创建另类数据集,例如收集用于本书第二部分中的自然语言处理NLP)和情感分析算法的盈利电话转录。

第四章,Alpha 因子研究,提供了理解因子如何工作以及如何衡量其绩效的框架,例如使用信息系数IC)。它演示了如何使用 Python 库离线和在 Quantopian 平台上从数据中设计 alpha 因子。它还介绍了使用zipline库对因子进行回测以及使用alphalens库评估其预测能力的方法。

第五章,策略评估,介绍了如何使用历史数据通过zipline离线和在 Quantopian 平台上构建、测试和评估交易策略。它介绍并演示了如何使用pyfolio库计算投资组合绩效和风险指标。它还介绍了如何应对策略回测的方法论挑战,并介绍了从投资组合风险角度优化策略的方法。

第二部分 - ML 基础知识

第二部分涵盖了基本的监督和无监督学习算法,并说明了它们在交易策略中的应用。它还介绍了 Quantopian 平台,您可以在该平台上利用本书中开发的数据和 ML 技术来实施在实时市场中执行交易的算法策略。

第六章,机器学习流程,通过概述如何制定、训练、调整和评估 ML 模型的预测性能作为系统工作流程来铺设舞台。

第七章,线性模型,展示了如何使用线性和逻辑回归进行推断和预测,以及如何使用正则化来管理过拟合的风险。它介绍了 Quantopian 交易平台,并演示了如何构建因子模型和预测资产价格。

第八章,时间序列模型,涵盖了单变量和多变量时间序列,包括向量自回归模型和共整合测试,以及它们如何应用于成对交易策略。第九章,贝叶斯机器学习,介绍了如何制定概率模型以及马尔科夫链蒙特卡洛MCMC)采样和变分贝叶斯如何促进近似推理。它还说明了如何使用 PyMC3 进行概率编程,以深入了解参数和模型的不确定性。

第十章,决策树和随机森林,展示了如何构建、训练和调整非线性基于树的模型以进行洞察和预测。它介绍了基于树的集成模型,并说明了随机森林如何使用自举聚合来克服决策树的一些弱点。第十一章,梯度提升机,集成模型,并演示了如何使用库xgboostlightgbmcatboost进行高性能训练和预测,并深入审查了如何调整众多的超参数。

第十二章,无监督学习,介绍了如何使用降维和聚类进行算法交易。它使用主成分和独立成分分析来提取数据驱动的风险因子。它介绍了几种聚类技术,并演示了如何使用分层聚类进行资产配置。

第三部分 – 自然语言处理

第三部分专注于文本数据,并介绍了最先进的无监督学习技术,以从这一关键的替代数据源中提取高质量的信号。

第十三章,处理文本数据,演示了如何将文本数据转换为数值格式,并应用了第二部分中的分类算法进行大规模数据集的情感分析。第十四章,主题建模,应用了贝叶斯无监督学习来提取能够总结大量文档的潜在主题,并提供了更有效地探索文本数据或将主题用作分类模型特征的方法。它演示了如何将这一技术应用到 第三章,金融替代数据,中获取的收益电话文本和提交给证券交易委员会 (SEC) 的年度报告。

第十五章,词嵌入,使用神经网络学习最先进的语言特征,以单词向量的形式捕获语义上下文,比传统的文本特征更好地表示语义内容,是从文本数据中提取交易信号的一个非常有前景的途径。

第四部分 – 深度学习和强化学习

第四部分介绍了深度学习和强化学习。

  • 第十七章深度学习,介绍了 Keras、TensorFlow 和 PyTorch,这三个最流行的深度学习框架,并说明了如何训练和调整各种架构。

  • 第十八章循环神经网络,为时间序列数据提供了 RNNs。

  • 第十九章卷积神经网络,说明了如何使用 CNN 处理图像和文本数据

  • 第二十章自编码器和生成对抗网络,展示了如何使用深度神经网络进行无监督学习,使用自编码器生成合成数据

  • 第二十一章强化学习,演示了使用强化学习构建动态代理程序,根据奖励使用 OpenAI gym 平台学习策略函数

您成功所需的条件

该书内容围绕着将机器学习算法应用于不同数据集。书中还在 GitHub 上提供了大量额外内容,以便于审阅并通过书中讨论的示例进行实验。它包含了额外的细节和说明,以及众多参考资料。

数据来源

我们将使用来自市场、基本和替代来源的免费历史数据。 第二章,市场和基本数据 和 第三章,金融替代数据 讲述了这些数据来源的特点和获取方式,并介绍了我们在整本书中将使用的关键提供者。 伴随的 GitHub 仓库(见下文)包含了如何获取或创建我们在整个书中将使用的一些数据集的说明,并包括一些较小的数据集。

我们将要获取和处理的一些示例数据源包括但不限于:

  • 纳斯达克 ITCH 订单簿数据

  • 电子数据收集、分析和检索(EDGAR)美国证券交易委员会申报

  • 来自 Seeking Alpha 的盈利电话转录

  • Quandl 每日价格以及超过 3,000 只美国股票的其他数据点

  • 来自美联储等机构的各种宏观基本数据

  • 大量 Yelp 商业评论和 Twitter 数据集

  • 油轮图像数据

一些数据非常庞大(例如纳斯达克和 SEC 申报)。 笔记本会指示是否是这种情况。

GitHub 仓库

GitHub 仓库包含了更多细节中涉及的许多概念和模型的 Jupyter Notebooks。 在书中使用时会引用这些笔记本。 每个章节都有自己的目录,需要时有单独的说明,并且包括与章节内容相关的参考资料。

Jupyter Notebooks 是创建可重现计算叙事的绝佳工具,它使用户能够创建和共享结合了实时代码、叙述文本、数学方程、可视化、交互控件和其他丰富输出的文档。 它还提供了用于与数据进行交互计算的构建模块,例如文件浏览器、终端和文本编辑器。

您可以在以下位置找到代码文件:

github.com/PacktPublishing/Hands-On-Machine-Learning-for-Algorithmic-Trading

Python 库

该书采用 Python 3.7,并推荐使用 miniconda 安装 conda 包管理器,并创建一个 conda 环境来安装必要的库。为此,GitHub 仓库包含一个 environment.yml 文件。请参考 GitHub 仓库的 README 文件中引用的安装说明。

投资行业中机器学习的崛起

在过去几十年中,投资行业已经发生了巨大变化,并在竞争加剧、技术进步和复杂的经济环境中继续发展。本节将回顾塑造投资环境总体和算法交易特别情境的几个关键趋势,以及将在本书中反复出现的相关主题。

推动算法交易和机器学习成为当前主流的趋势包括:

  • 市场微观结构的变化,如电子交易的普及和跨资产类别和地理区域的市场整合

  • 以风险因子暴露为框架的投资策略的发展,而不是资产类别

  • 计算能力、数据生成和管理以及分析方法的革命

  • 算法交易先驱相对于人类、离散投资者的表现优异

此外,2001 年和 2008 年的金融危机影响了投资者对分散化和风险管理的看法,并催生了以 交易所交易基金 (ETF) 形式的低成本被动投资工具。在 2008 年危机后的低收益和低波动性中,成本意识强的投资者将 2 万亿美元从主动管理型共同基金转移到被动管理的 ETF。竞争压力还体现在对冲基金费用的降低,从传统的 2% 年度管理费和 20% 利润份额降至 2017 年的平均 1.48% 和 17.4%。

从电子交易到高频交易

电子交易在能力、交易量、资产类别覆盖范围和地域覆盖范围方面取得了长足的进步,自 20 世纪 60 年代网络开始将价格路由到计算机终端以来。

股票市场已经在全球范围内引领了这一趋势。美国证券交易委员会(SEC)于 1997 年颁布的订单处理规则通过电子通讯网络ECN)向交易所引入了竞争。ECN 是自动化的替代交易系统ATS),它们以指定价格匹配买卖订单,主要用于股票和货币,并注册为经纪人。它允许不同地理位置的大型经纪公司和个人交易者在交易所和交易时间之后直接进行交易,无需中间商。暗池是另一种类型的 ATS,它允许投资者下订单和交易,而无需公开透露其信息,就像交易所维护的订单簿中一样。自 2007 年 SEC 裁定以来,暗池已经增长,通常设在大型银行内,并受到 SEC 监管。

随着电子交易的兴起,成本效益执行的算法迅速发展,并且采用情况从卖方迅速扩展到买方和各种资产类别。自 2000 年左右,自动交易就作为卖方工具出现,旨在实现成本效益的交易执行,通过将订单分散到时间上来限制市场影响。这些工具扩展到买方,并且通过考虑交易成本和流动性以及短期价格和成交量预测等因素变得越来越复杂。

直接市场访问DMA)通过允许交易者直接将订单发送到交易所,使用经纪人的基础设施和市场参与者标识,为交易者提供了更大的执行控制权。赞助访问通过经纪人去除了预先交易风险控制,并形成了高频交易HFT)的基础。

HFT 指的是金融工具的自动化交易,以微秒为单位的极低延迟执行,并且参与者持有很短时间的头寸。其目标是发现和利用市场微观结构的不有效率,即交易场所的机构基础设施。在过去的十年中,HFT 已经大幅增长,据估计,在美国股票市场中占据大约 55%的交易量,在欧洲股票市场中约占 40%。HFT 也在期货市场上增长到大约 80%的外汇期货交易量,以及两三分之二的利率和国债 10 年期期货交易量(FAS 2016)。

高频交易策略旨在利用被动或激进策略每笔交易获得小额利润。被动策略包括套利交易,以从不同交易场所交易的同一资产或其衍生品的微小价格差异中获利。激进策略包括订单预期或动量引爆。订单预期,也称为流动性检测,涉及提交小型探索性订单以侦测大型机构投资者的隐藏流动性,并在大订单之前交易,以从随后的价格波动中获益。动量引爆意味着一个算法执行并取消一系列订单,以欺骗其他高频交易算法更积极地买入(或卖出),并从由此产生的价格变化中获益。

监管机构对某些激进的高频交易策略与市场脆弱性和波动性增加之间的潜在联系表示担忧,比如 2010 年 5 月的闪电崩盘、2014 年 10 月的国债市场波动以及 2015 年 8 月 24 日道琼斯工业平均指数暴跌超过 1000 点。与此同时,由于高频交易的存在,市场流动性随着交易量的增加而增加,从而降低了整体交易成本。

交易量减少、波动性降低以及技术成本和获取数据和交易场所的准入成本上升的组合导致了财务压力。美国股票的高频交易收入据估计首次下降到 2008 年以来的 10 亿美元以下,从 2009 年的 79 亿美元下降。

这一趋势导致了行业的整合,例如,最大的上市专有交易公司 Virtu Financial 进行了各种收购,并共享基础设施投资,例如芝加哥和东京之间的新 Go West 超低延迟路线。同时,创业公司如 Alpha Trading Lab 提供高频交易基础设施和数据,以通过众包算法来使高频交易民主化,并获得利润的一部分。

因子投资和智能贝塔基金

资产提供的回报是与金融投资相关的不确定性或风险的函数。例如,股权投资意味着承担公司的经营风险,而债券投资意味着承担违约风险。

在特定风险特征预测回报的程度上,识别和预测这些风险因素的行为成为设计投资策略时的主要关注点。这产生了有价值的交易信号,并是优秀主动管理结果的关键。随着时间的推移,该行业对风险因素的理解发生了很大变化,并影响了机器学习在算法交易中的应用。

现代投资组合理论MPT)引入了对于给定资产的特异风险和系统性风险的区分。特异风险可以通过多元化消除,但系统性风险则不能。在 1960 年代初,资本资产定价模型CAPM)确定了驱动所有资产回报的单一因素:市场投资组合相对于国库券的回报。市场投资组合由所有可交易证券组成,按其市值加权。资产对市场的系统性暴露由贝塔(beta)来衡量,即资产回报与市场投资组合之间的相关性。

认识到资产风险不取决于孤立的资产,而是取决于其相对于其他资产和整个市场的运动方式,是一项重大的概念突破。换句话说,资产并不因其特定的特异特征而赚取风险溢价,而是因其暴露于基础因素风险而获利。

然而,大量的学术文献和长期的投资经验已经证明,CAPM 的预测是错误的,即资产风险溢价仅取决于其暴露于由资产贝塔测量的单一因素。相反,后来发现了许多额外的风险因素。因子是一种可量化的信号、属性或任何与未来股票回报历史上相关的变量,并且预计未来仍将相关。

这些风险因素被标记为异常,因为它们与有效市场假说EMH)相矛盾,后者认为市场均衡将始终根据 CAPM 定价证券,因此其他因素不应具有预测能力。因素背后的经济理论可以是理性的,即因素风险溢价弥补了不良时期低回报的情况,也可以是行为的,即代理人未能套利超出的回报。

知名的异常包括价值、规模和动量效应,这些效应有助于预测回报,同时控制 CAPM 市场因素。规模效应基于小型公司系统性地胜过大型公司,由 Banz(1981)和 Reinganum(1981)发现。价值效应(Basu 1982)指出,具有低估价指标的公司表现更好。它暗示着具有低价格倍数的公司,如市盈率或市净率低的公司,表现比它们更昂贵的同行更好(正如价值投资的创始人本杰明·格雷厄姆和大卫·多德所建议,并被沃伦·巴菲特所普及)。

动量效应是由克利福德·阿斯尼斯等人于 1980 年代末发现的,阿斯尼斯是 AQR 的创始合伙人之一。该效应表明,具有良好动量的股票,即近 6-12 个月的回报较高的股票,其未来的回报高于市场风险相似的劣质动量股票。研究人员还发现,价值和动量因子解释了美国以外股票的回报,以及其他资产类别,如债券、货币和大宗商品,以及额外的风险因素。

在固定收益领域,价值策略被称为乘坐收益曲线,是一种利率曲线溢价形式。在大宗商品中,它被称为卷曲回报,对于上升期货曲线,它有正回报,否则则为负回报。在外汇市场中,价值策略被称为利差

还有一项流动性溢价。更不流动的证券以低价格交易,并且相对于更流动的对应品具有较高的平均超额回报。具有较高违约风险的债券平均回报较高,反映了信用风险溢价。由于当回报往往下跌时投资者愿意为高波动性购买保险,因此期权市场中的波动性保护卖方往往会获得较高的回报。

多因子模型将风险定义为比市场投资组合更广泛和多样化的内容。1976 年,斯蒂芬·罗斯提出了套利定价理论,该理论主张投资者获得了多个系统性风险来源的补偿,这些风险是不可分散的。最重要的三个宏观因素是增长、通胀和波动性,除了生产力、人口结构和政治风险。1992 年,尤金·法玛和肯尼斯·弗伦奇将股权风险因素的大小和价值与市场因素结合到一个单一模型中,更好地解释了横截面股票回报。后来,他们添加了一个同时解释两种资产类别回报的模型,该模型还包括债券风险因素。

风险因素特别吸引人的一个方面是它们之间的低或负相关性。例如,价值和动量风险因素呈负相关,降低了风险,并且使风险调整后的回报超出了风险因素所隐含的收益。此外,利用杠杆和多空策略,因子策略可以组合成市场中性方法。在将暴露于正风险的证券的多头头寸与暴露于负风险的证券的低配头寸或空头头寸相结合后,可以收集到动态风险溢价。

因此,解释超越 CAPM 的回报的因素被纳入了倾向于支持一个或多个因素的投资风格中,资产开始流入基于因子的投资组合。 2008 年的金融危机强调了当投资者不看基础因子风险时,资产类别标签可能会极具误导性并导致虚假的分散化感,因为资产类别同时崩盘。

在过去几十年中,量化因子投资已经从基于两三种风格的简单方法发展为多因子智能或异类β产品。 智能β基金在 2017 年突破了 1 万亿美元资产管理规模,证明了这种混合投资策略的受欢迎程度,该策略结合了主动和被动管理。 智能β基金采取被动策略,但根据一个或多个因素进行修改,例如选择更便宜的股票或根据股息支付进行筛选,以获得更好的回报。 这种增长与对传统主动管理者收取高费用的批评以及对其业绩加剧的审查同时发生。

持续发现和成功预测风险因素,无论是单独还是与其他风险因素结合,都会显著影响未来资产回报,跨资产类别,这是投资行业中机器学习激增的关键推动力,并且将是本书的一个关键主题。

算法先驱在规模上超越了人类

引领算法交易的公司的资产管理规模AUM)的业绩和增长在引起投资者兴趣以及随后行业努力复制其成功方面发挥了关键作用。系统性基金与高频交易(HFT)不同之处在于,交易可以持有更长时间,同时寻求利用套利机会,而不是单纯依靠速度优势。

主要或完全依赖算法决策的系统性策略最著名的是由数学家 James Simons 引入的,他于 1982 年创立了文艺复兴技术公司,并将其打造成为首屈一指的量化公司。 其神秘的 Medallion 基金,对外关闭,自 1982 年以来年化收益估计为 35%。

DE Shaw,Citadel 和 Two Sigma 是最著名的三家使用基于算法的系统性策略的量化对冲基金,在 2017 年首次以总收益为标准进入前 20 名表现者之列,扣除费用,并自成立以来。

DE Shaw 成立于 1988 年,2018 年资产管理规模为 470 亿美元,在榜单上排名第 3。 Citadel 由 Kenneth Griffin 于 1990 年创立,管理着 290 亿美元,排名第 5 位。 Two Sigma 仅于 2001 年由 DE Shaw 的校友 John Overdeck 和 David Siegel 创立,从 2011 年的 80 亿美元资产管理规模增长到 2018 年的 520 亿美元。 Bridgewater 成立于 1975 年,资产管理规模超过 1500 亿美元,由于其也融合了系统性策略的纯阿尔法基金,仍然处于领先地位。

同样,在机构投资者 2017 年对冲基金 100 强榜单上,排名前六位的五家公司在很大程度上或完全依靠计算机和交易算法做出投资决策——所有这些公司都在一个充满挑战的环境中增长了资产。几家定量型公司上升了几个等级,并在某些情况下将其资产增长了两位数的百分比。排名第二的应用量化研究AQR)在 2017 年将其对冲基金资产增长了 48%,达到了 697 亿美元,并且公司总资产管理规模达到了 1876 亿美元。

在过去三年中,根据复合绩效排名,文艺复兴技术运营的基于量化的对冲基金排名分别为 6 和 24,Two Sigma 排名第 11,D.E. Shaw 分别排名 18 和 32,Citadel 排名 30 和 37。除了表现最好的之外,算法策略在过去几年中表现良好。在过去五年中,量化对冲基金的年均收益率约为 5.1%,而同期平均对冲基金的年均涨幅为 4.3%。

由机器学习驱动的基金吸引了 1 万亿美元的资产管理规模。

计算能力、数据和机器学习方法的三次革命使得系统化、数据驱动的策略的采用不仅更具吸引力和成本效益,而且是竞争优势的关键来源。

因此,算法方法不仅在开创这些策略的对冲基金行业中找到了更广泛的应用,而且在更广泛的资产管理公司以及 ETF 等被动管理的车辆中也找到了应用。特别是,利用机器学习和算法自动化的预测分析在投资过程的所有步骤中发挥着越来越重要的作用,从构思和研究到策略制定和投资组合构建,再到交易执行和风险管理,跨资产类别都是如此。

由于没有量化或算法基金的客观定义,行业规模的估计各不相同,许多传统对冲基金甚至包括共同基金和交易所交易基金(ETF)正在引入计算机驱动的策略或将其整合到人加机的自主环境中。

摩根士丹利在 2017 年估计,过去六年中,算法策略以每年 15%的速度增长,并在对冲基金、共同基金和智能贝塔 ETF 之间控制着约 1.5 万亿美元。其他报告表明,量化对冲基金行业即将超过 1 万亿美元的资产管理规模,在传统对冲基金出现资金流出的背景下,其规模自 2010 年以来几乎翻了一番。相比之下,根据最新的全球对冲基金研究报告,对冲基金行业的总资本达到了 3.21 万亿美元。

市场研究公司 Preqin 估计,几乎有 1,500 家对冲基金中的大多数基金都借助于计算机模型进行交易。量化对冲基金现在负责美国所有股票交易的 27%,而在 2013 年仅占 14%。但许多基金使用数据科学家或量化分析师,他们反过来又使用机器来构建大型统计模型(WSJ)。

然而,近年来,基金已经转向了真正的机器学习,人工智能系统可以以高速分析大量数据,并通过这些分析改进自身。最近的例子包括 Rebellion Research、Sentient 和 Aidyia,它们依赖于进化算法和深度学习来设计完全自动化的人工智能AI)驱动的投资平台。

从核心对冲基金行业开始,算法策略的采用已经扩展到了共同基金,甚至是以智能贝塔基金的形式管理的被动交易基金,以及以量化方法的形式管理的自由基金。

量化基金的出现

主动投资管理出现了两种不同的方法:系统化(或量化)和自由裁量投资。系统化方法依赖于算法,以重复可行且数据驱动的方式来识别跨多个证券的投资机会;相比之下,自由裁量方法涉及对少量证券进行深入分析。随着基本面经理采用更多的数据科学驱动方法,这两种方法变得越来越相似。

根据巴克莱的数据,现在连基本面交易员也使用量化技术,占系统资产的 550 亿美元。量化基金对特定公司不持偏见,而是交易各种证券的模式和动态。巴克莱编制的数据显示,量化交易员现在占总对冲基金资产的约 17%。

资产规模达 120 亿美元的 Point72 资产管理公司已经将大约一半的投资组合经理转向了人加机器的方法。Point72 还向一个分析大量替代数据并将结果传递给交易员的团队投资了数千万美元。

投资战略能力

对相关能力的投资——技术、数据,以及最重要的是熟练的人才——凸显了使用机器学习进行算法交易对于竞争优势有多么重要,尤其是考虑到自 2008 年金融危机以来,被动指数投资工具(如 ETF)的日益普及。

摩根士丹利指出,其量化客户中仅有 23% 的客户表示不考虑使用或尚未使用机器学习,而在 2016 年这一比例为 44%。

Guggenheim Partners LLC 在加利福尼亚州劳伦斯·伯克利国家实验室建造了一个价值 100 万美元的超级计算集群,用于帮助 Guggenheim 的量化投资基金进行数据分析。计算机的电费每年还要再花费 100 万美元。

AQR 是一个量化投资集团,依靠学术研究来识别并系统地交易那些长期以来证明能够击败整个市场的因素。该公司过去不喜欢完全依靠计算机策略的量化同行,如文艺复兴技术或 DE Shaw。然而,最近,AQR 开始利用机器学习在市场中寻找利润模式,以解析新型数据集,例如油井和油轮所投下的阴影的卫星图片。

领先的公司黑石集团,拥有超过 5 万亿美元的资产管理规模,也通过大量投资于 SAE,一个在金融危机期间收购的系统性交易公司,来打败裁量基金经理的算法。富兰克林·坦普尔顿公司以未披露的金额收购了 Random Forest Capital,这是一家以债务为重点、以数据为导向的投资公司,希望其技术能够支持更广泛的资产管理者。

机器学习和另类数据

对冲基金长期以来一直通过信息优势和发现新的不相关信号来寻找 Alpha。在历史上,这包括专有调查购物者、选民以及选举或公投前的情况。偶尔,利用公司内部人员、医生和专家网络来扩展对行业趋势或公司的了解越过了法律界限:2010 年后,一系列交易员、投资组合经理和分析师因使用内幕信息而受到起诉,动摇了这一行业。

相比之下,利用机器学习开发传统和另类数据源的信息优势与专家和行业网络或接触公司管理层无关,而是与收集大量数据并实时分析它们的能力相关。

三个趋势彻底改变了算法交易策略中数据的使用方式,并可能进一步将投资行业从裁量性转变为量化风格:

  • 数字数据量的指数增长

  • 计算能力和数据存储容量的成本下降带来了增长。

  • 分析复杂数据集的机器学习方法的进步

传统数据包括经济统计数据、交易数据或企业报告。而另类数据则更为广泛,包括卫星图像、信用卡销售、情绪分析、移动地理位置数据和网站抓取等来源,以及将业务中生成的数据转化为有价值的情报。原则上,它包括任何包含可使用机器学习提取交易信号的数据源。

例如,来自保险公司的数据,关于新汽车保险政策的销售,不仅代表了新汽车销售的量,还可以细分为品牌或地理区域。许多供应商从网站上抓取有价值的数据,范围从应用下载和用户评论到航空公司和酒店预订。社交媒体网站也可以被抓取,以获取有关消费者观点和趋势的线索。

通常,数据集很大,需要使用可扩展的数据解决方案进行存储、访问和分析,以进行并行处理,例如 Hadoop 和 Spark;根据德意志银行的数据,目前全球有超过 10 万亿个网页的 10 亿多个网站,数据量达到 500 涵字节(或 5000 亿吉字节)。每年新增的网站超过 1 亿个。

在公司公布业绩之前,可以通过其网站上职位列表的减少、员工在招聘网站 Glassdoor 上对其首席执行官的内部评价,或者其网站上服装平均价格的下降来获取对公司前景的实时见解。这可以与汽车停车场的卫星图像和手机定位数据结合使用,这些数据显示有多少人正在访问商店。另一方面,对特定功能区域或特定地理区域的职位发布量增加可以得出战略性动向。

最有价值的数据之一是直接揭示消费支出的数据,信用卡信息是其主要来源。这些数据仅提供了销售趋势的部分视图,但与其他数据结合使用时可以提供关键见解。例如,Point72 每天分析 8 千万笔信用卡交易。我们将在《第三章》详细探讨各种数据来源、使用案例以及如何评估它们,金融的替代数据

在过去两年中,投资集团在替代数据集和数据科学家方面的支出已经翻了一番,因为资产管理行业试图重振其日渐衰落的运势。2018 年 12 月,alternativedata.org 上列出了 375 家替代数据提供商(由提供商 Yipit 赞助)。

资产管理者去年在数据集和招聘新员工进行解析方面的总支出为 3.73 亿美元,比 2016 年增长了 60%,今年预计总支出将达到 6.16 亿美元,根据 alternativedata.org 对投资者的调查。该机构预测,到 2020 年,整体支出将上升到超过 10 亿美元。一些估计甚至更高:Optimus,一家咨询公司,估计投资者每年在替代数据上的支出约为 50 亿美元,并预计未来几年行业将以 30% 的速度增长。

随着对有价值数据源的竞争日益激烈,独家安排成为数据源合同的一个关键特征,以保持信息优势。同时,隐私问题日益严重,监管机构已经开始关注目前主要没有受到监管的数据提供者行业。

交易算法的众包

最近,几家算法交易公司开始提供投资平台,提供数据访问和编程环境,以众包方式获取成为投资策略或整个交易算法的风险因素。关键示例包括 WorldQuant、Quantopian 和 2018 年推出的 Alpha Trading Labs。

WorldQuant 自 2007 年以来为 Millennium Management 管理了超过 50 亿美元,资产管理规模为 346 亿美元,并于 2018 年宣布将推出其首个公共基金。它在全球的α工厂中雇佣了数百名科学家和更多的兼职工人,这个工厂将投资过程组织成量化的生产线。该工厂声称已经生产了 400 万个成功测试的α因子,用于更复杂的交易策略,并且目标是 1 亿个。每个α因子都是一个算法,旨在预测未来资产价格的变化。其他团队将α因子组合成策略,将策略组合成投资组合,在投资组合之间分配资金,并在避免相互 cannibalize 的策略的同时管理风险。

设计和执行交易策略

机器学习可以在交易策略的生命周期的多个步骤中增加价值,并依赖于关键的基础设施和数据资源。因此,这本书旨在探讨机器学习技术如何融入更广泛的设计、执行和评估策略的过程中。

一个算法交易策略由一系列α因子驱动,这些因子将一个或多个数据源转化为信号,进而预测未来的资产回报并触发买入或卖出订单。第二章,市场和基本数据和第三章,金融替代数据涵盖了数据的采集和管理,这是成功交易策略的最重要的驱动因素。

第四章,α因子研究概述了一个方法论上合理的过程,用于管理随着数据量增加而增加的虚假发现的风险。第五章,策略评估为交易策略的执行和绩效评估提供了背景:

让我们简要地了解一下这些步骤,我们将在接下来的章节中深入讨论。

数据采集和管理

数据在体积、多样性和速度方面的戏剧性演变既是将机器学习应用于算法交易的必要条件,也是驱动力。数据的不断增加需要积极管理,以发掘潜在价值,包括以下步骤:

  1. 识别和评估包含不会太快衰减的 Alpha 信号的市场、基本和替代数据来源。

  2. 部署或访问基于云的可扩展数据基础设施和分析工具,如 Hadoop 或 Spark,以促进快速、灵活的数据访问

  3. 谨慎管理和策划数据,避免通过**点时(PIT)**基础进行向前看偏差调整它。这意味着数据可能只反映给定时间可用和已知的信息。在扭曲的历史数据上训练的 ML 算法几乎肯定会在实时交易中失败。

Alpha 因子研究和评估

Alpha 因子的设计旨在从数据中提取信号,以预测给定投资宇宙在交易周期内的资产回报。当评估时,一个因子对每个资产都有一个值,但可能结合一个或多个输入变量。该过程涉及下图中概述的步骤:

交易策略工作流的研究阶段包括 Alpha 因子的设计、评估和组合。机器学习在这个过程中起着重要作用,因为投资者对较简单因子的信号衰减以及当今可用的数据更加丰富而作出反应,因素的复杂性增加了。

预测性 Alpha 因子的开发需要探索输入数据与目标回报之间的关系,创造性的特征工程,并测试和微调数据转换以优化输入的预测能力。

数据转换范围从简单的非参数排名到复杂的集成模型或深度神经网络,取决于输入中的信号量和输入与目标之间关系的复杂性。许多较简单的因子已经从学术研究中出现,并且在过去几十年中在工业中越来越广泛地使用。

为了最小化由数据挖掘导致的假发现的风险,并且因为金融领域已经经历了几十年的研究,并产生了几个诺贝尔奖,投资者更喜欢依赖与金融市场和投资者行为理论相一致的因子。阐明这些理论不在本书的范围之内,但参考资料将突出显示进一步探讨这种算法交易策略重要框架方面的途径。

要验证 alpha 因子候选的信号内容,就需要在代表市场体制的环境中获得其预测能力的稳健估计。可靠的估计需要避免许多方法论和实践上的陷阱,包括使用导致存活或前瞻性偏差的数据,因为它们不反映真实的 PIT 信息,或者由于对同一数据进行多次测试而未能纠正偏差。

从 alpha 因子中得出的信号通常单独很弱,但与其他因子或数据源结合起来,例如,根据市场或经济环境的情况调节信号,就足够强大了。

投资组合优化与风险管理

Alpha 因子发出入场和退出信号,导致买入或卖出订单,订单执行结果导致投资组合持仓。各个持仓的风险配置相互作用,形成特定的投资组合风险配置。投资组合管理涉及优化持仓权重,以实现所需的投资组合风险和回报配置,该过程高度动态,可以不断纳入不断演化的市场数据。

在此过程中的交易执行需要平衡交易员的困境:快速执行往往会由于市场影响而增加成本,而慢速执行可能会在实现价格偏离决策时的价格时引起执行差距。风险管理贯穿整个投资组合管理过程,以根据观察到或预测到的市场环境变化来调整持仓或承担对冲,从而影响投资组合风险配置。

策略回测

将投资理念纳入算法策略中需要进行广泛的测试,采用科学方法试图根据其在备用样本市场情景中的表现来拒绝该理念。测试可能涉及使用模拟数据来捕捉被认为可能但在历史数据中未反映出来的情景。

一个策略回测引擎需要逼真地模拟策略的执行,以实现无偏的性能和风险估计。除了数据或统计学使用上的缺陷可能引入的潜在偏差之外,回测引擎还需要准确地表示与市场条件相一致的交易信号评估、订单下达和执行等实践方面的内容。

机器学习和算法交易策略

量化策略已经在三个阶段中演变并变得更加复杂:

  1. 在 1980 年代和 1990 年代,信号通常源自学术研究,并使用从市场和基本数据中衍生出的单一或极少量的输入。这些信号现在在很大程度上被商品化,并且作为 ETF 可得,例如基本的均值回归策略。

  2. 在 2000 年代,基于因子的投资大量涌现。基金使用算法识别暴露于价值或动量等风险因子的资产,以寻求套利机会。金融危机早期的赎回引发了 2007 年 8 月的量化颤抖,这一现象在基于因子的基金行业中蔓延开来。现在,这些策略也以长期智能贝塔基金的形式出现,根据一组给定的风险因子倾斜投资组合。

  3. 第三个时代由对 ML 能力和替代数据的投资驱动,以生成可重复交易策略的利润信号。因子衰减是一个主要挑战:从发现到出版,新异常的超额收益已经显示出下降了四分之一,并且在出版后因竞争和拥挤导致下降超过 50%。

有几种使用算法执行交易规则的交易策略类别:

  • 旨在从小的价格波动中获利的短期交易,例如由于套利。

  • 旨在利用预测其他市场参与者行为的行为策略。

  • 旨在优化交易执行的程序,以及

  • 基于预测定价的大量交易群体。

上述 HFT 基金主要依赖短期持有期从基于买卖盘套利或统计套利的微小价格波动中获利。行为算法通常在较低流动性环境中运作,并旨在预测大型参与者可能会对价格产生重大影响的动向。价格影响的期望基于嗅探算法,这些算法产生有关其他市场参与者策略或市场模式(例如 ETF 强制交易)的见解。

交易执行程序旨在限制交易的市场影响,并从简单的切片交易以匹配时间加权平均价格TWAP)或成交量加权平均价格VWAP)到更复杂的算法。这些算法可以在证券或投资组合级别操作,例如,实施多腿衍生品或跨资产交易。

交易 ML 的用例

ML 从各种市场、基本和替代数据中提取信号,并可以应用于算法交易策略过程的所有步骤。关键应用包括:

  • 数据挖掘以识别模式和提取特征。

  • 通过监督学习生成风险因子或 Alpha,并提出交易思路。

  • 将个体信号聚合成策略。

  • 根据算法学到的风险配置资产。

  • 通过使用合成数据来测试和评估策略。

  • 使用强化学习进行交易策略的交互式自动优化。

我们简要介绍了其中一些应用,并确定我们将在后面的章节中演示它们的使用。

用于特征提取的数据挖掘

对大型复杂数据集的成本效益评估需要大规模检测信号。全书中有几个示例:

  • 信息论是一个有用的工具,用于提取捕捉潜在信号的特征,并可用于 ML 模型。在第四章,Alpha Factor Research中,我们使用互信息来评估单个特征对监督学习算法预测资产收益的潜在价值。

  • 在第十二章,无监督学习中,我们介绍了从高维数据集中创建特征的各种技术。在第十四章,主题建模中,我们将这些技术应用于文本数据。

  • 我们强调了获取有关单个变量预测能力的模型特定方法。我们使用一种称为SHapley Additive exPlanationsSHAP)的新颖博弈论方法来将预测性能归因于具有大量输入变量的复杂梯度增强机器中的单个特征。

监督学习用于α因子的创建和聚合

将 ML 应用于交易的主要理由是获得关于资产基本面、价格走势或市场状况的预测。策略可以利用多个 ML 算法相互构建。下游模型可以通过整合关于个别资产前景、资本市场预期和证券之间相关性的预测,生成组合水平的信号。或者,ML 预测可以像上面概述的量化基本方法那样通知自主交易。ML 预测还可以针对特定风险因素,如价值或波动性,或者实施技术方法,如趋势跟踪或均值回归:

  • 在第三章,金融替代数据中,我们说明了如何处理基本数据以创建 ML 驱动的估值模型的输入

  • 在第十三章,处理文本数据,第十四章,主题建模,和第十五章,词嵌入中,我们使用企业评论的替代数据,该数据可用于为公司的收入制定预测,作为估值练习的输入。

  • 在第八章,时间序列模型中,我们演示了如何预测宏观变量作为市场预期的输入以及如何预测波动性等风险因素

  • 第十八章递归神经网络中,我们介绍了递归神经网络RNNs),它们在非线性时间序列数据上表现出优越的性能。

资产配置

ML 已被用于基于决策树模型进行投资组合配置,该模型计算一种层次化的风险平衡形式。因此,风险特征是由资产价格模式驱动的,而不是由资产类别驱动的,实现了优越的风险收益特征。

在第五章,策略评估和第十二章,无监督学习中,我们说明了层次聚类如何提取数据驱动的风险类别,这些类别比传统资产类别定义更好地反映了相关性模式。

测试交易想法

回测是选择成功的算法交易策略的关键步骤。使用合成数据的交叉验证是生成可靠的样本外结果的关键 ML 技术,当结合适当的方法来纠正多次测试时。金融数据的时间序列性质要求对标准方法进行修改,以避免前瞻性偏差或以其他方式污染用于训练、验证和测试的数据。此外,历史数据的有限可用性已经促使出现了使用合成数据的替代方法:

  • 我们将演示使用市场、基本和替代数据来测试 ML 模型的各种方法,以获得对样本外误差的合理估计。

  • 第二十章自动编码器和生成对抗网络中,我们介绍了能够生成高质量合成数据的 GAN。

强化学习

交易发生在竞争激烈、互动式市场中。强化学习旨在训练代理以学习基于奖励的策略函数。

  • 第二十一章强化学习中,我们介绍了关键的强化学习算法,如 Q-Learning 和 Dyna 架构,并演示了使用 OpenAI 的 gym 环境对交易进行强化学习算法的训练。

概要

在本章中,我们介绍了算法交易策略以及 ML 如何成为设计和组合 alpha 因子的关键因素,这些因素又是投资组合表现的关键驱动因素。我们涵盖了围绕算法交易策略的各种行业趋势,替代数据的出现以及利用 ML 来利用这些新信息优势来源的情况。

此外,我们介绍了算法交易策略设计过程,重要的 alpha 因子类型,以及我们将如何使用 ML 来设计和执行我们的策略。在接下来的两章中,我们将更仔细地研究任何算法交易策略的推动力—市场、基本和替代数据来源—使用 ML。

第二章:市场和基本数据

数据一直是交易的重要驱动因素,交易员长期以来一直在努力通过获取优越信息来获取优势。这些努力至少可以追溯到有关罗斯柴尔德家族利用鸽子跨越海峡携带的关于滑铁卢战役英军胜利的提前消息进行债券购买的传闻。

如今,对更快数据访问的投资采取了由领先的高频交易HFT)公司组成的 Go West 联盟的形式,该联盟将芝加哥商品交易所CME)与东京连接起来。在 CME 和纽约 BATS 交易所之间的往返延迟已降至接近理论极限的 8 毫秒,因为交易员竞相利用套利机会。

传统上,投资策略主要依赖于公开可用的数据,有限地努力创建或获取私有数据集。在股票的情况下,基本策略使用基于报告的财务数据构建的金融模型,可能结合行业或宏观数据。由技术分析驱动的策略从市场数据中提取信号,例如价格和成交量。

机器学习ML)算法可以更有效地利用市场和基本数据,特别是当与替代数据结合使用时,这是下一章的主题。我们将在后续章节中介绍几种侧重于市场和基本数据的技术,例如经典和现代时间序列技术,包括循环神经网络RNNs)。

本章介绍市场和基本数据源以及它们被创建的环境。熟悉各种订单类型和交易基础设施很重要,因为它们影响交易策略的回测模拟。我们还说明了如何使用 Python 访问和处理交易和财务报表数据。

特别是,本章将涵盖以下主题:

  • 市场微观结构如何塑造市场数据

  • 如何利用 Nasdaq ITCH 从 tick 数据重建订单簿

  • 如何使用各种类型的条形图总结 tick 数据

  • 如何处理可扩展业务报告语言XBRL)编码的电子申报

  • 如何解析和结合市场和基本数据以创建 P/E 序列

  • 如何使用 Python 访问各种市场和基本数据源

如何处理市场数据

市场数据是在众多市场交易中买卖订单的提交和处理过程中产生的。这些数据反映了交易场所的机构环境,包括管理订单、交易执行和价格形成的规则和法规。

算法交易员使用机器学习算法分析买卖订单的流动以及由此产生的成交量和价格统计数据,提取能捕捉到例如需求-供给动态或某些市场参与者行为的交易信号或特征。

我们将首先审查影响在回测期间模拟交易策略的机构特征。然后,我们将介绍如何从订单簿来源重建 Tick 数据。接下来,我们将重点介绍几种规范化 Tick 数据的方法,并旨在最大化信息内容。最后,我们将说明如何访问各种市场数据提供商接口,并突出几个提供商。

市场微观结构

市场微观结构是金融经济学的一个分支,它研究交易过程以及相关市场的组织。机构细节在不同资产类别及其衍生品、交易场所和地理位置上相当复杂和多样化。在我们深入研究交易产生的数据之前,我们将对关键概念进行简要概述。GitHub 上的参考链接指向了几个对这一主题进行了详细处理的来源。

市场场所

金融工具的交易发生在有组织的、主要是电子交易所和场外市场上。交易所是买方和卖方相遇的中央市场,在这里买方竞相出价,而卖方竞相报出最低的报价。

在美国和国外有许多交易所和替代交易场所。以下表格列出了一些较大的全球交易所以及截至 2018 年 03 月各种资产类别(包括衍生品)的 12 个月交易量。通常,少数金融工具占据了大部分交易量:

股票
交易所市值(美元百万)上市公司数量每日成交量(美元百万)每日股票交易量('000)每日期权交易量('000)
纽约证券交易所23,138,6262,29478,4106,1221,546
纳斯达克-美国10,375,7182,96865,0267,1312,609
日本交易所集团6,287,7393,61828,3973,3611
上海证券交易所5,022,6911,42134,7369,801
欧洲交易所4,649,0731,2409,410836304
香港交易及结算所4,443,0822,18612,0311,174516
伦敦证券交易所集团3,986,4132,62210,3981,011
深圳证券交易所3,547,3122,11040,24414,443
德国交易所2,339,0925067,825475
印度孟买证券交易所有限公司2,298,1795,4396021,105
印度国家证券交易所有限公司2,273,2861,9525,09210,355
BATS 全球市场 - 美国1,243
芝加哥期权交易所1,811
国际证券交易所1,204

交易所可能依赖双边交易或以订单为驱动的系统,根据某些规则匹配买入和卖出订单。价格形成可能通过拍卖进行,例如在纽约证券交易所(NYSE)中,最高出价和最低报价被匹配,或通过买家从卖家购买然后卖给买家的交易商进行。

许多交易所使用提供流动性的中间人,即通过在某些证券中做市来进行交易的能力。例如,纽约证券交易所通常有一个指定的市场主持人,他确保每个证券的交易有序进行,而全国证券交易商自动报价系统Nasdaq)有几个。中间人可以充当作为自己代理人交易的交易商,也可以充当作为他人代理人交易的经纪人。

交易所过去是成员所有的,但随着市场改革的加剧,它们经常转为公司所有。纽约证券交易所可以追溯到 1792 年,而纳斯达克于 1971 年开始,是世界上第一个电子股票交易市场,并接管了大多数曾在场外交易的股票交易。仅在美国股票市场,交易分散在 13 个交易所和 40 多个另类交易场所,每个都向综合带报告交易,但延迟不同。

订单类型

交易员可以提交各种类型的买入或卖出订单。一些订单保证立即执行,而另一些可能规定价格阈值或其他触发执行的条件。订单通常仅在同一交易日有效,除非另有规定。

市场订单保证在到达交易场所时立即执行订单,以那一刻的价格为准。相比之下,限价订单仅在市场价格高于(低于)卖出(买入)限价订单的限价时执行。转而停止订单仅在市场价格上升到(下跌到)买入(卖出)停止订单的指定价格时才变为活动状态。购买停止订单可用于限制空头交易的损失。停止订单也可能有限制。

订单可能附加有许多其他条件——全或无订单防止部分执行,仅在指定数量的股票可用时才会被填充,并且可以在当天或更长时间内有效。它们需要特殊处理,对市场参与者不可见。立即成交或取消订单也防止部分执行,但如果未立即执行则取消。立即取消订单立即买入或卖出可用的股票数量并取消剩余部分。不持有订单允许经纪人决定执行的时间和价格。最后,市场开盘/收盘订单在市场开盘或收盘时或附近执行。允许部分执行。

处理订单簿数据

市场数据的主要来源是订单簿,它在整天实时不断更新以反映所有交易活动。 交易所通常将此数据作为实时服务提供,并可能免费提供一些历史数据。

交易活动体现在市场参与者发送的大量有关交易订单的消息中。 这些消息通常符合用于实时交换证券交易和市场数据的电子金融信息交换FIX)通信协议或本地交换协议的语法。

FIX 协议

就像 SWIFT 是后台(例如,用于交易结算)消息传递的消息协议一样,FIX 协议是交易执行之前和之间的默认消息标准,在交易所、银行、经纪商、结算公司和其他市场参与者之间的通信中。 富达投资和所罗门兄弟公司于 1992 年引入了 FIX,以促进经纪商和机构客户之间的电子通信,当时他们通过电话交换信息。

它在全球股票市场上变得流行,然后扩展到外汇、固定收益和衍生品市场,进一步扩展到后交易以支持直通处理。 交易所提供对 FIX 消息的访问作为实时数据提要,由算法交易员解析以跟踪市场活动,并且例如识别市场参与者的踪迹并预测其下一步行动。

消息序列允许重建订单簿。 跨多个交易所的交易规模产生了大量(~10 TB)难以处理的非结构化数据,因此可以成为竞争优势的来源。

FIX 协议目前版本为 5.0,是一个具有庞大相关行业专业人士社区的免费开放标准。 它像更近期的 XML 一样是自描述的,FIX 会话由底层的传输控制协议TCP)层支持。 社区不断添加新功能。

该协议支持管道分隔的键值对,以及基于标签的 FIXML 语法。 请求服务器登录的示例消息如下所示:

8=FIX.5.0|9=127|35=A|59=theBroker.123456|56=CSERVER|34=1|32=20180117- 08:03:04|57=TRADE|50=any_string|98=2|108=34|141=Y|553=12345|554=passw0rd!|10=131|

有一些用于制定和解析 FIX 消息的 Python 开源 FIX 实现可以使用。 交互经纪商提供了用于自动交易的基于 FIX 的计算机对计算机接口CTCI)(请参见 GitHub 存储库中本章的资源部分)。

纳斯达克 TotalView-ITCH 订单簿数据

虽然 FIX 具有主导的大市场份额,但交易所也提供本地协议。 纳斯达克提供了一种 TotalView ITCH 直接数据提要协议,允许订阅者跟踪股票工具的单个订单,从下单到执行或取消。

因此,它允许重建订单簿,跟踪特定证券或金融工具的活跃限价买入和卖出订单列表。订单簿通过列出每个价格点上投标或报价的股份数量来显示全天市场深度。它还可能识别特定买入和卖出订单的市场参与者,除非它是匿名下达的。市场深度是流动性的关键指标,以及大额市场订单的潜在价格影响。

除了匹配市价和限价订单,纳斯达克还进行市场开盘和闭市时执行大量交易的拍卖或交叉交易。随着被动投资继续增长,交叉交易变得越来越重要,交易员寻找执行更大块的股票的机会。TotalView 还发布了纳斯达克开市和闭市以及纳斯达克 IPO/停牌交叉交易的净订单失衡指示器(NOII)。

解析二进制 ITCH 消息

ITCH v5.0 规范声明了与系统事件、股票特征、限价订单的下达和修改以及交易执行相关的 20 多种消息类型。它还包含有关开市和闭市前净订单失衡的信息。

纳斯达克提供了数月的每日二进制文件样本。本章的 GitHub 存储库包含一个名为 build_order_book.ipynb 的笔记本,演示了如何解析 ITCH 消息的示例文件,并重建任何给定 tick 的执行交易和订单簿。

以下表格显示了样本文件日期为 2018 年 3 月 29 日时最常见消息类型的频率:

消息类型订单簿影响消息数量
A新的未归属限价订单136,522,761
D订单取消133,811,007
U订单取消并替换21,941,015
E完全或部分执行;可能有多条针对同一原始订单的消息6,687,379
X部分取消后修改5,088,959
F添加归属订单2,718,602
P交易消息(非交叉)1,120,861
C在不同于初始显示价格的价格上全部或部分执行157,442
Q交叉交易消息17,233

对于每条消息,规范列出了组件及其相应的长度和数据类型:

名称偏移量长度注释
消息类型01F添加订单 MPID 归属消息
股票定位12整数标识证券的定位代码
跟踪编号32整数纳斯达克内部跟踪编号
时间戳56整数自午夜以来的纳秒数
订单参考编号118整数新订单的唯一参考编号
买卖指示符 191字母订单类型:B = 买入订单,S = 卖出订单
股票204整数添加到订单簿的订单股票数量
股票248Alpha股票符号,右侧填充空格
价格324价格(4)新订单的显示价格
归属364Alpha与订单相关联的纳斯达克市场参与者标识符

Python 提供了 struct 模块,通过格式字符串来解析二进制数据,该格式字符串通过指定字节字符串的各个组件的长度和类型来标识消息元素,按照规范中的排列方式。

让我们逐步解析交易消息并重建订单簿的关键步骤:

  1. ITCH 解析器依赖于作为.csv文件提供的消息规范(由create_message_spec.py创建),并根据formats字典组装格式字符串:
formats = {
    ('integer', 2): 'H',  # int of length 2 => format string 'H'
    ('integer', 4): 'I',
    ('integer', 6): '6s', # int of length 6 => parse as string, 
      convert later
    ('integer', 8): 'Q',
    ('alpha', 1)  : 's',
    ('alpha', 2)  : '2s',
    ('alpha', 4)  : '4s',
    ('alpha', 8)  : '8s',
    ('price_4', 4): 'I',
    ('price_8', 8): 'Q',
}
  1. 解析器将消息规范转换为格式字符串和捕获消息内容的namedtuples
# Get ITCH specs and create formatting (type, length) tuples
specs = pd.read_csv('message_types.csv')
specs['formats'] = specs[['value', 'length']].apply(tuple, 
                           axis=1).map(formats)

# Formatting for alpha fields
alpha_fields = specs[specs.value == 'alpha'].set_index('name')
alpha_msgs = alpha_fields.groupby('message_type')
alpha_formats = {k: v.to_dict() for k, v in alpha_msgs.formats}
alpha_length = {k: v.add(5).to_dict() for k, v in alpha_msgs.length}

# Generate message classes as named tuples and format strings
message_fields, fstring = {}, {}
for t, message in specs.groupby('message_type'):
    message_fields[t] = namedtuple(typename=t, field_names=message.name.tolist())
    fstring[t] = '>' + ''.join(message.formats.tolist())
  1. alpha 类型的字段需要按照format_alpha函数中定义的进行后处理:
def format_alpha(mtype, data):
    for col in alpha_formats.get(mtype).keys():
        if mtype != 'R' and col == 'stock': # stock name only in 
                                              summary message 'R'
            data = data.drop(col, axis=1)
            continue
        data.loc[:, col] = data.loc[:, col].str.decode("utf-
                                    8").str.strip()
        if encoding.get(col):
            data.loc[:, col] = data.loc[:, 
                     col].map(encoding.get(col)) # int encoding
    return data
  1. 单日的二进制文件包含超过 3 亿条消息,总计超过 9 GB。该脚本会将解析的结果迭代地附加到以快速的 HDF5 格式存储的文件中,以避免内存限制(有关此格式的更多信息,请参阅本章的最后一节)。以下(简化的)代码处理二进制文件,并生成按消息类型存储的解析订单:
with (data_path / file_name).open('rb') as data:
    while True:
        message_size = int.from_bytes(data.read(2), byteorder='big', 
                       signed=False)
        message_type = data.read(1).decode('ascii')
        message_type_counter.update([message_type])
        record = data.read(message_size - 1)
        message = message_fields[message_type]._make(unpack(fstring[message_type],  
                                   record))
        messages[message_type].append(message)

        # deal with system events like market open/close
        if message_type == 'S':
            timestamp = int.from_bytes(message.timestamp, 
                                       byteorder='big')
            if message.event_code.decode('ascii') == 'C': # close
                store_messages(messages)
                break
  1. 预料之中,这一天交易的 8500 多只股票中的一小部分占了大部分交易:
with pd.HDFStore(hdf_store) as store:
    stocks = store['R'].loc[:, ['stock_locate', 'stock']]
    trades = store['P'].append(store['Q'].rename(columns=
                        {'cross_price': 'price'}).merge(stocks)
trades['value'] = trades.shares.mul(trades.price)
trades['value_share'] = trades.value.div(trades.value.sum())
trade_summary = 
    trades.groupby('stock').value_share.sum().sort_values
                            (ascending=False)
trade_summary.iloc[:50].plot.bar(figsize=(14, 6), color='darkblue', 
                                 title='% of Traded Value')
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda y, _: 
                                    '{:.0%}'.format(y)))

我们得到了以下图形的绘制:

重建交易和订单簿

解析的消息允许我们重建给定日期的订单流。'R' 消息类型包含在给定日期内交易的所有股票列表,包括有关首次公开募股IPOs)和交易限制的信息。

在一天的交易过程中,会添加新订单,并删除执行和取消的订单。对于引用前一日期放置的订单的消息,进行适当的会计处理需要跟踪多天的订单簿,但我们在此忽略了此方面的内容。

get_messages() 函数说明了如何收集影响交易的单一股票的订单(有关每个消息的详细信息,请参阅 ITCH 规范,略有简化,请参阅笔记本):

def get_messages(date, stock=stock):
    """Collect trading messages for given stock"""
    with pd.HDFStore(itch_store) as store:
        stock_locate = store.select('R', where='stock = 
                                     stock').stock_locate.iloc[0]
        target = 'stock_locate = stock_locate'

        data = {}
        # relevant message types
        messages = ['A', 'F', 'E', 'C', 'X', 'D', 'U', 'P', 'Q']
        for m in messages:
            data[m] = store.select(m,  
              where=target).drop('stock_locate', axis=1).assign(type=m)

    order_cols = ['order_reference_number', 'buy_sell_indicator', 
                  'shares', 'price']
    orders = pd.concat([data['A'], data['F']], sort=False,  
                        ignore_index=True).loc[:, order_cols]

    for m in messages[2: -3]:
        data[m] = data[m].merge(orders, how='left')

    data['U'] = data['U'].merge(orders, how='left',
                                right_on='order_reference_number',
                                left_on='original_order_reference_number',
                                suffixes=['', '_replaced'])

    data['Q'].rename(columns={'cross_price': 'price'}, inplace=True)
    data['X']['shares'] = data['X']['cancelled_shares']
    data['X'] = data['X'].dropna(subset=['price'])

    data = pd.concat([data[m] for m in messages], ignore_index=True, 
                      sort=False)

重建成功的交易,即作为与被取消的订单相对的订单的交易相关消息,CEPQ,相对比较简单:

def get_trades(m):
    """Combine C, E, P and Q messages into trading records"""
    trade_dict = {'executed_shares': 'shares', 'execution_price': 
                  'price'}
    cols = ['timestamp', 'executed_shares']
    trades = pd.concat([m.loc[m.type == 'E', cols + 
             ['price']].rename(columns=trade_dict),
             m.loc[m.type == 'C', cols + 
             ['execution_price']].rename(columns=trade_dict),
             m.loc[m.type == 'P', ['timestamp', 'price', 'shares']],
             m.loc[m.type == 'Q', ['timestamp', 'price', 
             'shares']].assign(cross=1),
             ], sort=False).dropna(subset=['price']).fillna(0)
    return trades.set_index('timestamp').sort_index().astype(int)

订单簿跟踪限价订单,并且买入和卖出订单的各种价格水平构成了订单簿的深度。要重建给定深度级别的订单簿,需要以下步骤:

  1. add_orders() 函数累积卖单按升序排列,买单按降序排列,以给定时间戳为基础直至达到所需的深度级别:
def add_orders(orders, buysell, nlevels):
    new_order = []
    items = sorted(orders.copy().items())
    if buysell == -1:
        items = reversed(items)  
    for i, (p, s) in enumerate(items, 1):
        new_order.append((p, s))
        if i == nlevels:
            break
    return orders, new_order
  1. 我们遍历所有 ITCH 消息,并根据规范要求处理订单及其替换:
for message in messages.itertuples():
    i = message[0]
    if np.isnan(message.buy_sell_indicator):
        continue
    message_counter.update(message.type)

    buysell = message.buy_sell_indicator
    price, shares = None, None

    if message.type in ['A', 'F', 'U']:
        price, shares = int(message.price), int(message.shares)

        current_orders[buysell].update({price: shares})
        current_orders[buysell], new_order = 
          add_orders(current_orders[buysell], buysell, nlevels)
        order_book[buysell][message.timestamp] = new_order

    if message.type in ['E', 'C', 'X', 'D', 'U']:
        if message.type == 'U':
            if not np.isnan(message.shares_replaced):
                price = int(message.price_replaced)
                shares = -int(message.shares_replaced)
        else:
            if not np.isnan(message.price):
                price = int(message.price)
                shares = -int(message.shares)

        if price is not None:
            current_orders[buysell].update({price: shares})
            if current_orders[buysell][price] <= 0:
                current_orders[buysell].pop(price)
            current_orders[buysell], new_order = 
              add_orders(current_orders[buysell], buysell, nlevels)
            order_book[buysell][message.timestamp] = new_order

不同价格水平上的订单数量,在以下截图中使用不同强度的颜色突出显示买入和卖出订单的深度流动性。左侧面板显示了限价订单价格分布偏向于更高价格的买单。右侧面板绘制了交易日内限价订单和价格的演变:深色线跟踪了市场交易小时内的执行交易价格,而红色和蓝色点表示每分钟的限价订单(详见笔记本):

规范化 tick 数据

交易数据按纳秒索引,噪音很大。例如,出现买卖市价订单交替引发的买卖跳动,导致价格在买入和卖出价格之间波动。为了提高噪声-信号比并改善统计性能,我们需要重新采样和规范化 tick 数据,通过聚合交易活动来实现。

通常,我们收集聚合期间的开盘(第一个)、最低、最高和收盘(最后)价格,以及成交量加权平均价格VWAP)、交易的股数和与数据相关的时间戳。

在此章节的 GitHub 文件夹中查看名为normalize_tick_data.ipynb的笔记本,以获取额外的细节。

Tick 柱状图

AAPL的原始 tick 价格和成交量数据的图表如下:

stock, date = 'AAPL', '20180329'
title = '{} | {}'.format(stock, pd.to_datetime(date).date()

with pd.HDFStore(itch_store) as store:
    s = store['S'].set_index('event_code') # system events
    s.timestamp = s.timestamp.add(pd.to_datetime(date)).dt.time
    market_open = s.loc['Q', 'timestamp'] 
    market_close = s.loc['M', 'timestamp']

with pd.HDFStore(stock_store) as store:
    trades = store['{}/trades'.format(stock)].reset_index()
trades = trades[trades.cross == 0] # excluding data from open/close crossings
trades.price = trades.price.mul(1e-4)

trades.price = trades.price.mul(1e-4) # format price
trades = trades[trades.cross == 0]    # exclude crossing trades
trades = trades.between_time(market_open, market_close) # market hours only

tick_bars = trades.set_index('timestamp')
tick_bars.index = tick_bars.index.time
tick_bars.price.plot(figsize=(10, 5), title=title), lw=1)

我们得到了前述代码的下列图表:

由于scipy.stats.normaltest的 p 值较低,可以看出 tick 返回远非正态分布:

from scipy.stats import normaltest
normaltest(tick_bars.price.pct_change().dropna())

NormaltestResult(statistic=62408.76562431228, pvalue=0.0)

时间柱状图

时间柱状图涉及按周期聚合交易:

def get_bar_stats(agg_trades):
    vwap = agg_trades.apply(lambda x: np.average(x.price, 
           weights=x.shares)).to_frame('vwap')
    ohlc = agg_trades.price.ohlc()
    vol = agg_trades.shares.sum().to_frame('vol')
    txn = agg_trades.shares.size().to_frame('txn')
    return pd.concat([ohlc, vwap, vol, txn], axis=1)

resampled = trades.resample('1Min')
time_bars = get_bar_stats(resampled)

我们可以将结果显示为价格-成交量图:

def price_volume(df, price='vwap', vol='vol', suptitle=title):
    fig, axes = plt.subplots(nrows=2, sharex=True, figsize=(15, 8))
    axes[0].plot(df.index, df[price])
    axes[1].bar(df.index, df[vol], width=1 / (len(df.index)), 
                color='r')

    xfmt = mpl.dates.DateFormatter('%H:%M')
    axes[1].xaxis.set_major_locator(mpl.dates.HourLocator(interval=3))
    axes[1].xaxis.set_major_formatter(xfmt)
    axes[1].get_xaxis().set_tick_params(which='major', pad=25)
    axes[0].set_title('Price', fontsize=14)
    axes[1].set_title('Volume', fontsize=14)
    fig.autofmt_xdate()
    fig.suptitle(suptitle)
    fig.tight_layout()
    plt.subplots_adjust(top=0.9)

price_volume(time_bars)

我们得到了前述代码的下列图表:

或者使用bokeh绘图库绘制蜡烛图:

resampled = trades.resample('5Min') # 5 Min bars for better print
df = get_bar_stats(resampled)

increase = df.close > df.open
decrease = df.open > df.close
w = 2.5 * 60 * 1000 # 2.5 min in ms

WIDGETS = "pan, wheel_zoom, box_zoom, reset, save"

p = figure(x_axis_type='datetime', tools=WIDGETS, plot_width=1500, title = "AAPL Candlestick")
p.xaxis.major_label_orientation = pi/4
p.grid.grid_line_alpha=0.4

p.segment(df.index, df.high, df.index, df.low, color="black")
p.vbar(df.index[increase], w, df.open[increase], df.close[increase], fill_color="#D5E1DD", line_color="black")
p.vbar(df.index[decrease], w, df.open[decrease], df.close[decrease], fill_color="#F2583E", line_color="black")
show(p)

请看以下截图:

绘制 AAPL 蜡烛图

成交量柱状图

时间柱状图平滑了原始 tick 数据中的一些噪音,但可能未能解决订单碎片化的问题。以执行为中心的算法交易可能旨在在给定期间内匹配成交量加权平均价格VWAP),并将单个订单分成多个交易,并根据历史模式下订单。时间柱状图会对相同的订单进行不同处理,即使市场没有新的信息到达。

成交量柱状图提供了一种根据成交量聚合交易数据的替代方法。我们可以按以下方式实现:

trades_per_min = trades.shares.sum()/(60*7.5) # min per trading day
trades['cumul_vol'] = trades.shares.cumsum()
df = trades.reset_index()
by_vol = 
   df.groupby(df.cumul_vol.div(trades_per_min).round().astype(int))
vol_bars = pd.concat([by_vol.timestamp.last().to_frame('timestamp'), 
                      get_bar_stats(by_vol)], axis=1)
price_volume(vol_bars.set_index('timestamp'))

我们得到了前述代码的下列图表:

美元柱状图

当资产价格发生显着变化或股票拆分后,给定数量股票的价值也会发生变化。 Volume bars 不会正确反映这一点,并且可能妨碍对反映这些变化的不同期间的交易行为进行比较。 在这些情况下,应调整 volume bar 方法,以利用股票和价格的乘积来生成美元 bars。

市场数据的 API 访问

有几种选项可以使用 Python 通过 API 访问市场数据。 我们首先介绍了内置于 pandas 库中的几个数据源。 然后,我们简要介绍了交易平台 Quantopian,数据提供商 Quandl 以及本书稍后将使用的回测库,并列出了访问各种类型市场数据的几种其他选项。 在 GitHub 上的文件夹目录 data_providers 包含了几个示例笔记本,演示了这些选项的使用方法。

使用 pandas 进行远程数据访问

pandas 库使用 read_html 函数访问网站上显示的数据,并通过相关的 pandas-datareader 库访问各种数据提供商的 API 端点。

阅读 HTML 表格

下载一个或多个 html 表格的内容的方法如下,例如从 Wikipedia 获取 S&P500 指数的成分:

sp_url = 'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies'
sp = pd.read_html(sp_url, header=0)[0] # returns a list for each table
sp.info()

RangeIndex: 505 entries, 0 to 504
Data columns (total 9 columns):
Ticker symbol             505 non-null object
Security                  505 non-null object
SEC filings               505 non-null object
GICS Sector               505 non-null object
GICS Sub Industry         505 non-null object
Location                  505 non-null object
Date first added[3][4]    398 non-null object
CIK                       505 non-null int64
Founded                   139 non-null object

用于市场数据的 pandas-datareader

pandas 曾用于直接便捷访问数据提供商的 API,但该功能已迁移到相关的 pandas-datareader 库。 API 的稳定性因提供商政策而异,在 2018 年 6 月的版本 0.7 中,以下数据源可用:

来源范围注释
Yahoo! Finance股票和外汇对的 EOD 价格、分红、拆分数据不稳定
Tiingo股票、共同基金和交易所交易基金的 EOD 价格需要免费注册
投资者交易所IEX历史股票价格,订单簿数据限制为五年
RobinhoodEOD 股票价格限制为一年
Quandl各种资产价格的市场高级数据需要订阅
纳斯达克最新在纳斯达克交易的股票代码以及一些额外信息
Stooq一些股票市场指数数据
MOEX莫斯科证券交易所数据
Alpha VantageEOD 股票价格和外汇对
Fama/French来自 FF 数据库的因子收益和研究组合

访问和检索数据的方式对所有数据源都是相似的,如 Yahoo! Finance 所示:

import pandas_datareader.data as web
from datetime import datetime

start = '2014'              # accepts strings
end = datetime(2017, 5, 24) # or datetime objects

yahoo= web.DataReader('FB', 'yahoo', start=start, end=end)
yahoo.info()

DatetimeIndex: 856 entries, 2014-01-02 to 2017-05-25
Data columns (total 6 columns):
High         856 non-null float64
Low          856 non-null float64
Open         856 non-null float64
Close        856 non-null float64
Volume       856 non-null int64
Adj Close    856 non-null float64

dtypes: float64(5), int64(1)

投资者交易所

IEX 是作为对高频交易争议的回应而启动的另一种交易所,出现在迈克尔·刘易斯有争议的《闪 Boys》中。 它旨在减缓交易速度,创造一个更公平的竞争环境,并自 2016 年推出以来一直在迅速增长,但在 2018 年 6 月仍然很小,市场份额约为 2.5%。

除了历史结束日价格和成交量数据外,IEX 还提供实时的订单簿深度报价,通过价格和方向聚合订单的规模。该服务还包括最后成交价和规模信息:

book = web.get_iex_book('AAPL')
orders = pd.concat([pd.DataFrame(book[side]).assign(side=side) for side in ['bids', 'asks']])
orders.sort_values('timestamp').head()

  price  size timestamp      side
4 140.00  100  1528983003604 bids
3 175.30  100  1528983900163 bids
3 205.80  100  1528983900163 asks
1 187.00  200  1528996876005 bids
2 186.29  100  1528997296755 bids

datareader.ipynb笔记本中查看更多示例。

Quantopian

Quantopian 是一家投资公司,提供一个研究平台来集体开发交易算法。免费注册后,它使会员能够使用各种数据源研究交易想法。它还提供了一个环境,用于对算法进行历史数据的回测,以及使用实时数据进行样本外测试。对于表现最佳的算法,它授予投资额度,其作者有权获得 10%的利润份额(在撰写本文时)。

Quantopian 研究平台包括用于 Alpha 因子研究和绩效分析的 Jupyter Notebook 环境。还有一个用于编写算法策略和使用自 2002 年以来带有分钟柱频率的历史数据回测结果的交互式开发环境IDE)。

用户还可以使用实时数据模拟算法,这称为纸上交易。Quantopian 提供各种市场数据集,包括美国股票和期货价格和成交量数据,频率为一分钟,以及美国股票公司基本面数据,并集成了众多替代数据集。

我们将在第四章中更详细地介绍 Quantopian 平台,Alpha 因子研究并且在整本书中依赖其功能,所以随时打开一个账户(有关更多详细信息,请参阅 GitHub repo)。

Zipline

Zipline 是算法交易库,为 Quantopian 回测和实时交易平台提供支持。它也可以离线使用,使用有限数量的免费数据包来开发策略,这些数据包可以被摄取并用于测试交易想法的表现,然后将结果转移到在线 Quantopian 平台进行纸上和实时交易。

以下代码说明了zipline允许我们访问一系列公司的每日股票数据。您可以在 Jupyter Notebook 中使用相同名称的魔术函数运行zipline脚本。

首先,您需要使用所需的安全符号初始化上下文。我们还将使用一个计数器变量。然后zipline调用handle_data,在其中我们使用data.history()方法回顾一个单一周期,并将上一天的数据附加到.csv文件中:

%load_ext zipline
%%zipline --start 2010-1-1 --end 2018-1-1 --data-frequency daily
from zipline.api import order_target, record, symbol

def initialize(context):
 context.i = 0
 context.assets = [symbol('FB'), symbol('GOOG'), symbol('AMZN')]

def handle_data(context, data):
 df = data.history(context.assets, fields=['price', 'volume'], 
                   bar_count=1, frequency="1d")
 df = df.to_frame().reset_index()

 if context.i == 0:
 df.columns = ['date', 'asset', 'price', 'volumne']
 df.to_csv('stock_data.csv', index=False)
 else:
     df.to_csv('stock_data.csv', index=False, mode='a', header=None)
                context.i += 1

df = pd.read_csv('stock_data.csv')
df.date = pd.to_datetime(df.date)
df.set_index('date').groupby('asset').price.plot(lw=2, legend=True, 
       figsize=(14, 6));

我们得到了上述代码的下列图表:

我们将在接下来的章节中更详细地探讨zipline的功能,特别是在线 Quantopian 平台。

Quandl

Quandl 提供广泛的数据来源,包括免费和订阅,使用 Python API。注册并获取免费 API 密钥,以进行 50 次以上的调用。Quandl 数据涵盖除股票外的多种资产类别,包括外汇、固定收益、指数、期货和期权以及商品。

API 的使用简单直观,文档完善,灵活性强,除了单个数据系列下载外,还有许多其他方法,例如批量下载或元数据搜索。以下调用获取了自 1986 年以来由美国能源部报价的石油价格:

import quandl
oil = quandl.get('EIA/PET_RWTC_D').squeeze()
oil.plot(lw=2, title='WTI Crude Oil Price')

我们通过前述代码得到了这个图表:

其他市场数据提供商

各种各样的提供商为各种资产类别提供市场数据。相关类别中的示例包括:

  • 交易所从数据服务中获得越来越广泛的收入,通常使用订阅方式。

  • 彭博和汤姆森路透一直是领先的数据聚合商,在 285 亿美元的金融数据市场中占有超过 55%的份额。较小的竞争对手,如 FactSet,正在增长,或者新兴的,如 money.net 和 Quandl 以及 Trading Economics 或 Barchart.

  • 专业数据提供商层出不穷。LOBSTER 就是一个例子,它实时聚合纳斯达克订单簿数据。

  • 免费数据提供商包括 Alpha Vantage,该公司提供 Python API 用于实时股票、外汇和加密货币市场数据,以及技术指标。

  • 提供数据访问的众包投资公司包括 Quantopian 以及于 2018 年 3 月推出的 Alpha Trading Labs,它们提供 HFT 基础设施和数据。

如何处理基本数据

基本数据涉及确定证券价值的经济驱动因素。数据的性质取决于资产类别:

  • 对于股票和公司信用,它包括公司财务数据以及行业和全球范围的数据。

  • 对于政府债券,它包括国际宏观数据和外汇。

  • 对于商品,它包括特定资产的供需决定因素,例如作物的天气数据。

我们将重点关注美国的股票基本面,因为数据更容易获取。全球有约 13,000 多家上市公司,每年产生 2 百万页的年度报告和 3 万多小时的收益电话。在算法交易中,基本数据和从这些数据中衍生的特征可能被直接用于推导交易信号,例如作为价值指标,并且是预测模型(包括机器学习模型)的重要输入。

财务报表数据

证券交易委员会SEC)要求美国发行人,即上市公司和证券,包括共同基金,提交三份季度财务报表(表格 10-Q)和一份年度报告(表格 10-K),以及其他各种监管文件要求。

自 20 世纪 90 年代初,美国证券交易委员会通过其电子数据收集、分析和检索EDGAR)系统提供这些报告。它们构成了股权和其他证券基本分析的主要数据来源,例如企业信用,其价值取决于发行者的业务前景和财务状况。

自动处理 – XBRL

自从 SEC 引入了 XBRL 以来,对监管提交的自动分析变得更加容易,XBRL 是一种免费、开放和全球标准,用于电子报告的表示和交换。XBRL 基于 XML;它依赖于定义报告元素含义的分类法,并映射到在报告的电子版本中突出显示相应信息的标签。其中一种分类法代表了美国普遍公认的会计准则GAAP)。

为了应对会计丑闻,SEC 于 2005 年引入了自愿的 XBRL 提交,之后从 2009 年开始要求所有提交者使用此格式,并继续将强制覆盖范围扩展到其他监管提交。SEC 维护一个网站,列出了塑造不同提交内容的当前分类法,并可用于提取特定项目。

以下数据集提供了从提交给委员会的 EX-101 附件中提取的信息,以扁平化数据格式提供,以帮助用户消化数据进行分析。数据反映了 XBRL 标记的财务报表的选定信息。目前,它包括季度和年度财务报表的数字数据,以及某些额外字段(例如标准工业分类SIC))。

有几种途径可跟踪和访问向 SEC 报告的基本数据:

  • 作为 EDGAR 公共 传播服务PDS)的一部分,接受的提交的电子订阅需要付费。

  • SEC 每 10 分钟更新一次RSS订阅,其中列出了结构化披露提交。

  • 有用于通过 FTP 检索所有提交的公共索引文件,以进行自动处理。

  • 财务报表(和附注)数据集包含了来自所有财务报表和相关附注的解析 XBRL 数据。

SEC 还发布了包含通过 SEC.gov 提交的 EDGAR 提交的互联网搜索流量的日志文件,尽管有六个月的延迟。

建立基本数据时间序列

财务报表和附注数据集中的数据范围包括从主要财务报表(资产负债表、利润表、现金流量表、权益变动表和全面收益表)和这些报表的附注中提取的数字数据。该数据最早可追溯至 2009 年。

提取财务报表和附注数据集

以下代码下载并提取了给定季度范围内财务报表和附注FSN)数据集中包含的所有历史提交(有关更多详细信息,请参阅edgar_xbrl.ipynb):

SEC_URL = 'https://www.sec.gov/files/dera/data/financial-statement-and-notes-data-sets/'

first_year, this_year, this_quarter = 2014, 2018, 3
past_years = range(2014, this_year)
filing_periods = [(y, q) for y in past_years for q in range(1, 5)]
filing_periods.extend([(this_year, q) for q in range(1, this_quarter + 
                                                     1)])
for i, (yr, qtr) in enumerate(filing_periods, 1):
    filing = f'{yr}q{qtr}_notes.zip'
    path = data_path / f'{yr}_{qtr}' / 'source'
    response = requests.get(SEC_URL + filing).content
    with ZipFile(BytesIO(response)) as zip_file:
        for file in zip_file.namelist():
            local_file = path / file
            with local_file.open('wb') as output:
                for line in zip_file.open(file).readlines():
                    output.write(line)

数据相当庞大,为了实现比原始文本文件更快的访问,最好将文本文件转换为二进制、列式 parquet 格式(请参见本章中关于与 pandas DataFrames兼容的各种数据存储选项的性能比较的使用 pandas 进行高效数据存储一节):

for f in data_path.glob('**/*.tsv'):
    file_name = f.stem  + '.parquet'
    path = Path(f.parents[1]) / 'parquet'
    df = pd.read_csv(f, sep='\t', encoding='latin1', low_memory=False)
    df.to_parquet(path / file_name)

对于每个季度,FSN 数据组织成包含有关提交、数字、税项标签、演示等信息的八个文件集。每个数据集由行和字段组成,并以制表符分隔的文本文件形式提供:

文件数据集描述
SUB提交根据公司、表格、日期等识别每个 XBRL 提交
TAG标签定义和解释每个税项标签
DIM尺寸对数字和纯文本数据进行详细描述
NUM数字每个备案中每个不同数据点的一行
TXT纯文本包含所有非数字 XBRL 字段
REN渲染在 SEC 网站上呈现的信息
PRE展示主要报表中标签和数字展示的详细信息
CAL计算显示标签之间的算术关系

检索所有季度苹果备案

提交数据集包含检索备案所需的唯一标识符:中央索引键CIK)和接入号(adsh)。以下显示了有关苹果 2018Q1 10-Q 备案的一些信息:

apple = sub[sub.name == 'APPLE INC'].T.dropna().squeeze()
key_cols = ['name', 'adsh', 'cik', 'name', 'sic', 'countryba',  
            'stprba', 'cityba', 'zipba', 'bas1', 'form', 'period', 
            'fy', 'fp', 'filed']
apple.loc[key_cols]

name                    APPLE INC
adsh                    0000320193-18-000070
cik                     320193
name                    APPLE INC
sic                     3571
countryba               US
stprba                  CA
cityba                  CUPERTINO
zipba                   95014
bas1                    ONE APPLE PARK WAY
form                    10-Q
period                  20180331
fy                      2018
fp                      Q2
filed                   20180502

使用中央索引键,我们可以识别出适用于Apple的所有历史季度备案,并将此信息结合起来获得 26 份10-Q表格和 9 份年度10-K表格:

aapl_subs = pd.DataFrame()
for sub in data_path.glob('**/sub.parquet'):
    sub = pd.read_parquet(sub)
    aapl_sub = sub[(sub.cik.astype(int) == apple.cik) & (sub.form.isin(['10-Q', '10-K']))]
    aapl_subs = pd.concat([aapl_subs, aapl_sub])

aapl_subs.form.value_counts()
10-Q    15
10-K     4

有了每个备案的接入号,我们现在可以依靠税项分类来从NUMTXT文件中选择适当的 XBRL 标签(在TAG文件中列出)以获取感兴趣的数字或文本/脚注数据点。

首先,让我们从 19 份苹果备案中提取所有可用的数字数据:

aapl_nums = pd.DataFrame()
for num in data_path.glob('**/num.parquet'):
    num = pd.read_parquet(num)
    aapl_num = num[num.adsh.isin(aapl_subs.adsh)]
    aapl_nums = pd.concat([aapl_nums, aapl_num])

aapl_nums.ddate = pd.to_datetime(aapl_nums.ddate, format='%Y%m%d')    
aapl_nums.shape
(28281, 16)

建立一个价格/收益时间序列

总共,九年的备案历史为我们提供了超过 28,000 个数字值。我们可以选择一个有用的字段,例如每股稀释收益EPS),将其与市场数据结合起来计算流行的市盈率P/E)估值比率。

但是,我们需要考虑到,苹果于 2014 年 6 月 4 日进行了 7:1 的股票分割,并且调整了分割前的每股收益,以使收益可比,如下图所示:

field = 'EarningsPerShareDiluted'
stock_split = 7
split_date = pd.to_datetime('20140604')

# Filter by tag; keep only values measuring 1 quarter
eps = aapl_nums[(aapl_nums.tag == 'EarningsPerShareDiluted')
                & (aapl_nums.qtrs == 1)].drop('tag', axis=1)

# Keep only most recent data point from each filing
eps = eps.groupby('adsh').apply(lambda x: x.nlargest(n=1, columns=['ddate']))

# Adjust earnings prior to stock split downward
eps.loc[eps.ddate < split_date,'value'] = eps.loc[eps.ddate < 
        split_date, 'value'].div(7)
eps = eps[['ddate', 'value']].set_index('ddate').squeeze()
eps = eps.rolling(4, min_periods=4).sum().dropna() # create trailing 
                  12-months eps from quarterly data

我们可以使用 Quandl 来获取自 2009 年以来的苹果股价数据:

import pandas_datareader.data as web
symbol = 'AAPL.US'
aapl_stock = web.DataReader(symbol, 'quandl', start=eps.index.min())
aapl_stock = aapl_stock.resample('D').last() # ensure dates align with 
                                               eps data

现在我们有了数据来计算整个期间的滚动 12 个月 P/E 比率:

pe = aapl_stock.AdjClose.to_frame('price').join(eps.to_frame('eps'))
pe = pe.fillna(method='ffill').dropna()
pe['P/E Ratio'] = pe.price.div(pe.eps)
axes = pe.plot(subplots=True, figsize=(16,8), legend=False, lw=2);

对于前述代码,我们得到了以下的绘图:

其他基本数据来源

还有许多其他的基础数据来源。许多可通过早期介绍的pandas_datareader模块访问。还有其他数据可以直接从某些组织获得,例如 IMF、世界银行或世界各地的主要国家统计机构(请参阅 GitHub 上的参考文献)。

pandas_datareader – 宏观和行业数据

pandas_datareader库根据上一节市场数据末尾介绍的约定简化了访问。它覆盖了许多全球基础宏观和行业数据源的 API,包括以下内容:

  • 肯尼斯·弗伦奇的数据库:捕捉规模、价值和动量因素、分解行业的投资组合的市场数据

  • 圣路易斯联邦储备银行(FRED):美国经济和金融市场的联邦储备数据

  • 世界银行:长期、低频经济和社会发展以及人口统计数据库

  • 经济合作与发展组织(OECD):类似于 OECD 国家

  • Enigma:各种数据集,包括替代来源

  • Eurostat:欧盟经济、社会和人口统计数据

用 pandas 进行高效的数据存储

在本书中我们将使用许多不同的数据集,值得比较主要格式的效率和性能。特别是,我们比较以下内容:

  • CSV: 逗号分隔,标准的纯文本文件格式。

  • HDF5:分层数据格式,最初在国家超级计算中心开发,是一种用于数值数据的快速可扩展的存储格式,可以使用PyTables库在 pandas 中使用。

  • Parquet: 二进制的,列式存储格式,是 Apache Hadoop 生态系统的一部分,提供了高效的数据压缩和编码,并由 Cloudera 和 Twitter 开发。通过由 pandas 的原始作者 Wes McKinney 领导的pyarrow库可用于 pandas。

storage_benchmark.ipynb笔记本使用一个可配置为包含数值数据、文本数据或两者的测试DataFrame来比较上述库的性能。对于HDF5库,我们测试fixedtable格式。table格式允许查询并且可以追加。

以下图表说明了具有随机浮点数的 100,000 行和 1000 个随机 10 个字符字符串列或仅有 2,000 个浮点列的 100,000 行的读写性能:

  • 对于纯数值数据,HDF5 格式性能最佳,并且表格式与 CSV 共享 1.6 GB 的最小内存占用。固定格式使用了两倍的空间,parquet 格式使用了 2 GB。

  • 对于数字和文本数据的混合,parquet显着更快,而 HDF5 则利用其相对于 CSV 的读取优势(在两种情况下写入性能都很低):

该笔记本演示了如何使用%%timeit单元格魔法配置、测试和收集时间,并同时演示了使用相关的 pandas 命令来使用这些存储格式所需的用法。

总结

本章介绍了构成大多数交易策略骨干的市场和基本数据来源。您了解了访问这些数据的多种方式,以及如何预处理原始信息,以便您可以开始使用我们即将介绍的机器学习技术提取交易信号。

在我们进入交易策略的设计和评估以及使用 ML 模型之前,我们需要涵盖近年来出现的替代数据集,这些数据集对算法交易的 ML 流行程度有着重要推动作用。

第三章:金融领域的替代数据

在互联网和移动网络的爆炸性增长推动下,数字数据在新数据源的处理、存储和分析技术进步的同时呈指数级增长。数字数据的可用性和管理能力的指数级增长,反过来又成为驱动创新的机器学习(ML)在包括投资行业在内的各行业的戏剧性性能提升背后的关键力量。

数据革命的规模是非凡的:仅过去两年就创造了今天世界上所有数据的 90%,到 2020 年,全球 77 亿人口预计每天每秒产生 1.7 MB 的新信息。另一方面,回到 2012 年,仅有 0.5% 的数据被分析和使用,而到 2020 年,有 33% 被认为具有价值。随着全球对分析的投资预计将于 2020 年超过 2100 亿美元,价值创造潜力将倍增,数据的可用性和使用之间的差距可能会迅速缩小。

本章解释了个人、业务流程和传感器如何产生替代数据。它还提供了一个框架,用于为投资目的导航和评估不断增长的替代数据供应。它演示了工作流程,从获取到预处理和使用 Python 存储通过网络抓取获得的数据,为 ML 应用铺平了道路。最后,它通过提供来源、供应商和应用程序的示例来结束。

本章将涵盖以下主题:

  • 替代数据革命如何释放新的信息来源

  • 个人、业务流程和传感器如何生成替代数据

  • 如何评估用于算法交易的不断增长的替代数据供应

  • 如何在 Python 中处理替代数据,例如通过抓取互联网

  • 替代数据的重要类别和提供商

替代数据革命

由数字化、网络化和存储成本的暴跌驱动的数据洪流已经导致可用于预测分析的信息性质发生了深刻的定性变化,通常由五个 V 总结:

  • 容量:由在线和离线活动、交易、记录和其他来源产生、收集和存储的数据量是数量级更大的副产品,随着分析和存储能力的增长,这些来源和数量也在不断增加。

  • 速度:数据生成、传输和处理以接近实时的速度变得可用。

  • 多样性:数据的组织格式不再局限于结构化、表格形式,如 CSV 文件或关系数据库表。相反,新的来源产生半结构化格式,如 JSON 或 HTML,以及非结构化内容,包括原始文本、图像和音频或视频数据,为使数据适用于机器学习算法增加了新的挑战。

  • 真实性:来源和格式的多样性使得验证数据信息内容的可靠性变得更加困难。

  • 价值:确定新数据集的价值可能会比以往更加耗时和耗资源,并且更加不确定。

对于算法交易而言,如果新数据来源提供了无法从传统来源获取的信息,或者提供了更早的获取机会,则它们将提供信息优势。随着全球趋势,投资行业正迅速扩展到超越市场和基本数据的替代来源,以通过信息优势实现阿尔法。数据、技术能力和相关人才的年度支出预计将从当前的 30 亿美元以每年 12.8%的速度增加到 2020 年。

如今,投资者可以实时获取宏观或公司特定的数据,而这些数据在历史上只能以更低的频率获得。新数据来源的用例包括以下内容:

  • 代表性商品和服务的在线价格数据可用于衡量通货膨胀

  • 商店访问或购买次数可以允许对公司或行业特定销售或经济活动进行实时估计

  • 卫星图像可以揭示农业产量,或者矿山或石油钻井平台上的活动,而这些信息在其他地方得到之前是不可用的

随着大数据集的标准化和采用的推进,传统数据中包含的信息可能会失去大部分预测价值。

此外,处理和整合多样化数据并应用机器学习的能力允许获得复杂的见解。过去,定量方法依赖于简单的启发式方法来使用历史数据对公司进行排名,例如按照价格/账面价值比进行排名,而机器学习算法则综合新指标,并学习和适应这些规则,考虑到市场数据的演变。这些见解创造了捕捉经典投资主题的新机会,如价值、动量、质量或情绪:

  • 动量:机器学习可以识别资产暴露于市场价格波动、行业情绪或经济因素

  • 价值:算法可以分析大量经济和行业特定的结构化和非结构化数据,超越财务报表,以预测公司的内在价值

  • 质量:集成数据的复杂分析使得能够评估顾客或员工评论、电子商务或应用流量,以确定市场份额或其他基本收益质量驱动因素的增益

然而,在实践中,有用的数据通常不是免费提供的,而是需要进行彻底的评估、昂贵的获取、谨慎的管理和复杂的分析才能提取可交易的信号。

替代数据的来源

替代数据由许多来源生成,但可以在高层次上分类为主要由以下来源产生的:

  • 在社交媒体上发布帖子、评论产品或使用搜索引擎的个人

  • 记录商业交易的企业,特别是信用卡支付,或作为中间商捕获供应链活动

  • 传感器,它们除了其他功能外,通过诸如卫星或安全摄像头的图像或通过诸如手机基站的移动模式捕获经济活动

替代数据的性质继续迅速发展,因为新的数据来源变得可用,而以前标记为替代的来源成为主流的一部分。例如,波罗的海干散货运价指数BDI),现在通过 Bloomberg 终端可用,汇集了数百家航运公司的数据以近似干散货运输船的供需情况。

替代数据包括原始数据以及已汇总或以某种形式加工以增加价值的数据。例如,一些提供商旨在提取可交易的信号,如情绪分数。我们将在第四章,Alpha 因子研究中讨论各种类型的提供商。

替代数据来源在关键方面有所不同,这些方面决定了它们对算法交易策略的价值或信号内容。我们将在下一节关于评估替代数据集中讨论这些方面。

个人

个人通过在线活动以及离线活动而自动生成电子数据,因为后者被电子捕获并经常与在线身份关联。由个人生成的数据通常是文本、图像或视频格式的非结构化数据,通过多个平台传播,包括:

  • 社交媒体帖子,例如在 Twitter、Facebook 或 LinkedIn 等综合性网站上的意见或反应,或在 Glassdoor 或 Yelp 等商业评论网站上

  • 在网站上反映对产品的兴趣或感知的电子商务活动,例如 Amazon 或 Wayfair

  • 利用诸如 Google 或 Bing 之类的平台的搜索引擎活动

  • 移动应用程序的使用情况、下载量和评论

  • 个人数据,如消息流量

社交媒体情感分析变得非常流行,因为它可以应用于个别股票、行业篮子或市场指数。最常见的来源是 Twitter,其次是各种新闻供应商和博客网站。由于通常是通过日益商品化的网络抓取获得,供应是竞争性的,价格更低。可靠的社交媒体数据集通常包括博客、推文或视频,在大规模消费者最近采用这些工具的情况下,历史不足五年。相比之下,搜索历史可追溯至 2004 年。

业务流程

企业和公共实体生产和收集许多有价值的替代数据来源。由业务流程产生的数据通常比个人生成的数据更有结构。它非常有效地作为活动的领先指标,这种活动通常以更低的频率可用。

由业务流程产生的数据包括:

  • 由处理器和金融机构提供的支付卡交易数据

  • 公司排放的数据由普通数字化活动或记录生成,例如银行记录、收银机扫描数据或供应链订单

  • 贸易流动和市场微观结构数据(如 L-2 和 L-3 订单簿数据,在第二章中有图示,市场与基本数据

  • 由信用评级机构或金融机构监测的公司支付,以评估流动性和信用状况

信用卡交易和公司排放数据,如销售点数据,是最可靠和最具预测性的数据集之一。信用卡数据的历史可追溯到约十年前,并且在不同的滞后期几乎可以实时获得,而公司盈利报告的滞后期为 2.5 周。公司排放数据的时间范围和报告滞后期因来源而异。市场微观结构数据的历史超过 15 年,而与之相比,销售方流量数据通常只有不到五年的一致历史。

传感器

嵌入在广泛范围设备中的网络传感器生成的数据是增长最快的数据来源之一,其增长受到智能手机普及和卫星技术成本降低的推动。

这一类替代数据通常非常无结构,通常比个人或业务流程生成的数据体积大得多,并且具有更高的处理挑战。该类别中的关键替代数据来源包括:

  • 卫星成像用于监测经济活动,例如建筑、航运或商品供应

  • 用于跟踪零售店铺交通的地理位置数据,例如使用志愿者智能手机数据,或者在运输路线上,例如在船只或卡车上

  • 在感兴趣的位置设置摄像头

  • 天气和污染传感器

**物联网(IoT)**将通过将网络微处理器嵌入个人和商业电子设备,如家用电器、公共空间和工业生产过程,进一步加速这类替代数据的大规模收集。

基于传感器的替代数据包括卫星图像、移动应用程序使用情况或蜂窝位置跟踪,通常具有三到四年的历史。

卫星

发射地理空间成像卫星所需的资源和时间表已经大幅降低;成本从数千万美元和数年的准备时间降至约 10 万美元,将小型卫星作为低地球轨道的辅助有效载荷发射。因此,公司可以使用整个卫星机队获得对特定位置的更高频率覆盖(目前约每天一次)。

应用案例包括监测经济和商业活动,可以通过航拍覆盖范围捕捉到,例如农业和矿产生产和货运、房地产或船舶的建造、工业事故如火灾,或位置感兴趣处的汽车和人流量。相关的传感器数据由用红外线光监视农作物的农业无人机贡献。

在卫星图像数据能够可靠用于 ML 模型之前,可能需要解决一些挑战。这些挑战包括考虑天气条件,特别是云层覆盖和季节效应,节假日期间,以及可能影响预测信号质量的特定位置的不规则覆盖。

地理位置数据

地理位置数据是传感器产生的另一类迅速增长的替代数据。一个熟悉的来源是智能手机,个人通过应用程序或 GPS、CDMA 或 WiFi 等无线信号自愿共享他们的地理位置,以测量周围地点(如商店、餐厅或活动场所)的人流量。

此外,越来越多的机场、购物中心和零售店安装了传感器,跟踪顾客的数量和移动。尽管最初部署这些传感器的动机通常是为了衡量营销活动的影响,但由此产生的数据也可以用于估算人流量或销售情况。用于捕捉地理位置的传感器包括 3D 立体视频和热成像,这降低了隐私顾虑,但对移动对象效果很好。还有安装在天花板上的传感器,以及压力敏感的垫子。一些供应商结合使用多个传感器,包括视觉、音频和手机定位,全面了解购物者的旅程,这不仅包括访问次数和时长,还延伸到转化和重复访问的测量。

评估替代数据集

替代数据的最终目标是在寻找产生 alpha 的交易信号的竞争中提供信息优势,即正的、不相关的投资回报。在实践中,从替代数据集中提取的信号可以作为独立基础使用,也可以作为定量策略的一部分与其他信号组合使用。如果基于单一数据集的策略产生的夏普比率足够高,独立使用是可行的,但在实践中很少见(有关信号测量和评估的详细信息,请参阅 第四章 Alpha 因子研究)。

量化公司正在建立可以单独是弱信号但组合后可能产生吸引人回报的 alpha 因子库。正如 第一章 用于交易的机器学习 中所强调的,投资因素应基于基本的经济理念,否则,它们更可能是对历史数据过拟合的结果,而不是对新数据持续产生 alpha 的结果。

由于竞争导致的信号衰减是一个严重问题,随着替代数据生态系统的发展,很少有数据集将保留有意义的夏普比率信号。延长替代数据集信号内容的半衰期的有效策略包括独家协议或专注于提高处理挑战以提高进入门槛的数据集。

评估标准

可以基于其信号内容的质量、数据的定性方面以及各种技术方面来评估替代数据集。

信号内容的质量

信号内容可以根据目标资产类别、投资风格、与传统风险溢价的关系以及最重要的,其 alpha 内容来评估。

资产类别

大多数替代数据集包含与股票和商品直接相关的信息。自 2006 年 Zillow 成功地开创了价格估算以后,针对房地产投资的有趣数据集也在增加。

随着用于监测企业支付的替代来源的发展,包括针对中小企业的,企业信用的替代数据正在增长。围绕固定收益和利率预测的替代数据是一个较新的现象,但随着更多的产品销售和价格信息被大规模地获取,它还在增加。

投资风格

大多数数据集关注特定行业和股票,因此自然吸引长短股权投资者。随着替代数据收集的规模和范围不断扩大,替代数据可能也会变得与宏观主题的投资者相关,例如消费信贷、新兴市场的活动和商品趋势。

一些替代数据可用作市场风险传统度量的代理,而其他信号则更相关于使用量化策略的高频交易者,这些策略在短期内进行。

风险溢价

一些替代数据集,如信用卡支付或社交媒体情绪,已被证明产生的信号与传统股票市场的风险溢价(如价值、动量和波动性质量)之间的相关性较低(低于 5%)。因此,将来自这类替代数据的信号与基于传统风险因素的算法交易策略结合起来,可以成为更多元化的风险溢价投资组合的重要组成部分。

Alpha 内容和质量

正当投资于替代数据集所需的信号强度自然取决于其成本,而替代数据的价格差异很大。评分社交情绪的数据可以以几千美元或更少的价格获得,而涵盖全面和及时的信用卡支付的数据则可能每年成本数百万美元。

我们将详细探讨如何使用历史数据,即所谓的回测,评估由替代数据驱动的交易策略,以估计数据集中包含的 Alpha 量。在个别情况下,一个数据集可能包含足够的 Alpha 信号来驱动一个独立的策略,但更典型的是结合各种替代和其他数据源的使用。在这些情况下,一个数据集允许提取出产生小正夏普比率的弱信号,这些信号在自身上不会获得资本分配,但当与类似的其他信号集成时可以提供投资组合级别的策略。然而,并不保证这一点,因为也有许多替代数据集不包含任何 Alpha 内容。

除了评估数据集的 Alpha 内容之外,还重要评估信号的增量或正交程度,即唯一于一个数据集还是已被其他数据捕获,在后一种情况下比较这种类型信号的成本。

最后,评估依赖于给定数据的策略的潜在容量是至关重要的,即可以分配的资本量而不会损害其成功,因为容量限制会使数据成本的回收变得更加困难。

数据的质量

数据集的质量是另一个重要的标准,因为它影响分析和货币化所需的工作量,以及它包含的预测信号的可靠性。质量方面包括数据频率和其可用历史长度、其所含信息的可靠性或准确性、它是否符合当前或潜在未来的法规,以及其使用的独家性。

法律和声誉风险

使用替代数据可能带有法律或声誉风险,特别是当它们包括以下项目时:

  • 重要非公开信息MNPI),因为它意味着侵犯了内幕交易法规

  • 个人身份信息PII),主要因为欧盟已经颁布了通用数据保护条例GDPR

因此,法律和合规要求需要彻底审查。当数据提供者也是积极基于数据集进行交易的市场参与者时,也可能存在利益冲突。

排他性

替代数据集包含的信号是否足够预测,能够在一段有意义的时间内以高夏普比率单独驱动策略的可能性与其可用性和处理的便利性成反比。换句话说,数据越独占,处理难度越大,数据越有可能具有阿尔法内容,而不会遭受快速信号衰减的影响。

提供标准财务比率的公共基本数据包含很少的阿尔法,不适合独立策略,但可能有助于多样化风险因素的投资组合。大型复杂数据集需要更长的时间被市场吸收,并且新数据集继续频繁出现。因此,评估其他投资者对数据集的熟悉程度以及提供商是否是此类信息的最佳来源至关重要。

当企业开始销售其为其他目的生成的废弃数据时,排他性或成为新数据集的早期采用者可能会带来额外的好处,因为可能可以影响数据的收集或策划方式,或者协商限制竞争对手访问的条件,至少在一定时间段内。

时间范围

对于在不同情景下测试数据集的预测能力而言,更广泛的历史记录非常理想。可用性在几个月到几十年之间变化很大,并且对基于数据构建和测试的交易策略的范围有重要影响。我们在介绍主要来源的主要类型时提到了一些不同数据集的时间范围。

频率

数据的频率决定了新信息多久可用一次以及在给定时期内预测信号可以多么差异化。它还影响投资策略的时间范围,范围从每日,到每周,甚至更低的频率。

可靠性

当然,数据准确反映其意图的程度以及这可以得到多好的验证是非常重要的关注点,并且应通过彻底的审计进行验证。这适用于原始数据和处理过的数据,其中提取或聚合信息的方法需要进行分析,考虑到提议收购的成本效益比。

技术方面

技术方面关注报告的延迟或延迟以及数据提供的格式。

延迟

数据提供商通常提供批量资源,延迟可能来自数据的收集方式、后续处理和传输,以及法规或法律约束。

格式

数据的可用格式范围广泛,取决于来源。处理后的数据将以用户友好的格式提供,并可通过强大的 API 轻松集成到现有系统或查询中。另一方面,体积庞大的数据源,如视频、音频或图像数据,或专有格式,需要更多的技能来准备分析,但也为潜在竞争者提供了更高的准入壁垒。

替代数据市场

投资行业预计在 2018 年将花费约 2,000,000,000-3,000,000,000 美元用于数据服务,预计这一数字将与其他行业保持两位数的增长。这些支出包括替代数据的获取、相关技术的投资以及合格人才的聘用。

安永的一项调查显示,2017 年替代数据的使用得到了广泛的应用;例如,有 43%的基金使用了网络抓取的数据,几乎 30%的基金正在尝试卫星数据。根据迄今为止的经验,基金经理认为网络抓取的数据和信用卡数据最具洞察力,而地理定位和卫星数据约 25%的人认为不够信息丰富:

反映这个新兴行业的快速增长,替代数据提供商市场相当分散。根据摩根大通的数据,有超过 500 家专业数据公司,而AlternativeData.org列出了 300 多家。供应商扮演着多种角色,包括咨询公司、数据聚合商和技术解决方案;卖方支持以各种格式提供数据,从原始数据到半加工数据或从一个或多个来源提取的信号形式。

我们将重点介绍主要类别的规模,并概述一些突出的例子,以说明它们的多样性。

数据提供商和使用案例

AlternativeData.org(由供应商 Yipit 支持)列出了几个类别,可以作为各种数据提供商领域活动的大致代理。社交情绪分析是迄今为止最大的类别,而卫星和地理定位数据近年来增长迅速:

产品类别供应商数量目标
社交情绪48原始或加工后的社交媒体数据;短期趋势
卫星26中期经济活动的航拍监测
地理定位22追踪零售、商业地产或活动人流量
网络数据和流量22监控搜索兴趣、品牌流行度和事件
信用卡和借记卡使用情况14追踪短期消费者支出和企业收入
应用使用情况7监控应用销售或收集二手数据
电子邮件和消费者收据6通过连锁店、品牌、行业或地理位置跟踪消费者支出
天气4与作物和商品相关的长期趋势
其他87

以下简要示例旨在说明服务提供商的广泛范围和潜在用例。

社会情感数据

社会情感分析与 Twitter 数据最密切相关。Gnip 是一个早期的社交媒体聚合器,通过 API 从许多网站提供数据,并于 2014 年以 1.34 亿美元的价格被 Twitter 收购。搜索引擎是另一个来源,当研究人员发表在《自然》杂志上时,基于 Google Trends 的投资策略(例如债务)可以用于一个较长时期的有利交易策略时,它变得显著(参见 GitHub repo github.com/PacktPublishing/Hands-On-Machine-Learning-for-Algorithmic-Trading 的参考资料)。

Dataminr

Dataminr 成立于 2009 年,根据与 Twitter 的独家协议提供社会情感和新闻分析。该公司是较大的替代性提供商之一,并于 2018 年 6 月由富达领投筹集了额外的 3.92 亿美元,估值达到 16 亿美元,使其总融资达到 569 亿美元。它强调使用机器学习从社交媒体提取的实时信号,并为广泛的客户提供服务,包括不仅仅是买卖双方的投资公司,还有新闻组织和公共部门。

StockTwits

StockTwits 是一个社交网络和微博平台,几十万投资专业人士在其中分享信息和交易想法,这些信息以 StockTwits 的形式被广泛的金融网络和社交媒体平台的大量观众所关注。这些数据可以被利用,因为它可能反映了投资者的情绪或本身驱动了交易,反过来又影响了价格。GitHub 上的参考资料包含了一篇建立在选定特征上的交易策略的链接。

RavenPack

RavenPack 分析大量不同的非结构化基于文本的数据,生成包含对投资者相关信息的结构化指标,包括情感评分。底层数据来源包括高级新闻线和监管信息,以及新闻稿和超过 19,000 个网上出版物。摩根大通测试了基于情感评分的多头主权债券和股票策略,并取得了与传统风险溢价低相关的积极结果(见参考资料)。

卫星数据

RS Metrics 成立于 2010 年,通过卫星、无人机和飞机三角测量地理空间数据,重点关注金属和商品、房地产和工业应用。该公司基于自己的高分辨率卫星提供信号、预测分析、警报和终端用户应用。使用案例包括估算针对特定连锁店或商业地产的零售流量,以及某些常见金属的生产和储存或相关生产地点的就业情况。

地理位置数据

Advan 成立于 2015 年,为对冲基金客户提供源自手机流量数据的信号,目标是美国和欧洲各个领域的 1600 个股票。该公司使用应用程序收集数据,在明确获得用户同意的情况下,在智能手机上安装地理位置代码,并使用多个通道(如 WiFi、蓝牙和蜂窝信号)跟踪位置以提高准确性。使用案例包括估算实体店位置的客流量,进而作为预测交易公司收入的模型的输入。

电子邮件收据数据

Eagle Alpha 提供了一系列服务,其中包括利用电子邮件收据的大量在线交易数据,涵盖了 5000 多个零售商,包括在 53 个产品组中分类的项目和 SKU 级交易数据。摩根大通分析了一个时间序列数据集,从 2013 年开始,涵盖了整个样本期间内始终活跃的用户群。数据集包含每个时期的总体花费、订单数量和独立买家数量。

处理替代数据

我们将通过网络爬虫说明替代数据的获取,首先针对 OpenTable 餐厅数据,然后转移到 Seeking Alpha 托管的盈利电话转录。

爬取 OpenTable 数据

替代数据的典型来源是评价网站,如 Glassdoor 或 Yelp,通过员工评论或客户评论传达内部见解。这些数据为旨在预测企业前景或直接其市值以获取交易信号的 ML 模型提供了宝贵的输入。

数据需要从 HTML 源中提取,除非有法律障碍。为了说明 Python 提供的网络爬虫工具,我们将从 OpenTable 检索有关餐厅预订的信息。此类数据可用于预测地理位置的经济活动、房地产价格或餐厅连锁收入。

使用 requests 和 BeautifulSoup 从 HTML 中提取数据

在本节中,我们将请求和解析 HTML 源代码。我们将使用 requests 库进行 超文本传输协议 (HTTP) 请求和检索 HTML 源代码,使用 BeautifulSoup 解析和提取文本内容。

然而,我们将遇到一个常见的障碍:网站可能只在初始页面加载后使用 JavaScript 请求某些信息。因此,直接的 HTTP 请求将不会成功。为了规避这种类型的保护,我们将使用一个无界面浏览器,以浏览器的方式检索网站内容:

from bs4 import BeautifulSoup
import requests

# set and request url; extract source code
url = "https://www.opentable.com/new-york-restaurant-listings"
html = requests.get(url)
html.text[:500]

' <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE"/> <title>Restaurant Reservation Availability</title> <meta name="robots" content="noindex" > </meta> <link rel="shortcut icon" href="//components.otstatic.com/components/favicon/1.0.4/favicon/favicon.ico" type="image/x-icon"/><link rel="icon" href="//components.otstatic.com/components/favicon/1.0.4/favicon/favicon-16.png" sizes="16x16"/><link rel='

现在我们可以使用 BeautifulSoup 解析 HTML 内容,然后查找我们通过检查源代码获得的所有与餐厅名称相关的span 标签,即 rest-row-name-text(请参阅 GitHub 仓库中链接的指令以检查网站源代码):

# parse raw html => soup object
soup = BeautifulSoup(html.text, 'html.parser')

# for each span tag, print out text => restaurant name
for entry in soup.find_all(name='span', attrs={'class':'rest-row-name-
text'}):
    print(entry.text)

Wade Coves
Alley
Dolorem Maggio
Islands
...

一旦你识别出感兴趣的页面元素,BeautifulSoup 将很容易地检索其中包含的文本。如果你想要获取每个餐厅的价格类别,你可以使用:

# get the number of dollars signs for each restaurant
for entry in soup.find_all('div', {'class':'rest-row-pricing'}):
    price = entry.find('i').text

当你尝试获取预订数量时,然而,你只会得到一个空列表,因为该网站使用 JavaScript 代码在初始加载完成后请求此信息:

soup.find_all('div', {'class':'booking'})
[]

介绍 Selenium - 使用浏览器自动化

我们将使用浏览器自动化工具 Selenium 操作一个无头 FireFox 浏览器,它将为我们解析 HTML 内容。

以下代码打开了 FireFox 浏览器:

from selenium import webdriver

# create a driver called Firefox
driver = webdriver.Firefox()

让我们关闭浏览器:

# close it
driver.close()

要使用 selenium 和 Firefox 检索 HTML 源代码,请执行以下操作:

import time, re

# visit the opentable listing page
driver = webdriver.Firefox()
driver.get(url)

time.sleep(1) # wait 1 second

# retrieve the html source
html = driver.page_source
html = BeautifulSoup(html, "lxml")

for booking in html.find_all('div', {'class': 'booking'}):
    match = re.search(r'\d+', booking.text)
    if match:
        print(match.group())

建立一个餐厅预订数据集

现在,你只需要将网站中所有有趣的元素结合起来,创建一个特性,你可以将其用于模型中,以预测地理区域的经济活动或特定社区的人流量。

使用 Selenium,你可以跟随链接到下一页,并快速构建纽约市超过 10,000 家餐厅的数据集,然后定期更新以跟踪时间序列。首先,我们设置一个函数来解析我们计划爬取的页面的内容:

def parse_html(html):
    data, item = pd.DataFrame(), {}
    soup = BeautifulSoup(html, 'lxml')
    for i, resto in enumerate(soup.find_all('div', class_='rest-row-
           info')):
        item['name'] = resto.find('span', class_='rest-row-name-
                                   text').text

        booking = resto.find('div', class_='booking')
        item['bookings'] = re.search('\d+', booking.text).group() if 
                                       booking else 'NA'

        rating = resto.select('div.all-stars.filled')
        item['rating'] = int(re.search('\d+', 
                rating[0].get('style')).group()) if rating else 'NA'

        reviews = resto.find('span', class_='star-rating-text--review-
                              text')
        item['reviews'] = int(re.search('\d+', reviews.text).group()) if reviews else 'NA'

        item['price'] = int(resto.find('div', class_='rest-row-
                            pricing').find('i').text.count('$'))
        item['cuisine'] = resto.find('span', class_='rest-row-meta--
                                      cuisine').text
        item['location'] = resto.find('span', class_='rest-row-meta--
                                       location').text
        data[i] = pd.Series(item)
    return data.T

然后,我们启动一个无界面浏览器,它将继续为我们点击“下一页”按钮,并捕获每个页面显示的结果:

restaurants = pd.DataFrame()
driver = webdriver.Firefox()
url = "https://www.opentable.com/new-york-restaurant-listings"
driver.get(url)
while True:
    sleep(1)
    new_data = parse_html(driver.page_source)
    if new_data.empty:
        break
    restaurants = pd.concat([restaurants, new_data], ignore_index=True)
    print(len(restaurants))
    driver.find_element_by_link_text('Next').click()
driver.close()

网站仍在不断变化,因此这段代码可能在某些时候停止工作,并需要更新以跟随最新的站点导航和机器人检测。

进一步的一步 - Scrapy 和 splash

Scrapy 是一个强大的库,用于构建跟随链接、检索内容并以结构化方式存储解析结果的机器人。结合无头浏览器 splash 使用,它还可以解释 JavaScript,并成为 Selenium 的高效替代方案。你可以在 01_opentable 目录中使用 scrapy crawl opentable 命令运行蜘蛛,结果将记录在 spider.log 中:

from opentable.items import OpentableItem
from scrapy import Spider
from scrapy_splash import SplashRequest

class OpenTableSpider(Spider):
    name = 'opentable'
    start_urls = ['https://www.opentable.com/new-york-restaurant-
                   listings']

    def start_requests(self):
        for url in self.start_urls:
            yield SplashRequest(url=url,
                                callback=self.parse,
                                endpoint='render.html',
                                args={'wait': 1},
                                )

    def parse(self, response):
        item = OpentableItem()
        for resto in response.css('div.rest-row-info'):
            item['name'] = resto.css('span.rest-row-name-
                                      text::text').extract()
            item['bookings'] = 
                  resto.css('div.booking::text').re(r'\d+')
            item['rating'] = resto.css('div.all-
                  stars::attr(style)').re_first('\d+')
            item['reviews'] = resto.css('span.star-rating-text--review-
                                         text::text').re_first(r'\d+')
            item['price'] = len(resto.css('div.rest-row-pricing > 
                                i::text').re('\$'))
            item['cuisine'] = resto.css('span.rest-row-meta--
                                         cuisine::text').extract()
            item['location'] = resto.css('span.rest-row-meta--
                               location::text').extract()
            yield item

从这些数据中提取信息的方法有很多,超出了个别餐厅或连锁店的评论和预订。

我们还可以进一步收集并对餐馆的地址进行地理编码,以将餐馆的物理位置与其他感兴趣的区域(如热门零售店或街区)联系起来,以获取有关经济活动特定方面的见解。如前所述,这样的数据结合其他信息将最有价值。

收益电话转录

文本数据是一个重要的替代数据来源。一个例子是收益电话的转录,执行人员不仅展示最新的财务结果,还回答金融分析师的问题。投资者利用这些转录来评估情绪变化、特定主题的强调或沟通风格。

我们将说明如何从流行的交易网站www.seekingalpha.com爬取和解析收益电话的转录:

import re
from pathlib import Path
from time import sleep
from urllib.parse import urljoin
from bs4 import BeautifulSoup
from furl import furl
from selenium import webdriver

transcript_path = Path('transcripts')

SA_URL = 'https://seekingalpha.com/'
TRANSCRIPT = re.compile('Earnings Call Transcript')

next_page = True
page = 1
driver = webdriver.Firefox()
while next_page:
    url = f'{SA_URL}/earnings/earnings-call-transcripts/{page}'
    driver.get(urljoin(SA_URL, url))
    response = driver.page_source
    page += 1
    soup = BeautifulSoup(response, 'lxml')
    links = soup.find_all(name='a', string=TRANSCRIPT)
    if len(links) == 0:
        next_page = False
    else:
        for link in links:
            transcript_url = link.attrs.get('href')
            article_url = furl(urljoin(SA_URL, 
                           transcript_url)).add({'part': 'single'})
            driver.get(article_url.url)
            html = driver.page_source
            meta, participants, content = parse_html(html)
            meta['link'] = link

driver.close()

使用正则表达式解析 HTML

为了从非结构化的转录中收集结构化数据,我们可以使用正则表达式以及 BeautifulSoup

它们让我们不仅可以收集有关收益电话公司和时间的详细信息,还可以记录谁在场,并将声明归因于分析师和公司代表:

def parse_html(html):
    date_pattern = re.compile(r'(\d{2})-(\d{2})-(\d{2})')
    quarter_pattern = re.compile(r'(\bQ\d\b)')
    soup = BeautifulSoup(html, 'lxml')

    meta, participants, content = {}, [], []
    h1 = soup.find('h1', itemprop='headline').text
    meta['company'] = h1[:h1.find('(')].strip()
    meta['symbol'] = h1[h1.find('(') + 1:h1.find(')')]

    title = soup.find('div', class_='title').text
    match = date_pattern.search(title)
    if match:
        m, d, y = match.groups()
        meta['month'] = int(m)
        meta['day'] = int(d)
        meta['year'] = int(y)

    match = quarter_pattern.search(title)
    if match:
        meta['quarter'] = match.group(0)

    qa = 0
    speaker_types = ['Executives', 'Analysts']
    for header in [p.parent for p in soup.find_all('strong')]:
        text = header.text.strip()
        if text.lower().startswith('copyright'):
            continue
        elif text.lower().startswith('question-and'):
            qa = 1
            continue
        elif any([type in text for type in speaker_types]):
            for participant in header.find_next_siblings('p'):
                if participant.find('strong'):
                    break
                else:
                    participants.append([text, participant.text])
        else:
            p = []
            for participant in header.find_next_siblings('p'):
                if participant.find('strong'):
                    break
                else:
                    p.append(participant.text)
            content.append([header.text, qa, '\n'.join(p)])
    return meta, participants, content

我们将结果存储在几个 .csv 文件中,以便在使用 ML 处理自然语言时轻松访问:

def store_result(meta, participants, content):
    path = transcript_path / 'parsed' / meta['symbol']
    if not path.exists():
        path.mkdir(parents=True, exist_ok=True)
    pd.DataFrame(content, columns=['speaker', 'q&a', 
              'content']).to_csv(path / 'content.csv', index=False)
    pd.DataFrame(participants, columns=['type', 'name']).to_csv(path / 
                 'participants.csv', index=False)
    pd.Series(meta).to_csv(path / 'earnings.csv'

在 GitHub 仓库中的 README 中查看其他详细信息和引用,以获取进一步开发网络爬虫应用程序的资源。

总结

在本章中,我们介绍了作为大数据革命结果而可用的新型替代数据来源,包括个人、业务流程和传感器,例如卫星或 GPS 位置设备。我们提出了一个框架来从投资的角度评估替代数据集,并列出了帮助您导航这个提供关键输入的庞大且迅速扩张的领域的关键类别和提供者,这些输入用于使用 ML 的算法交易策略。

我们探索了强大的 Python 工具,以大规模收集您自己的数据集,这样您就有可能通过网络爬取来获得您的私人信息优势,成为一个算法交易员。

我们现在将在接下来的章节中进行设计和评估产生交易信号的 alpha 因子,并研究如何在投资组合背景下将它们结合起来。