温故而知新。

框架

HFT-Infra.png 上图是我眼中的最简交易系统,它分为几个部分:

  • 网关(Gateway): 负责和交易所/经纪人(远端)打交道。一方面接收行情数据(报价更新,订单更新等),另一方面把交易指令传给远端.
  • 定价引擎(Pricing Engine): 接入的行情数据需要转换成策略需要的报价。对于衍生品来说,它的输出应当至少包含衍生品的理论价格。定价引擎可能还有额外的输入,比如对于期权定价而言,,一般会使用类Black-Scholes模型定价,有了标的物(underlying)的市场数据之后,它还需要波动率(volatility)、利率等参数的输入以及一些合规、风控相关的参数。
  • 策略(Strategy): 交易策略接收定价引擎的信息,同时他也接受策略目标instrument的实时行情。不同的策略给出不同的执行建议,然后把这些执行建议传给后续模块。
  • 风控&执行复用(Compliance & Execution Mux): 一个交易系统(很)可能同时执行多个策略。不同策略发出的执行建议可能互相重合、冲突或者产生执行时的合规风险。这个模块负责处理所有的执行请求,把合格的请求发给Gateway执行。这边用Mux相对形象一些,暂时还没想到更好的词。

需要说明的是,上面这些仅仅是极其基础的组件。如果把交易系统作为一个模块看待,它其实会有许多附加组件,例如高频交易员往往会根据经验值调整一些参数,这些参数会反映在策略执行、风控、定价模块中,于此就会产生一些和人交互的UI组件。

优化: 软件、硬件、程序语言...

不同于一众互联网公司的系统,高频交易系统对于低延迟的渴求相当急切,对它来说高并发往往是可以忽略的。重要的是一个报价更新如何最快到达系统,一个订单(order)如何在最快的时间内到达交易所。目前能见到的国外交易公司,主要用C++编写交易系统,当然也有很厉害的公司用自己定制的JVM跑Java交易。对于延迟不是非常敏感的市场,也有使用Python作为开发语言的。当然这些仅限于软件层面,事实上很多交易公司已经用上了FPGA用来进一步加速执行速度,甚至使用FPGA来执行一些简单但是对延迟极其敏感的交易策略。 以C++为例,代码编写上将会大量使用模板(template)替代虚函数。一般应用场景上虚函数调用的开销可能是不值一提的,但是如果算到了纳秒(或CPU tick)级别,虚函数的开销也会令人头疼。也许有人会问,那接口继承怎么不用虚函数弄呢?有兴趣的可以去看一下CRTP设计模式。

Gateway

网关系统的职责是负责对外联系,一般分为行情数据(Market Data)和订单执行(Order Execution)两个部分。交易所一般会提供机房租赁,衍生品交易公司会采用co-location策略把交易主机放在租的机房里,确保和交易所的Matching Engine距离最近。所谓Matching Engine就是交易所自己用来匹配订单(order)的中央机器(其实有很多个机器)。 就行情数据而言,绝大多数交易所是用UDP组播的方式下发数据的。收到组播数据后,需要把订单报价更新的信息尽快处理并上发。就程序逻辑优化而言,第一是要尽最大可能减少内存拷贝(memory copy)。第二是要钻研(并且实验!)交易所给的数据格式,避免去读取不需要的字段。其次某些交易所的市场数据可能还是通过ASCII字符下放的,这边就要尽量优化string to int的延迟。

Market Data

对于某些交易Gateway实现,也会包含price book/order book的更新。行情数据可以细分为不同的频道(channel),一些会播放price book update, 另一些则是order book update. 后者往往包含更多的交易信息,这些交易信息与trade update合并关联之后,就能给pricing module提供实时更新。对于price book/ order book,写代码的小哥往往会对他们各自抽象各自的数据结构,这些数据结构需要保证book update的响应尽量快。在book得到更新后,上层系统(strategy, pricing module)对它的需求是不同的,有些需要full depth of book,有些可能只需要几个book level或是只要TOB(top of book),针对这些不同的需求,系统也会给出不同的优化。也有系统把book update的具体操作另外归类为几个特殊事件直接传给系统上层、以便做出最快响应。这些事件可能包括巨大的价格变动(此时很可能需要撤单)。 另一部分个重要部分是重启、恢复机制。由于UDP传输的不稳定性(尽管已经是co-location了),交易所一般提供通信恢复的专门channel播放恢复数据。在网络中断或者系统故障后,需要通过数据恢复机制重建各种交易工具(instrument)的最新信息。

Order Execution

再来讲讲发单的模块。系统给发单模块的指令已经是经过各种决策后的,一般不需要再进行过滤。一般而言,这部分是通过TCP传输的。为了尽快发单,一般采用数据结构预填充的方法,即把交易信息用数据结构表示,里面固定的字段预先填好。比如C++实现时,Order Execution模块会把各种发单请求写成类成员,在OE class构造时预先构造好。对于OE而言,一般情况下并发并不是主要考虑的因素,因为大部分交易所是允许单个消息包含多个订单请求的(bulk orders or bulk delete orders), 往往把交易请求拆单并发发出的总体耗时比用单个请求发出的更不划算。但这部分仍然需要通过做实验观察得出结论,对于部分的交易所,将一个大单拆成几小份可能有一半左右能抢到,但是如果做成一个大单可能真的是Fill(10%) or kill(90%)了。对于一些需要并发才能优化的交易所,也许会需要使用无锁队列(如MPMC Queue)进行优化。 socket连接?有人可能会问socket怎么搞。其实这种时候用整个系统用busy loop, blocking的方式或许比费劲心事async来得更有效。当然对整个trading engine而言,它应当是多线程、适当异步的,或许Proactor模式更适合一些。所谓多线程,在通信不是很繁忙的desk上,整个gateway系统可以是一个线程,在比较繁忙的desk上,把market data和order execution拆成两个线程做是一种解法。

关于优化,再说一句

不只是应用层的软件,在内核层也需要对性能进行优化。一个简单方法是购买专用的网络硬件,然后利用驱动(等)把网络传输的操作从内核态操作转移到用户态进行。学过操作系统的同学应该知道,在内核态和用户态中间反复切换是有成本的。 此外,一般用于高频交易的主机往往要求CPU主频够快,对核心数要求并不特别高。为了主频够快,一些公司甚至会购买定制优化的超频主机来使用,通过将线程直接分别绑定在CPU core上,然后isolate cpu,再考虑NUMA node,继而用realtime scheduler实现各种黑优化。

交易策略 Trading Strategy

一个交易系统启动之后,往往要运行多个交易策略。单个的交易策略主要由行情变动驱动,打个比方——如果市场的价格发生大幅度变化,那么可能某个期权的报价(Quoting)策略就要立马做很多撤单操作了。一些策略同样也会对成交(Trade)做出相应。 除了直接处理行情信息外,策略也会处理由行情间接引发的其他因子(factor)的更新变化。这些因子的更新频率可能不如实时行情那么频繁,但是也会通过其他的消息途径输入。另外,可能有一些人工设定的策略参数发生了临时调整,这些信息也会输入进来。 如果要对行情变化做出响应,在一个多线程的交易系统中,可能会用到一些消息队列。行情更新的信息会被主线程推到消息队列里,每个策略跑在单独的线程(这个线程可能会独占某个CPU核心)中,不停地做循环(Busy loop)去拿队列里的可用更新数据,做出相应的响应,然后再继续下一次轮询... 将策略的实现与多线程细节隔离。交易策略的执行可能会用到多线程,但是较好的实践方式是将多线程的业务逻辑和策略的主逻辑进行隔离,一个策略需要尽可能在在自身逻辑上保持单线程。如果策略逻辑本身需要费心多线程的话(例如和其他策略频繁地交流),它的性能将变得比较差。 策略的输出——基本上是一堆指令(command),其中绝大多数是交易指令。这些交易指令基本上会被堆到一些队列容器里,然后——等等——得交给交易限制检查(limit checker)模块先做一番检查。不同策略发出的交易指令可能会有冲突或者重叠,所以如果能安排一个Order Execution Manager的模块来快速处理这些交易指令,可能是明智之举。经过筛查的交易指令最终将会被发回到网关(Gateway)模块,然后发往交易所。一般来说,一个策略不是很关心它生成的单条指令最终的执行结果,这是因为系统发出去的订单结果,包括市场对它的反应,肯定会第一时间反馈到行情更新上。当然Order Execution Manager可能会对发单执行情况做一些统计并作为信息输入的一部分回馈给某个策略。

性能评价

  • Hit rate,中文可能叫命中率。当你觉得市场上的行情报价有钱可赚的时候——打个比方,有人在以很便宜的价格卖某种期权——你就需要发出一个订单去吃掉对方的单。在你接收到这种利好行情的时候,别家也会接受到同样的信息,所以很有可能你有非常多的对手都想要吃掉这个人的便宜货。这时候hit rate就是衡量 实际成交的订单数(或者具体到多少手)/发出的订单数. 一般而言hit rate越高系统的性能越好,但是这个值跟你算的理论价格也有关系——如果你一直算偏了fair price,那么没人跟你抢单,hit rate也会出奇高;
  • Tick to Trade/Quote,即从接收到行情数据开始,直至发生交易时的时间间隔。一个性能强劲的系统,它的TTT/TTQ是非常低的。目前使用FPGA收发的策略,TTT在纳秒级

书目推荐

  • 《Effective C++》如果对C++了解不深,最好先读这本;
  • 《Effective Modern C++》跟上面一本是相同的作者,讲C++11新特性的种种;
  • 《C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond》C++模板元编程
  • 《C++ Templates: The Complete Guide》这本有侯捷的译本叫《C++ Template 全览》,英文读起来有点吃力
  • 《Flash Boys: A Wall Street Revolt》当小说看就行,讲高频交易的一些故事的
  • 《Options, Futures and Other Derivatives》中文名《期权、期货及其他衍生产品》偏教材的入门书籍,看完这个再看下一本
  • 《Option Volatility & Pricing: Advanced Trading Strategies and Techniques》作者: Sheldon Natenberg 经典绿皮书

标签: none

已有 2 条评论

  1. echo echo

    希望老哥能多多推荐一些金融方面的书 嘿嘿

    1. 金融的范围太广了...

添加新评论

所有评论将经过人工审核:)