亚马逊AWS官方博客

使用 Amazon EKS 和 Ray 提高量化策略研究效率

1. 背景

在当今金融市场中,量化金融成为越来越重要的研究趋势。然而,开发高效的量化策略并非易事,需要处理大规模数据和复杂计算模型。为了解决这一挑战,金融机构越来越多地采用云计算和分布式计算技术。

本文结合 Amazon EKSRay,通过实际部署示例和对不同任务的测试结果比较,希望为有兴趣探索分布式投研任务的量化金融研究人员提供一种思路,以提高在量化金融投研过程中的策略研究效率。

2. 方案介绍及架构描述

在本方案中,量化投研团队可在云上便捷地构建一套可扩展,高度灵活性的分布式计算框架。研究员能够通过以下三个简单的步骤,即可使用 Ray 分布式计算框架加速量化投研任务:

  1. 在代码中增加 Ray 相关片段以声明使用 Ray 框架进行分布式计算
  2. 通过预定义的 yaml 创建可扩展的 Ray 计算集群
  3. 提交量化研究任务(模型训练,回测等)

  • 服务介绍

Amazon EKS:Amazon EKS 是一项托管 Kubernetes 服务,用于在 AWS Cloud 和本地数据中心上运行 Kubernetes。在云中,Amazon EKS 可自动管理负责安排容器、管理应用程序可用性、存储集群数据和其他关键任务的 Kubernetes 控制面板节点的可用性和可扩展性。

通过使用 Amazon EKS,能够帮助量化研究员简化对算力集群的管理和运维难度,并通过云平台的弹性扩缩的特点,满足不同研究任务下对于算力的需求,提高整体策略研究的效率。

  • Ray 框架简述

Ray (https://www.ray.io/)是一个开源的分布式计算框架,旨在简化构建分布式应用程序和系统的过程。它提供了高效的任务并行和数据并行模型,以及用于构建分布式应用程序的丰富工具和库。

3. 环境准备

3.1 创建 Amazon EKS 集群

  • 在本地笔记本或 k8s 管理服务器上安装并配置 kubectl,eksctl,awscli(需要 v2 版本)等工具,可参考 https://docs.thinkwithwp.com/zh_cn/eks/latest/userguide/getting-started.html 文档进行创建。
  • 配置 EKScluster.yaml 文件,在本次示例中,在东京 region 配置一个 2 节点的 k8s 集群,每个节点使用 m5.large 实例,具体 yaml 文件配置如下:
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-cluster-1
  region: ap-northeast-1

nodeGroups:
  - name: ng-1
    instanceType: m5.large
    desiredCapacity: 2
    volumeSize: 80
  • 使用 eksctl 创建 Amazon EKS 集群及 node group:eksctl create cluster -f EKScluster.yaml
  • 使用 kubectl get nodes -o wide 等命令确认集群创建完毕

3.2 创建 S3 存储桶

  • 通过 aws cli 命令行进行 S3 存储桶创建:

执行以下命令创建 S3 存储桶,将其中的<bucket-name>和<region-code>替换成自己所需要的存储桶名称和 AWS 对应 region,AWS region 建议和 Amazon EKS 所在的 region 保持一致(在本示例里为 ap-northeast-1)。

aws s3api create-bucket --bucket <bucket-name>  --create-bucket-configuration LocationConstraint=<region-code> 

3.3 配置合适的权限

在本次示例中,需要使用的数据在 S3 中,因此需要对 Amazon EKS 的 node 进行权限配置,以在 EC2 的 node 上包含 S3fullaccess 的权限,在实际生产环境中,需要根据具体需求,对权限进行最小特权原则的设计。

  • 可通过 aws cli 进行 IAM 策略添加,具体步骤如下:

获取 k8s 集群中的 node EC2 信息→获取 node EC2 的 instance profile 和 IAM role 信息→向指定 IAM role 增加 AmazonS3FullAccess 的 policy

kubectl get nodes -o wide
aws ec2 describe-instances --filters "Name=private-ip-address,Values=<instance internal ip>" --query 'Reservations[].Instances[].InstanceId' --output text
aws ec2 describe-instances --instance-ids <node的instance id> --query 'Reservations[].Instances[].IamInstanceProfile.Arn' --output text
aws iam list-instance-profiles --query 'InstanceProfiles[?Arn==`<node instance profile的arn>`].Roles[].RoleName' --output text
aws iam attach-role-policy --role-name <IAM role 的 arn> --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

至此,对于 Amazon EKS 集群及任务所需存储均已完成创建,之后将在 Amazon EKS 集群上部署 Ray 集群并进行任务提交测试。

4. 部署和测试

4.1 部署 Ray Cluster

Ray 在 k8s 上可通过 KubeRay operator 进行部署,通过 kuberay 可以部署 Ray 框架中的相关资源,并能够通过使用 Ray Autoscaler 对不同任务进行计算资源扩展。

  • 通过 helm 安装 KubeRay:
helm repo add kuberay https://ray-project.github.io/kuberay-helm/
helm install kuberay-operator kuberay/kuberay-operator --version 0.5.0

  • 配置 RayCluster.yaml,在此 sample 基础上,能够配置一个最大能够启动 10 个 worker node pods 的 Ray 集群:RayCluster.yaml
  • 部署 RayCluster,在 RayCluster.yaml 文件目录下执行以下命令:
kubectl apply -f raycluster.yaml

  • 以上步骤完成了在 Amazon EKS 上的 Ray 集群部署,可通过 kubectl get svc 查看 ray service,在本示例中,会使用 port forwarding 将 ray service 提供给研究员所在的 EC2 环境,研究员可在 EC2 上使用 localhost 地址直接提交任务。

kubectl port-forward --address 0.0.0.0 service/raycluster-autoscaler-head-svc 8265:8265
  • Ray 集群可以通过使用 ray job submit 方式提交任务,通过以下任务可查看 ray cluster 状态:
ray job submit --address http://localhost:8265 -- python -c "import ray; ray.init(); print(ray.cluster_resources())"

4.2 测试任务 — 计算 pi

此测试任务旨在通过简单的计算任务,熟悉并了解 ray 的工作模式,可为代码的并行化提供思路。

  • 测试环境:
    • 单机:m5.xlarge
    • ray on Amazon EKS:m5.large * 2

使用蒙特卡洛模拟进行 pi 的计算,原理是在一个单位的正方形内,选取 n 个点,计算点是否落在半径为 1 的圆内,通过在圆内的点的数量和总的点的数量,来进行 pi 的估算。

通过 Ray 集群,能够将估算任务进行并行化执行,通过@ray.remote 方法修饰需要分布式计算的函数,即可进行并行化,具体对比代码可参考:

单机计算 pi 代码:pi-ray.py

并行计算 pi 代码:pi-rayparallel.py

  • 下图中左边代码片段展示了使用 ray 对指定函数进行修饰,右面的代码片段展示了如何在代码中向 ray 提交分布式任务

  • 任务执行结果对比:
    • 单机执行时间:91.96s
    • ray 集群执行时间:53.75s

  • 从上述结果可以看出,使用 ray 集群后对任务执行时间有明显缩短,且代码改动量较少。

4.3 测试任务 — 量化回测任务

在日常的量化研究中,回测任务通常需要调整较多参数,如回测时间段、标的组合、策略参数等,通过使用并行化手段,能够提高回测任务的执行效率,使用 Ray 能够在代码修改量较小的情况下,即可获得分布式任务所带来的好处。

  • 测试环境:
    • 单机:m5.large,m5.xlarge
    • ray on Amazon EKS:m5.large * 2

此次测试任务以海龟交易法作为每个标的的回测策略,并根据 A 股市场行业进行标的划分,选择银行(42 个标的),证券(50 个标的),白酒(20 个标的),互联网(79 个标的)四个行业分别执行回测任务,回测时间段为 2010 年 1 月 1 日 至 2022 年 12 月 30 日。单个回测任务选择某个行业内所有标的分别执行回测任务,并输出最终回测结果。

在开始任务前,可将回测任务所需数据上传至 S3 存储桶内,日线数据放在{bucket-name}/daily 下,行业股票代码上传至{bucket-name}下。原始数据在这个链接下:数据

单机回测任务代码:TurtleBacktest.py

  • 基于 Ray 进行任务改造

在回测任务中,会从 S3 下载各个标的历史行情数据,并执行回测任务,再把结果上传至指定 S3 桶,在单机任务中,所有标的的数据下载、回测计算、数据上传均串行完成,通过@ray.remote 修饰 BackTest 函数,可通过 Ray 集群将不同标的的回测任务分散到不同的 worker 上执行,能够提升整体任务执行效率,缩短任务时间。与此同时,使用 ray 框架对于代码的修改度也较低。

在本次示例中,RayCluster.yaml 中对每个 Ray 集群的 worker pod 声明了所需要的资源(0.5C1G),通过@ray.remote 修饰 BackTest 函数,能将单个标的的回测任务分配到不同的 ray worker pod 中去,并进行并行执行。

    • 串行任务→并行任务概览

将并行的 BackTest 任务分配给不同的 Ray worker pod 进行执行

    • 使用 ray.remote 修饰需要并行执行的函数

    • 在主程序中通过.remote 方法修改任务执行代码,ray 会将任务分布到不同 worker pod 上执行

并行回测任务代码:TurtleBacktest-parallel.py

  • 任务提交
    • 通过 ray job submit 进行任务提交,由于使用了 backtrader 作为回测框架,可以在任务提交时使用 —runtime-env 进行依赖包安装,具体命令如下所示,也可在 ray cluster 部署时使用自定义镜像部署
ray job submit --address="http://localhost:8265" --runtime-env-json='{"working_dir": "/home/ec2-user/raytest/TurtleBacktest", "pip": ["backtrader"]}' -- python TurtleBacktest-parallel.py

如果 Ray cluster 使用了 autoscaler,则会在任务提交后根据任务所需自动进行 worker pod 的扩展,在任务结束时也可进行自行回收,无需研究员进行资源管理。

  • 测试结果对比:
任务 标的数 单机执行时间 m5.large(秒) 单机执行时间 m5.xlarge (秒) ray on Amazon EKS 执行时间(固定 4worker pods / autoscaler)(秒)
wine 20 40.95 29.98 16.05 / 31.17
bank 42 57.28 43.39 22.19 / 37.12
securities 50 77.97 57.59 27.59 / 44.18
internet 79 119.54 90.06 40.75 / 56.82

通过测试结果,可以观察到:

  • 在不修改代码的情况下,单机纵向扩容带来的任务时间缩短程度有限
  • 通过 ray 执行分布式回测任务,在资源总量相同的情况下,任务时间相比单机任务缩短接近一倍
  • 对于整体执行时间较短的任务,通过 ray autoscaler 进行扩容所带来的额外的任务启动 overhead 时间比例较高,可适当通过固定的 worker 进行并行任务

5. 总结

通过搭建基于 Amazon EKS 和 Ray 的计算环境,并进行了部分任务测试,可以发现:

  • 使用 Amazon EKS,能够帮助量化研究团队便捷、高效地搭建现代化投研环境,能够提供一个稳定、安全、可靠的计算环境
  • Ray 框架对于原本任务的代码改动程度很小,仅需要简单的几步即可实现分布式并行计算,对于研究人员来说学习曲线较为平滑
  • 使用 Amazon EKS 配合 Ray 计算框架对于量化策略研究过程中的计算资源能够进行较为自动化的分配,降低量化研究员对于不同任务的资源管理和维护复杂度

总体来说,本文通过对 Amazon EKS 和 Ray 的实践,为希望探索分布式投研任务的量化金融研究人员提供了一种思路,能够更简单地实现分布式任务,并无需管理和运维底层 IT 基础设施,帮助量化金融研究人员更专注在策略研发,提高整体策略研究效率。

参考文档

Amazon EKS 集群搭建入门:https://docs.thinkwithwp.com/zh_cn/eks/latest/userguide/getting-started.html

使用 eksctl 创建 Amazon EKS 集群和 node group:https://eksctl.io/usage/creating-and-managing-clusters/#using-config-fileshttps://eksctl.io/introduction/#getting-started

基于 K8S 搭建 Ray 集群:https://docs.ray.io/en/latest/cluster/kubernetes/getting-started.html#kuberay-quickstarthttps://docs.ray.io/en/latest/cluster/kubernetes/user-guides/config.html#kuberay-config

本篇作者

郑明明

亚马逊云科技解决方案架构师,服务于国内及全球多家头部金融机构,在 IT 与云计算领域有丰富的项目经验,对量化金融机构使用云计算有较为深入的探索和实践。