撮合引擎开发:开篇


撮合引擎开发:开篇数据库

撮合引擎开发:MVP版本服务器

撮合引擎开发:数据结构设计微信

撮合引擎开发:对接黑箱数据结构

撮合引擎开发:解密黑箱流程架构


前言

自从有人在微信群里开价5万求购Golang版的撮合引擎以后,我就想本身开发一款,毕竟,以个人经验来讲,开发个高性能的撮合引擎并没什么难度。并发

说干就干,因而,利用业余时间慢慢开发出了一款Golang版的高性能撮合引擎,前先后后花了大概一个月的时间。再想一想本身很久没更新文章了,个人我的IP都已经生锈了,也应该发大招磨一磨了。所以决定,干脆就以连载的方式,分享下我是如何设计与实现这款价值超5万的撮合引擎的。负载均衡

原本,想发成掘金小册,收点稿费,毕竟这是个具备很大商业价值的软件,但问了掘金的人员,他们目前不接收这类主题。最终决定免费发布,还能够多发几个渠道,说不定还能给我多带来些关注量。post

好了,下面开始进入撮合引擎系列的正题。性能

撮合引擎简介

撮合引擎是全部撮合交易系统的核心组件,不论是股票交易系统——包括现货交易、期货交易、期权交易等,仍是数字货币交易系统——包括币币交易、合约交易、杠杆交易等,以及各类不一样的贵金属交易系统、大宗商品交易系统等,虽然各类不一样交易系统的交易标的不一样,但只要都是采用撮合交易模式,都离不开撮合引擎。设计

撮合引擎是能够具备通用性的,一套具备通用性的撮合引擎实现理论上能够应用到任何撮合交易系统中,而无需作任何代码上的调整。便是说,同一套撮合引擎实现,既能够应用在股票交易系统,也能够应用在数字货币交易系统,能够用于现货交易,也能够用于合约交易等。

那么,一套具备通用性的撮合引擎应该具有哪些功能呢?肯定该问题的答案以前,咱们先简单梳理一下一个完整的交易流程是怎样的?通常会包括如下步骤:

  1. 系统开放某个交易标的的交易功能。
  2. 用户提交该交易标的的买卖申报,即委托单
  3. 系统验证委托单是否有效,包括交易标的是否处于可交易的状态、订单的价格和数量是否符合要求等。
  4. 肯定该委托单的**挂单(Maker)费率和吃单(Taker)**费率。
  5. 检查用户的资产帐户状况,包括帐户状态是否交易受限,是否有足够资金用于下单等。
  6. 将详细的委托单数据持久化到数据库,并冻结用户帐户中相应数量的资金。
  7. 将委托单进行撮合处理,即在**交易委托帐本(OrderBook)**中寻找能与该委托单匹配成交的订单,匹配的结果多是:所有成交、部分红交或无匹配。所有成交或部分红交时,可能在交易委托帐本中存在一个或多个匹配的订单,即会产生一条或多条成交记录。当无匹配或部分红交时,委托单的部分数据包括剩余未成交的数量会暂时保存到交易委托帐本中,等待与后续的委托单匹配撮合。
  8. 将撮合产生的成交记录持久化到数据库,并根据历史成交记录生成市场数据,如K线数据、今日涨跌幅等。
  9. 更新数据库中全部成交订单的委托单数据,以及更新订单用户的资产帐户余额。
  10. 将更新的订单数据、市场数据等发送给到前台。

整个交易流程中涉及到多个服务,包括用户服务、帐户服务、订单服务、撮合服务、市场数据服务等。其中,只有第7步是撮合引擎处理的。从单一职责原则来讲,撮合引擎就应该只作一件事,那就是负责撮合订单。撮合以前的委托单持久化、冻结资金等,以及撮合以后生成K线数据等,都不该该属于撮合引擎的职责。

撮合竞价方式

撮合竞价方式通常有两种,一是集合竞价,二是连续竞价。股票交易系统通常会在不一样交易时间段采用不一样的竞价方式,好比在开盘或收盘时采用集合竞价,从而产生开盘价收盘价,其他时间采用连续竞价。而大多数字货币交易系统则没有集合竞价,只有连续竞价,开盘价通常是在开始交易以前就设定好的。

集合竞价

所谓集合竞价,是指对一段时间内接收的买卖委托单一次性集中撮合的竞价方式。以深沪的股票交易系统为例,在每一个交易日的 9:15~9:25 期间是集合竞价时间。在该时间段内,系统陆续接收到的委托单不会即时成交,而是先将全部委托单按照价格优先、时间优先的原则排序,并在此基础上,找出一个基准价格,使它能同时知足如下三个条件:

  1. 可实现最大成交量的价格;
  2. 高于该价格的买单与低于该价格的卖单能所有成交的价格;
  3. 与该价格相同的买方或卖方至少有一方所有成交的价格。

在 9:25 分结束的时候,该基准价格就被肯定为成交价格,全部高于该价格的买单与低于该价格的卖单都将以该价格成交。未能成交的委托单,则自动转入连续竞价。

不过,若是知足以上三个条件的价格存在两个或两个以上呢?对此,深交所和上交所的处理方案有所不一样,深交所会取距前收盘价最近的价格为成交价,而上交所则取使未成交量最小的价格为成交价,若是未成交量最小的价格仍不止一个,则取中间价为成交价。

集合竞价的主要目的就是为了肯定开盘价或收盘价。

连续竞价

所谓连续竞价,也是咱们所熟悉的竞价方式,是指对买卖委托单逐笔连续撮合的竞价方式。用户的挂单,只要知足成交条件,就能即时成交。而集合竞价,则要等到最后一刻才会成交。

连续竞价时,依然要知足价格优先、时间优先的成交原则:

  1. 价格优先:买单则价格较高者能优先成交,卖单则是价格较低者能优先成交。
  2. 时间优先:买卖方向和价格相同的委托单,先申报的委托单会比后申报的委托单优先成交。

另外,买入价必须大于或等于卖出价才能撮合成交。当买入价等于卖出价时,成交价就是买入价或卖出价。当买入价大于卖出价时,则还要参考前一笔成交价来肯定最新成交价。假设买入价为 B,卖出价为 S,前一笔成交价为 P,最新成交价为 N,那么:

  • 若是 P >= B,则 N = B
  • 若是 P <= S,则 N = S
  • 若是 B > P > S,则 N = P

一套通用的撮合引擎应该两种竞价方式都支持,但对于同一交易标的来讲,两种竞价方式不能同时进行,所以设计上须要考虑如何在两种竞价方式之间切换,具体的实现思路在后续章节咱们再展开来说。

质量需求

咱们的撮合引擎除了要知足以上所说的功能需求,还应该知足一些质量需求,尤为对可用性可伸缩性性能的要求较高。另外,为了达到通用,也要知足可复用性的需求。

先说下可复用性,咱们指望的是该撮合引擎既能用于股票交易系统,也能用于数字货币交易系统,既能用于币币交易,也能用于合约交易。所以,该撮合引擎要避免引入与具体系统强相关的业务逻辑,以增强它的可复用性。

再看看性能,要衡量一个撮合引擎的性能,就看它处理每一个交易对的 TPS 有多高,即每秒钟能处理多少笔相同交易对的委托单。之前,基于数据库的撮合技术,TPS 通常只有10笔/秒。而如今基本都是采用内存撮合技术,TPS 很容易就能达到1000笔/秒,若是使用独占的高性能服务器,1万笔/秒甚至更高的 TPS 都不难达到。

接着谈谈可伸缩性,咱们的每个撮合引擎既能够同时处理多个交易标的,也能够只处理单个交易标的。当交易标的和并发量增多的时候,能够增长服务器,部署成撮合引擎集群,分别用来处理不一样的交易标的,从而可以实现负载均衡。

最后聊聊可用性,高可用主要体如今两点,一是故障率要低,二是对故障维修的时间要短。要下降故障率,那撮合引擎就须要有较高的健壮性,对于可能致使引擎出故障的各类异常状况要考虑好并设计好解决方案。另外,还能够采用多机热备份技术来提升可用性,并且要保证互备服务器之间的数据一致,那就须要引入内存状态机复制方案,实现上会复杂不少。

不过,咱们并不是一会儿就要达到很高的质量要求,由于要求越高,其架构和实现会越复杂。咱们能够先从简单的版本开始,而后不断升级迭代。

小结

咱们目的是实现一套通用的撮合引擎,要支持集合竞价和连续竞价,还要实现一些质量需求,提升系统的可复用性、性能、可伸缩性、可用性等。后续章节会对这些需求不断深刻探讨其设计与实现。另外,咱们将采用不断升级迭代的方式来设计和实现多个版本的撮合引擎。

留两个思考题:

  1. 集合竞价结束的时候,若是不存在符合那三个条件的基准价格,那开盘价又将如何肯定?
  2. 对于单个交易对,是否可经过横向增长服务器的方式提升其性能?

做者的我的博客

相关文章
相关标签/搜索