Loading...
交易成本分析TCA是交易者、投资组合经理和经纪人广泛使用的工具,旨在进行交易前和交易后的分析,帮助他们衡量和优化交易成本,并评估交易策略的有效性。本文将分析来自 LSEG Tick History PCAP 数据集的期权买卖差价,并使用 Amazon Athena for Apache Spark 进行分析。我们将展示如何访问数据、定义自定义函数、查询和过滤数据集,以及可视化分析结果,全程无需担心基础设施的设置或 Spark 的配置,即便是在处理大数据集时也如此。
期权价格报告局OPRA作为一个重要的证券信息处理机构,负责收集、整合和传播美国期权的最后销售报告、报价和相关信息。OPRA 在应对日益增长的交易活动和波动性方面发挥着关键作用,目前有 18 个活跃的美国期权交易所,覆盖超过 150 万个合格合约。
2024 年 2 月 5 日,证券行业自动化公司SIAC将把 OPRA 供稿升级为 96 个组播通道,以优化符号分配和线路容量利用率。尽管此次升级不会立即改变已发布数据的总量,但能显著加快数据传播速度,满足动态期权市场的需求。
OPRA 是最为庞大的数据源之一,2023 年第三季度的一天内达到了 1504 亿条消息的峰值,要求的容量余量为 4000 亿条消息。捕获每一条消息对于交易成本分析、市场流动性监测、交易策略评估和市场研究至关重要。
LSEG Tick History PCAP 是一个超过 30 PB 的云端存储库,涵盖超高质量的全球市场数据。数据直接在交易所数据中心捕获,并通过冗余捕获技术在主要和备份交易所的数据中心中进行有效运作,确保了无损数据捕获,并采用 GPS 时间源保证纳秒级时间戳精度。同时,捕获的数据经过精细的处理和仲裁,转化为 Parquet 格式进行分析。
数据的规范化过程每天可生成高达 6 TB 的压缩 Parquet 文件,这一庞大的数据量归因于 OPRA 的包容性,跨越多个交易所,涵盖多种期权合约,并具有多样的属性。市场波动性和期权交易所的市场造市活动进一步增加了在 OPRA 上发布的数据量。
数据集的属性使公司能够进行多种分析,包括:
交易前分析:评估潜在交易影响,基于历史数据探索不同实施策略。交易后评估:衡量实际执行成本与基准的比较以评估执行策略的表现。优化执行:基于历史市场模式微调执行策略,以最小化市场影响并减少整体交易成本。风险管理:识别滑点模式,找出异常值,主动管理与交易活动相关的风险。绩效归因:在分析投资组合表现时,将交易决策的影响与投资决策的影响分离。LSEG Tick History PCAP 数据集可通过 AWS Data Exchange 访问,也可以在 AWS Marketplace 上找到。利用 AWS Data Exchange for Amazon S3,您可以直接从 LSEG 的 Amazon S3 存储桶中访问 PCAP 数据,省去了企业存储数据副本的需要。这种方式简化了数据管理和存储,为客户提供了对高质量 PCAP 或规范化数据的快速访问,并集成了实用性和 显著的数据存储节省。
对于分析工作,Athena for Apache Spark 提供了简化的笔记本体验,可以通过 Athena 控制台或 Athena API 进行访问,从而搭建互动式 Apache Spark 应用程序。借助优化的 Spark 运行时,Athena 通过动态扩展 Spark 引擎的数量来处理多达 PB 的数据,且反应时间不足一秒。此外,常见的 Python 库如 pandas 和 NumPy被无缝集成,支持复杂应用逻辑的构建,用户还可以导入自定义库用于笔记本。Athena for Spark 支持大多数开放数据格式,并与 AWS Glue 数据目录无缝集成。
在本次分析中,我们使用了 2023 年 5 月 17 日的 LSEG Tick History PCAP OPRA 数据集,包含以下组分:
最佳买卖报价BBO 报告特定交易所的最高买入报价和最低卖出报价。全国最佳买卖报价NBBO 报告所有交易所的最高买入报价和最低卖出报价。交易 记录所有交易所的已完成交易。数据集的体积为:
交易 160 MB,分布于大约 60 个压缩的 Parquet 文件。BBO 24 TB,分布于大约 300 个压缩的 Parquet 文件。NBBO 28 TB,分布于大约 200 个压缩的 Parquet 文件。
对于交易成本分析TCA,分析 OPRA Tick History 数据涉及在特定交易事件周围剖析市场报价和交易。我们在本研究中使用以下指标:
报价差QS 计算为 BBO 卖出报价与买入报价之间的差值。有效差ES 计算为交易价格与 BBO 中点BBO 买入报价 (BBO 卖出报价 BBO 买入报价)/2之间的差值。有效/报价差EQF 计算为 (ES / QS) 100。我们在交易前和交易后四个时间段交易刚结束后、1 秒后、10 秒后和 60 秒后计算这些差值。
要配置 Athena for Apache Spark,请完成以下步骤:
在 Athena 控制台,点击 Get started,选择 Analyze your data using PySpark and Spark SQL。如果您是第一次使用 Athena Spark,请选择 Create workgroup。在 Workgroup name 中输入工作组名称,例如 tcaanalysis。在 Analytics engine 部分,选择 Apache Spark。在 Additional configurations 部分,您可以选择 Use defaults 或提供自定义的 AWS 身份和访问管理IAM角色和 Amazon S3 位置以存储计算结果。点击 Create workgroup。创建工作组后,导航到 Notebooks 标签页,选择 Create notebook。输入笔记本名称,例如 tcaanalysiswithtickhistory。点击 Create 以创建您的笔记本。如果您已经创建了 Spark 工作组,请在 Get started 下选择 Launch notebook editor。创建笔记本后,您将被重定向到交互式笔记本编辑器。现在我们可以向笔记本添加并运行以下代码。
完成以下步骤以创建分析:
导入常用库:pythonimport pandas as pdimport plotlyexpress as pximport plotlygraphobjects as go
创建我们的数据框以存储 BBO、NBBO 和交易数据:pythonbboquote = sparkreadparquet(fs3//ltbucketgt/mt=bboquote/f=opra/dt=20230517/)bboquotecreateOrReplaceTempView(bboquote)nbboquote = sparkreadparquet(fs3//ltbucketgt/mt=nbboquote/f=opra/dt=20230517/)nbboquotecreateOrReplaceTempView(nbboquote)trades = sparkreadparquet(fs3//ltbucketgt/mt=trade/f=opra/dt=20230517/291parquet)tradescreateOrReplaceTempView(trades)
现在我们可以确定一个用于交易成本分析的交易:pythonfilteredtrades = sparksql(select Product Price Quantity ReceiptTimestamp MarketParticipant from trades)
得到如下输出:
Product Price Quantity ReceiptTimestamp MarketParticipant QQQ 230518C00329000 117000000000000000001000000000000000000001684338565538021907NYSEArcaQQQ 230518C00329000 117000000000000000002000000000000000000001684338576071397557NASDAQOMXPHLXQQQ 230518C00329000 11600000000000000000100000000000000000001684338579104713924ISEQQQ 230518C00329000 11400000000000000000100000000000000000001684338580263307057NASDAQOMXBXOptionsQQQ 230518C00329000 11200000000000000000100000000000000000001684338581025332599ISE
我们将使用中间突出显示的交易信息,进一步分析交易产品tp、交易价格tpr和交易时间tt。
现在我们为分析创建多个辅助函数:pythondef calculateesqseqf(df tradeprice) df[BidPrice] = df[BidPrice]astype(double) df[AskPrice] = df[AskPrice]astype(double) df[ES] = ((df[AskPrice]df[BidPrice])/2) tradeprice df[QS] = df[AskPrice]df[BidPrice] df[EQF] = (df[ES]/df[QS])100 return df
def gettradebeforenseconds(tradetime df seconds=0 groupbycol=None) nseconds = seconds 1000000000 nseconds = tradetime retdf = df[df[ReceiptTimestamp] lt nseconds]groupby(groupbycol)last() retdf[BidPrice] = retdf[BidPrice]astype(double) retdf[AskPrice] = retdf[AskPrice]astype(double) retdf = retdfresetindex() return retdf
def gettradeafternseconds(tradetime df seconds=0 groupbycol=None) nseconds = seconds 1000000000 nseconds = tradetime retdf = df[df[ReceiptTimestamp] gt nseconds]groupby(groupbycol)first() retdf[BidPrice] = retdf[BidPrice]astype(double) retdf[AskPrice] = retdf[AskPrice]astype(double) retdf = retdfresetindex() return retdf
def getnbbotradebeforenseconds(tradetime df seconds=0) nseconds = seconds 1000000000 nseconds = tradetime retdf = df[df[ReceiptTimestamp] lt nseconds]iloc[1] retdf[BidPrice] = retdf[BidPrice]astype(double) retdf[AskPrice] = retdf[AskPrice]astype(double) return retdf
def getnbbotradeafternseconds(tradetime df seconds=0) nseconds = seconds 1000000000 nseconds = tradetime retdf = df[df[ReceiptTimestamp] gt nseconds]iloc[1] retdf[BidPrice] = retdf[BidPrice]astype(double) retdf[AskPrice] = retdf[AskPrice]astype(double) return retdf
鲸鱼加速器vip破解版在以下函数中,我们创建了包含所有交易前后报价的数据集。Athena Spark 将自动确定所需启动的数据处理单元DPU数量:pythondef gettcaanalysisviadfsinglequery(tradeproduct tradeprice tradetime) # BBO 报价 bbos = sparksql(fSELECT Product ReceiptTimestamp AskPrice BidPrice MarketParticipant FROM bboquote where Product = {tradeproduct}) bbos = bbostoPandas()
bbojustbefore = gettradebeforenseconds(tradetime bbos seconds=0 groupbycol=MarketParticipant)bbojustafter = gettradeafternseconds(tradetime bbos seconds=0 groupbycol=MarketParticipant)bbo1safter = gettradeafternseconds(tradetime bbos seconds=1 groupbycol=MarketParticipant)bbo10safter = gettradeafternseconds(tradetime bbos seconds=10 groupbycol=MarketParticipant)bbo60safter = gettradeafternseconds(tradetime bbos seconds=60 groupbycol=MarketParticipant)allbbos = pdconcat([bbojustbefore bbojustafter bbo1safter bbo10safter bbo60safter] ignoreindex=True sort=False)bboscalculated = calculateesqseqf(allbbos tradeprice)# NBBO 报价nbbos = sparksql(fSELECT Product ReceiptTimestamp AskPrice BidPrice BestBidParticipant BestAskParticipant FROM nbboquote where Product = {tradeproduct})nbbos = nbbostoPandas()nbbojustbefore = getnbbotradebeforenseconds(tradetimenbbos seconds=0)nbbojustafter = getnbbotradeafternseconds(tradetime nbbos seconds=0)nbbo1safter = getnbbotradeafternseconds(tradetime nbbos seconds=1)nbbo10safter = getnbbotradeafternseconds(tradetime nbbos seconds=10)nbbo60safter = getnbbotradeafternseconds(tradetime nbbos seconds=60)allnbbos = pdconcat([nbbojustbefore nbbojustafter nbbo1safter nbbo10safter nbbo60safter] ignoreindex=True sort=False)nbboscalculated = calculateesqs