编程语言
首页 > 编程语言> > 基于Java架构设计与开发

基于Java架构设计与开发

作者:互联网

关于撮合交易系统

 

撮合技术主要是从数据库撮合技术向内存撮合技术发展,这是因为数据库撮合技术越来越无法满足金融交易对于高可靠性、高性能、强安全性、可扩展性以及易维护性的需求。金融(币币)交易撮合系统中包括以下几个核心模块:

 

用户:终端用户委托报价与数量,生成订单发送至交易平台。

网关:负责收集用户订单,并将其派发给撮合引擎。

撮合引擎:交易系统中的核心部分,用于接收订单并根据业务逻辑实现订单 撮合同时生成交易记录,随后给予用户交易结果反馈。

数据库:用来存放交易过程中的订单和交易记录,实现数据持久化。

消息队列:一般用于订单消息的传输

关于技术选型

 

一个交易所平台的技术架构主要考虑安全性、分布式、易扩展、容错性、低延时、高并发等特性,以及熔断机制、服务注册和发现、消息服务、服务网关、安全认证、内存数据库、关系型数据库等各种选项,最终形成了如下技术选型:

 

 分布式基础进行架构SpringCloud与Dubbo之间二选一,由于SpringCloud更加知名,SpringCloud的程序员更好招聘,有利于系统的长期运维升级,而且SpringCloud是基于SpringBoot开发,比较有亲切感,所以选择了SpringCloud, 其实由于阿里系的强大影响,国内Dubbo使用更加广泛,不同的团队可以根据自己的情况选择。

引入Hystrix断路器作为容错保护模块,防止单个服务的故障,耗尽整个撮合系统容器的线程资源,避免分布式环境里大量级联失败。对通过第三方客户端访问依赖服务出现失败、拒绝、超时或短路时执行回退逻辑。

采用Eureka作为服务注册与发现中心,实现中间层服务,以达到负载均衡和中间层服务故障转移的目的。

服务网关Spring Cloud Gateway 与 Zuul 的选型,选择了Zuul,因为名字短一些。

引入SpringCloud Security安全认证模块用于构建安全的应用程序和服务,SpringCloud Security在Spring Boot和Spring Security OAuth2的基础上,可以快速创建和实现常见的安全认证方式,如单点登录,令牌中继和令牌交换等。

引入Redis作为内存数据库,兼做系统数据缓存和内存计算。

使用MySQL作为关系数据库,性能测试非常过关,而且对熟悉MYSQL的程序员非常友好。

消息队列中间件MQ采用了Kafka, 具有超高性能体现。

关于交易所架构设计

 

基于SpringCloud开发基于微服务架构的交易平台,首先需要对SpringCloud的基础架构有所了解,我们熟知的SpringCloud微服务架构如下图所示:

 

 

 

由于篇幅关系,本文就不对SpringCloud的技术架构进行详细解读了。

 

在SpringCloud这个优秀的微服务框架基础之上,如何构建一个交易系统呢?开源项目CoinExchange对交易所的架构做了如下架构设计:

 

 

 

将撮合交易引擎、API等拆分作为单独的服务,基于SpringCloud构建了一个精简的交易所架构。

 

部署图如下:

 

 

 

 

 

关于撮合交易引擎

 

采用内存撮合的方式进行,以Kafka做撮合订单信息传输,MongoDB持久化订单成交明细,MySQL记录订单总体成交。其中行情模块主要负责订单成交持久化、行情生成、行情推送等服务,包括:

 

K线数据,间隔分别为:1分钟、5分钟、15分钟、30分钟、1小时、1天、1周、1月

所有交易对的市场深度(market depth)数据

所有交易对的最新价格

最近成交的交易对

内存撮合交易支持的模式

 

限价订单与限价订单撮合

市价订单与限价订单撮合

限价订单与市价订单撮合

市价订单与市价订单撮合

撮合逻辑过程如下图所示:

 

 

 

示例代码如下:

 

  1 /**

  2 * 限价委托单与限价队列匹配

  3 * @param lpList 限价对手单队列

  4 * @param focusedOrder 交易订单

  5 */

  6 public void matchLimitPriceWithLPList(TreeMap<BigDecimal,MergeOrder> lpList, ExchangeOrder focusedOrder,boolean canEnterList){

  7 List<ExchangeTrade> exchangeTrades = new ArrayList<>();

  8 List<ExchangeOrder> completedOrders = new ArrayList<>();

  9 synchronized (lpList) {

 10 Iterator<Map.Entry<BigDecimal,MergeOrder>> mergeOrderIterator = lpList.entrySet().iterator();

 11 boolean exitLoop = false;

 12 while (!exitLoop && mergeOrderIterator.hasNext()) {

 13 Map.Entry<BigDecimal,MergeOrder> entry = mergeOrderIterator.next();

 14 MergeOrder mergeOrder = entry.getValue();

 15 Iterator<ExchangeOrder> orderIterator = mergeOrder.iterator();

 16 //买入单需要匹配的价格不大于委托价,否则退出

 17 if (focusedOrder.getDirection() == ExchangeOrderDirection.BUY && mergeOrder.getPrice().compareTo(focusedOrder.getPrice()) > 0) {

 18 break;

 19 }

 20 //卖出单需要匹配的价格不小于委托价,否则退出

 21 if (focusedOrder.getDirection() == ExchangeOrderDirection.SELL && mergeOrder.getPrice().compareTo(focusedOrder.getPrice()) < 0) {

 22 break;

 23 }

 24 while (orderIterator.hasNext()) {

 25 ExchangeOrder matchOrder = orderIterator.next();

 26 //处理匹配

 27 ExchangeTrade trade = processMatch(focusedOrder, matchOrder);

 28 exchangeTrades.add(trade);

 29 //判断匹配单是否完成

 30 if (matchOrder.isCompleted()) {

 31 //当前匹配的订单完成交易,删除该订单

 32 orderIterator.remove();

 33 completedOrders.add(matchOrder);

 34 }

 35 //判断交易单是否完成

 36 if (focusedOrder.isCompleted()) {

 37 //交易完成

 38 completedOrders.add(focusedOrder);

 39 //退出循环

 40 exitLoop = true;

 41 break;

 42 }

 43 }

 44 if(mergeOrder.size() == 0){

 45 mergeOrderIterator.remove();

 46 }

 47 }

 48 }

 49 //如果还没有交易完,订单压入列表中

 50 if (focusedOrder.getTradedAmount().compareTo(focusedOrder.getAmount()) < 0 && canEnterList) {

 51 addLimitPriceOrder(focusedOrder);

 52 }

 53 //每个订单的匹配批量推送

 54 handleExchangeTrade(exchangeTrades);

 55 if(completedOrders.size() > 0){

 56 orderCompleted(completedOrders);

 57 TradePlate plate = focusedOrder.getDirection() == ExchangeOrderDirection.BUY ? sellTradePlate : buyTradePlate;

 58 sendTradePlateMessage(plate);

 59 }

 60 }

 61 

 62 /**

 63 * 限价委托单与市价队列匹配

 64 * @param mpList 市价对手单队列

 65 * @param focusedOrder 交易订单

 66 */

 67 public void matchLimitPriceWithMPList(LinkedList<ExchangeOrder> mpList,ExchangeOrder focusedOrder){

 68 List<ExchangeTrade> exchangeTrades = new ArrayList<>();

 69 List<ExchangeOrder> completedOrders = new ArrayList<>();

 70 synchronized (mpList) {

 71 Iterator<ExchangeOrder> iterator = mpList.iterator();

 72 while (iterator.hasNext()) {

 73 ExchangeOrder matchOrder = iterator.next();

 74 ExchangeTrade trade = processMatch(focusedOrder, matchOrder);

 75 logger.info(">>>>>"+trade);

 76 if(trade != null){

 77 exchangeTrades.add(trade);

 78 }

 79 //判断匹配单是否完成,市价单amount为成交量

 80 if(matchOrder.isCompleted()){

 81 iterator.remove();

 82 completedOrders.add(matchOrder);

 83 }

 84 //判断吃单是否完成,判断成交量是否完成

 85 if (focusedOrder.isCompleted()) {

 86 //交易完成

 87 completedOrders.add(focusedOrder);

 88 //退出循环

 89 break;

 90 }

 91 }

 92 }

 93 //如果还没有交易完,订单压入列表中

 94 if (focusedOrder.getTradedAmount().compareTo(focusedOrder.getAmount()) < 0) {

 95 addLimitPriceOrder(focusedOrder);

 96 }

 97 //每个订单的匹配批量推送

 98 handleExchangeTrade(exchangeTrades);

 99 orderCompleted(completedOrders);

100 }

101 

102 

103 /**

104 * 市价委托单与限价对手单列表交易

105 * @param lpList 限价对手单列表

106 * @param focusedOrder 待交易订单

107 */

108 public void matchMarketPriceWithLPList(TreeMap<BigDecimal,MergeOrder> lpList, ExchangeOrder focusedOrder){

109 List<ExchangeTrade> exchangeTrades = new ArrayList<>();

110 List<ExchangeOrder> completedOrders = new ArrayList<>();

111 synchronized (lpList) {

112 Iterator<Map.Entry<BigDecimal,MergeOrder>> mergeOrderIterator = lpList.entrySet().iterator();

113 boolean exitLoop = false;

114 while (!exitLoop && mergeOrderIterator.hasNext()) {

115 Map.Entry<BigDecimal,MergeOrder> entry = mergeOrderIterator.next();

116 MergeOrder mergeOrder = entry.getValue();

117 Iterator<ExchangeOrder> orderIterator = mergeOrder.iterator();

118 while (orderIterator.hasNext()) {

119 ExchangeOrder matchOrder = orderIterator.next();

120 //处理匹配

121 ExchangeTrade trade = processMatch(focusedOrder, matchOrder);

122 if (trade != null) {

123 exchangeTrades.add(trade);

124 }

125 //判断匹配单是否完成

126 if (matchOrder.isCompleted()) {

127 //当前匹配的订单完成交易,删除该订单

128 orderIterator.remove();

129 completedOrders.add(matchOrder);

130 }

131 //判断焦点订单是否完成

132 if (focusedOrder.isCompleted()) {

133 completedOrders.add(focusedOrder);

134 //退出循环

135 exitLoop = true;

136 break;

137 }

138 }

139 if(mergeOrder.size() == 0){

140 mergeOrderIterator.remove();

141 }

142 }

143 }

144 //如果还没有交易完,订单压入列表中,市价买单按成交量算

145 if (focusedOrder.getDirection() == ExchangeOrderDirection.SELL&&focusedOrder.getTradedAmount().compareTo(focusedOrder.getAmount()) < 0

146 || focusedOrder.getDirection() == ExchangeOrderDirection.BUY&& focusedOrder.getTurnover().compareTo(focusedOrder.getAmount()) < 0) {

147 addMarketPriceOrder(focusedOrder);

148 }

149 //每个订单的匹配批量推送

150 handleExchangeTrade(exchangeTrades);

151 if(completedOrders.size() > 0){

152 orderCompleted(completedOrders);

153 TradePlate plate = focusedOrder.getDirection() == ExchangeOrderDirection.BUY ? sellTradePlate : buyTradePlate;

154 sendTradePlateMessage(plate);

155 }

156 }

 

 

关于区块链钱包对接

每个币种对应不同的数据访问方式,大部分区块链项目的钱包操作方式是相同的或十分相似的,比如BTC、LTC、BCH、BSV、BCD等比特币衍生币,其API操作方式几乎一样;再比如ETH,当你掌握一个合约币种的操作,其他基于ETH发行的数字货币的操作方式几乎一样。所以,基本上当你花时间弄懂了一个,就懂了一堆币种。

 

本项目使用的钱包操作方案也是不同的,也尽可能的为大家展示了不同用法:

 

如BTC、USDT,使用的自建全节点,现在差不多需要300G硬盘空间;

如ETH,使用的是自建轻节点(参考文章),因为全节点需要硬盘空间太大;

如BCH、BSV等,使用的是第三方区块链浏览器获取数据。

标签:撮合,架构设计,基于,Java,completedOrders,SpringCloud,matchOrder,订单,focusedOrder
来源: https://www.cnblogs.com/uveidve/p/12664499.html