├── engine ├── src │ ├── test │ │ └── java │ │ │ ├── testConnection.java │ │ │ ├── testEngineConfig.java │ │ │ ├── testMyBatis.java │ │ │ └── testBodyCodec.java │ └── main │ │ ├── resources │ │ ├── jdbc.properties │ │ ├── engine.properties │ │ ├── c3p0-config.xml │ │ ├── com │ │ │ └── star │ │ │ │ └── engine │ │ │ │ └── mapper │ │ │ │ └── DBQuery.xml │ │ └── mybatis-config.xml │ │ └── java │ │ ├── thirdpart │ │ ├── bus │ │ │ ├── api │ │ │ │ └── BusSender.java │ │ │ └── impl │ │ │ │ └── MQTTBusSenderImpl.java │ │ ├── fetchserv │ │ │ └── api │ │ │ │ └── FetchService.java │ │ ├── checksum │ │ │ ├── api │ │ │ │ └── CheckSum.java │ │ │ └── impl │ │ │ │ └── CheckSumImpl.java │ │ ├── codec │ │ │ ├── api │ │ │ │ ├── MsgCodec.java │ │ │ │ └── BodyCodec.java │ │ │ └── impl │ │ │ │ ├── BodyCodecImpl.java │ │ │ │ └── MsgCodecImpl.java │ │ ├── bean │ │ │ ├── CmdPack.java │ │ │ ├── CommonMsg.java │ │ │ └── MsgConstants.java │ │ ├── hq │ │ │ ├── MatchData.java │ │ │ └── L1MarketData.java │ │ ├── order │ │ │ ├── OrderType.java │ │ │ ├── OrderCmd.java │ │ │ ├── OrderDirection.java │ │ │ ├── OrderStatus.java │ │ │ └── CmdType.java │ │ └── tcp │ │ │ └── TcpDirectSender.java │ │ └── com │ │ └── star │ │ └── engine │ │ ├── handler │ │ ├── BaseHandler.java │ │ ├── exception │ │ │ └── DisruptorExceptionHandler.java │ │ ├── match │ │ │ └── StockMatchHandler.java │ │ └── risk │ │ │ └── ExistRiskHandler.java │ │ ├── EngineStartup.java │ │ ├── mapper │ │ └── DBQuery.java │ │ ├── bean │ │ ├── RbCmdFactory.java │ │ ├── orderbook │ │ │ ├── MatchEvent.java │ │ │ ├── api │ │ │ │ ├── OrderBook.java │ │ │ │ └── OrderBucket.java │ │ │ └── Order.java │ │ ├── command │ │ │ ├── RbCmd.java │ │ │ └── CmdResultCode.java │ │ └── DBUtil.java │ │ └── core │ │ ├── EngineApi.java │ │ └── EngineCore.java └── dependency-reduced-pom.xml ├── cfront ├── babel.config.js ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── assets │ │ ├── img │ │ │ ├── bg.png │ │ │ ├── sq.png │ │ │ ├── img.jpg │ │ │ ├── logo.png │ │ │ ├── show.png │ │ │ └── login-bg.jpg │ │ ├── logo.png │ │ ├── icon │ │ │ ├── iconfont.eot │ │ │ ├── iconfont.ttf │ │ │ └── iconfont.woff │ │ └── css │ │ │ ├── icon.css │ │ │ ├── theme-green │ │ │ ├── fonts │ │ │ │ ├── element-icons.ttf │ │ │ │ └── element-icons.woff │ │ │ └── color-green.css │ │ │ └── color-dark.css │ ├── views │ │ ├── About.vue │ │ ├── TradeQuery.vue │ │ ├── Dashboard.vue │ │ ├── OrderQuery.vue │ │ ├── HisOrderQuery.vue │ │ ├── 404.vue │ │ ├── Buy.vue │ │ ├── Sell.vue │ │ ├── PwdSetting.vue │ │ └── Home.vue │ ├── api │ │ ├── transferApi.js │ │ ├── frontConfig.js │ │ ├── constants.js │ │ ├── loginApi.js │ │ ├── formatter.js │ │ ├── orderApi.js │ │ └── axiosCommon.js │ ├── App.vue │ ├── store │ │ └── index.js │ ├── main.js │ ├── components │ │ ├── HelloWorld.vue │ │ └── CodeInput.vue │ ├── background.js │ └── router │ │ └── index.js ├── vue.config.js ├── README.md ├── jsconfig.json ├── .gitignore └── package.json ├── .gitignore ├── counter └── src │ └── main │ ├── java │ ├── com │ │ └── star │ │ │ └── counter │ │ │ ├── service │ │ │ ├── api │ │ │ │ ├── StockService.java │ │ │ │ ├── BalanceService.java │ │ │ │ ├── PosiService.java │ │ │ │ ├── TradeService.java │ │ │ │ ├── AccountService.java │ │ │ │ └── OrderService.java │ │ │ └── impl │ │ │ │ ├── StockServiceImpl.java │ │ │ │ ├── BalanceServiceImpl.java │ │ │ │ ├── PosiServiceImpl.java │ │ │ │ └── TradeServiceImpl.java │ │ │ ├── consumer │ │ │ ├── Addr.java │ │ │ └── MarketDataConsumer.java │ │ │ ├── bean │ │ │ ├── StockInfo.java │ │ │ ├── res │ │ │ │ ├── CaptchaRes.java │ │ │ │ └── CounterRes.java │ │ │ ├── Account.java │ │ │ ├── PosiInfo.java │ │ │ ├── TradeInfo.java │ │ │ └── OrderInfo.java │ │ │ ├── cache │ │ │ ├── CacheType.java │ │ │ ├── RedisStringCache.java │ │ │ └── StockCache.java │ │ │ ├── CounterApplication.java │ │ │ ├── mapper │ │ │ ├── StockMapper.java │ │ │ ├── BalanceMapper.java │ │ │ ├── TradeMapper.java │ │ │ ├── OrderMapper.java │ │ │ ├── AccountMapper.java │ │ │ └── PosiMapper.java │ │ │ ├── util │ │ │ ├── IDConverter.java │ │ │ └── TimeformatUtil.java │ │ │ ├── property │ │ │ └── CounterProperty.java │ │ │ ├── config │ │ │ ├── IdWorkerConfig.java │ │ │ ├── SenderConfig.java │ │ │ ├── CounterConfig.java │ │ │ ├── GatewayConfig.java │ │ │ └── WebSocketConfig.java │ │ │ ├── controller │ │ │ └── GlobalExceptionHandler.java │ │ │ ├── filter │ │ │ └── SessionCheckFilter.java │ │ │ └── gateway │ │ │ └── MsgTrans.java │ └── thirdpart │ │ ├── checksum │ │ ├── api │ │ │ └── CheckSum.java │ │ └── impl │ │ │ └── CheckSumImpl.java │ │ ├── codec │ │ ├── api │ │ │ ├── MsgCodec.java │ │ │ └── BodyCodec.java │ │ └── impl │ │ │ ├── BodyCodecImpl.java │ │ │ └── MsgCodecImpl.java │ │ ├── hq │ │ ├── MatchData.java │ │ └── L1MarketData.java │ │ ├── order │ │ ├── OrderType.java │ │ ├── OrderCmd.java │ │ ├── OrderDirection.java │ │ ├── OrderStatus.java │ │ └── CmdType.java │ │ └── bean │ │ ├── CommonMsg.java │ │ └── MsgConstants.java │ └── resources │ ├── com │ └── star │ │ └── counter │ │ └── mapper │ │ ├── StockMapper.xml │ │ ├── BalanceMapper.xml │ │ ├── TradeMapper.xml │ │ ├── AccountMapper.xml │ │ ├── PosiMapper.xml │ │ └── OrderMapper.xml │ └── application.yml ├── seq ├── src │ └── main │ │ ├── java │ │ ├── thirdpart │ │ │ ├── fetchserv │ │ │ │ └── api │ │ │ │ │ └── FetchService.java │ │ │ ├── checksum │ │ │ │ ├── api │ │ │ │ │ └── CheckSum.java │ │ │ │ └── impl │ │ │ │ │ └── CheckSumImpl.java │ │ │ ├── codec │ │ │ │ ├── api │ │ │ │ │ ├── MsgCodec.java │ │ │ │ │ └── BodyCodec.java │ │ │ │ └── impl │ │ │ │ │ ├── BodyCodecImpl.java │ │ │ │ │ └── MsgCodecImpl.java │ │ │ ├── bean │ │ │ │ ├── CmdPack.java │ │ │ │ ├── CommonMsg.java │ │ │ │ └── MsgConstants.java │ │ │ └── order │ │ │ │ ├── OrderType.java │ │ │ │ ├── OrderCmd.java │ │ │ │ ├── OrderDirection.java │ │ │ │ ├── OrderStatus.java │ │ │ │ └── CmdType.java │ │ └── com │ │ │ └── star │ │ │ └── seq │ │ │ ├── SeqStartup1.java │ │ │ ├── SeqStartup2.java │ │ │ ├── SeqStartup3.java │ │ │ └── bean │ │ │ └── Node.java │ │ └── resources │ │ ├── seq1.properties │ │ ├── seq2.properties │ │ └── seq3.properties └── dependency-reduced-pom.xml ├── gateway ├── src │ ├── main │ │ ├── java │ │ │ ├── thirdpart │ │ │ │ ├── fetchserv │ │ │ │ │ └── api │ │ │ │ │ │ └── FetchService.java │ │ │ │ ├── checksum │ │ │ │ │ ├── api │ │ │ │ │ │ └── CheckSum.java │ │ │ │ │ └── impl │ │ │ │ │ │ └── CheckSumImpl.java │ │ │ │ ├── codec │ │ │ │ │ ├── api │ │ │ │ │ │ └── BodyCodec.java │ │ │ │ │ └── impl │ │ │ │ │ │ └── BodyCodecImpl.java │ │ │ │ ├── uuid │ │ │ │ │ └── GudyUuid.java │ │ │ │ ├── order │ │ │ │ │ ├── OrderType.java │ │ │ │ │ ├── OrderCmd.java │ │ │ │ │ ├── OrderDirection.java │ │ │ │ │ ├── OrderStatus.java │ │ │ │ │ └── CmdType.java │ │ │ │ └── bean │ │ │ │ │ ├── CommonMsg.java │ │ │ │ │ └── MsgConstants.java │ │ │ └── com │ │ │ │ └── star │ │ │ │ └── gateway │ │ │ │ ├── GatewayStartup.java │ │ │ │ ├── container │ │ │ │ └── OrderCmdContainer.java │ │ │ │ ├── handler │ │ │ │ └── MsgHandler.java │ │ │ │ └── config │ │ │ │ └── GatewayConfig.java │ │ └── resources │ │ │ └── gateway.xml │ └── test │ │ └── java │ │ ├── UuidTest.java │ │ ├── CheckSumTest.java │ │ └── CodecTest.java └── dependency-reduced-pom.xml └── mqtt ├── src └── main │ └── java │ └── com │ └── star │ └── mqtt │ └── MQTTServerStart.java └── pom.xml /engine/src/test/java/testConnection.java: -------------------------------------------------------------------------------- 1 | public class testConnection { 2 | } 3 | -------------------------------------------------------------------------------- /cfront/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /cfront/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/public/favicon.ico -------------------------------------------------------------------------------- /cfront/src/assets/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/img/bg.png -------------------------------------------------------------------------------- /cfront/src/assets/img/sq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/img/sq.png -------------------------------------------------------------------------------- /cfront/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/logo.png -------------------------------------------------------------------------------- /cfront/src/assets/img/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/img/img.jpg -------------------------------------------------------------------------------- /cfront/src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/img/logo.png -------------------------------------------------------------------------------- /cfront/src/assets/img/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/img/show.png -------------------------------------------------------------------------------- /cfront/src/assets/icon/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/icon/iconfont.eot -------------------------------------------------------------------------------- /cfront/src/assets/icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/icon/iconfont.ttf -------------------------------------------------------------------------------- /cfront/src/assets/img/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/img/login-bg.jpg -------------------------------------------------------------------------------- /cfront/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /cfront/src/assets/css/icon.css: -------------------------------------------------------------------------------- 1 | 2 | [class*=" el-icon-lx"], [class^=el-icon-lx] { 3 | font-family: lx-iconfont!important; 4 | } -------------------------------------------------------------------------------- /cfront/src/assets/icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/icon/iconfont.woff -------------------------------------------------------------------------------- /cfront/vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | module.exports = defineConfig({ 3 | transpileDependencies: true 4 | }) 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /counter/.idea/ 3 | /counter/target/ 4 | /counter/counter.iml 5 | /counter/src/test/ 6 | /gateway/target/ 7 | /gateway/src/test/ 8 | /seq/src/test/ 9 | -------------------------------------------------------------------------------- /cfront/src/assets/css/theme-green/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/css/theme-green/fonts/element-icons.ttf -------------------------------------------------------------------------------- /cfront/src/assets/css/theme-green/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crazyzym/xingxing-match-trading/HEAD/cfront/src/assets/css/theme-green/fonts/element-icons.woff -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/api/StockService.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.api; 2 | 3 | public interface StockService { 4 | 5 | // getAllStockInfo(); 6 | } 7 | -------------------------------------------------------------------------------- /engine/src/main/resources/jdbc.properties: -------------------------------------------------------------------------------- 1 | jdbc.driver=com.mysql.cj.jdbc.Driver 2 | jdbc.url=jdbc:mysql://47.113.188.108:3306/match_trading?serverTimezone=Asia/Shanghai 3 | jdbc.username=root 4 | jdbc.password=Zym.141592 -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/bus/api/BusSender.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bus.api; 2 | 3 | import thirdpart.bean.CommonMsg; 4 | 5 | public interface BusSender { 6 | 7 | void startUp(); 8 | 9 | void publish(CommonMsg commonMsg); 10 | } 11 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/fetchserv/api/FetchService.java: -------------------------------------------------------------------------------- 1 | package thirdpart.fetchserv.api; 2 | 3 | import thirdpart.order.OrderCmd; 4 | 5 | import java.util.List; 6 | 7 | public interface FetchService { 8 | List fetchData(); 9 | } 10 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/fetchserv/api/FetchService.java: -------------------------------------------------------------------------------- 1 | package thirdpart.fetchserv.api; 2 | 3 | import thirdpart.order.OrderCmd; 4 | 5 | import java.util.List; 6 | 7 | public interface FetchService { 8 | List fetchData(); 9 | } 10 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/fetchserv/api/FetchService.java: -------------------------------------------------------------------------------- 1 | package thirdpart.fetchserv.api; 2 | 3 | import thirdpart.order.OrderCmd; 4 | 5 | import java.util.List; 6 | 7 | public interface FetchService { 8 | List fetchData(); 9 | } 10 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/handler/BaseHandler.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.handler; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | import com.star.engine.bean.command.RbCmd; 5 | 6 | public abstract class BaseHandler implements EventHandler { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/checksum/api/CheckSum.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.api; 2 | 3 | public interface CheckSum { 4 | 5 | /** 6 | * 得到校验和 7 | * @param data 数据的字节流 8 | * @return 校验和 9 | */ 10 | byte getCheckSum(byte[] data); 11 | } 12 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/checksum/api/CheckSum.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.api; 2 | 3 | public interface CheckSum { 4 | 5 | /** 6 | * 得到校验和 7 | * @param data 数据的字节流 8 | * @return 校验和 9 | */ 10 | byte getCheckSum(byte[] data); 11 | } 12 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/checksum/api/CheckSum.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.api; 2 | 3 | public interface CheckSum { 4 | 5 | /** 6 | * 得到校验和 7 | * @param data 数据的字节流 8 | * @return 校验和 9 | */ 10 | byte getCheckSum(byte[] data); 11 | } 12 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/checksum/api/CheckSum.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.api; 2 | 3 | public interface CheckSum { 4 | 5 | /** 6 | * 得到校验和 7 | * @param data 数据的字节流 8 | * @return 校验和 9 | */ 10 | byte getCheckSum(byte[] data); 11 | } 12 | -------------------------------------------------------------------------------- /cfront/src/api/transferApi.js: -------------------------------------------------------------------------------- 1 | import {reqRealEndAsync} from './axiosCommon'; 2 | 3 | import {config} from './frontConfig' 4 | 5 | export const queryTransfer = (params,callback) =>{ 6 | return reqRealEndAsync("post",config.real_domain, 7 | '/api/transferquery',params,callback); 8 | }; -------------------------------------------------------------------------------- /engine/src/main/resources/engine.properties: -------------------------------------------------------------------------------- 1 | id=1003 2 | 3 | # multicast(order) 4 | #orderrecvip=230.0.0.1 5 | orderrecvip=239.0.0.1 6 | orderrecvport=1234 7 | 8 | # seq urls 9 | sequrllist=127.0.0.1:8891,127.0.0.1:8892,127.0.0.1:8893 10 | 11 | # pub hq 12 | pubip=127.0.0.1 13 | pubport=1883 -------------------------------------------------------------------------------- /gateway/src/main/resources/gateway.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1001 6 | 7 | 8 | 8091 9 | 10 | 11 | 8890 12 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/api/BalanceService.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.api; 2 | 3 | public interface BalanceService { 4 | 5 | Long getBalanceByUid(long uid); 6 | 7 | void addBalance(long uid, long balance); 8 | 9 | void minusBalance(long uid, long balance); 10 | } 11 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/impl/StockServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.impl; 2 | 3 | import com.star.counter.service.api.StockService; 4 | import org.springframework.stereotype.Service; 5 | 6 | @Service 7 | public class StockServiceImpl implements StockService { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/codec/api/MsgCodec.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.api; 2 | 3 | import io.vertx.core.buffer.Buffer; 4 | import thirdpart.bean.CommonMsg; 5 | 6 | public interface MsgCodec { 7 | 8 | Buffer encodeToBuffer(CommonMsg msg); 9 | 10 | CommonMsg decodeFromBuffer(Buffer buffer); 11 | } 12 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/codec/api/MsgCodec.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.api; 2 | 3 | import io.vertx.core.buffer.Buffer; 4 | import thirdpart.bean.CommonMsg; 5 | 6 | public interface MsgCodec { 7 | 8 | Buffer encodeToBuffer(CommonMsg msg); 9 | 10 | CommonMsg decodeFromBuffer(Buffer buffer); 11 | } 12 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/codec/api/MsgCodec.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.api; 2 | 3 | import io.vertx.core.buffer.Buffer; 4 | import thirdpart.bean.CommonMsg; 5 | 6 | public interface MsgCodec { 7 | 8 | Buffer encodeToBuffer(CommonMsg msg); 9 | 10 | CommonMsg decodeFromBuffer(Buffer buffer); 11 | } 12 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/consumer/Addr.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.consumer; 2 | 3 | public class Addr { 4 | 5 | // 成交变动终端推送地址 6 | public final static String TRADE_NOTIFY_ADDR_PREFIX = "tradechange-"; 7 | 8 | // 委托变动终端推送 9 | public final static String ORDER_NOTIFY_ADDR_PREFIX = "orderchange-"; 10 | } 11 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/bean/StockInfo.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.bean; 2 | 3 | import lombok.*; 4 | 5 | @AllArgsConstructor 6 | @NoArgsConstructor 7 | @Data 8 | @ToString 9 | @EqualsAndHashCode 10 | public class StockInfo { 11 | 12 | private int code; 13 | private String name; 14 | private String abbrName; 15 | } 16 | -------------------------------------------------------------------------------- /cfront/src/api/frontConfig.js: -------------------------------------------------------------------------------- 1 | export const config = { 2 | 3 | //后台服务地址 4 | // real_domain: "http://47.113.188.108:8090", 5 | real_domain: "http://127.0.0.1:8090", 6 | 7 | real_ws_remote: { 8 | // host: "47.113.188.108", 9 | host: "127.0.0.1", 10 | port: 8501, 11 | path: "/eventbus/" 12 | }, 13 | 14 | } -------------------------------------------------------------------------------- /cfront/README.md: -------------------------------------------------------------------------------- 1 | # cfront 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /gateway/src/test/java/UuidTest.java: -------------------------------------------------------------------------------- 1 | import thirdpart.uuid.GudyUuid; 2 | 3 | public class UuidTest { 4 | 5 | public static void main(String[] args) { 6 | GudyUuid uuid = GudyUuid.getInstance(); 7 | uuid.init(0, 0); 8 | for (int i = 0; i < 1000; i++) { 9 | System.out.println(uuid.getUUID()); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /seq/src/main/resources/seq1.properties: -------------------------------------------------------------------------------- 1 | # raft 2 | datapath=/usr/matchtrading/logs/server1 3 | serveurl=127.0.0.1:8891 4 | serverlist=127.0.0.1:8891,127.0.0.1:8892,127.0.0.1:8893 5 | 6 | # gateways 7 | # bolt stands for the RPC protocol 8 | fetchurls=bolt://127.0.0.1:8890; 9 | 10 | # multicast 11 | #multicastip=230.0.0.1 12 | multicastip=239.0.0.1 13 | multicastport=1234 -------------------------------------------------------------------------------- /seq/src/main/resources/seq2.properties: -------------------------------------------------------------------------------- 1 | # raft 2 | datapath=/usr/matchtrading/logs/server2 3 | serveurl=127.0.0.1:8892 4 | serverlist=127.0.0.1:8891,127.0.0.1:8892,127.0.0.1:8893 5 | 6 | # gateways 7 | # bolt stands for the RPC protocol 8 | fetchurls=bolt://127.0.0.1:8890; 9 | 10 | # multicast 11 | #multicastip=230.0.0.1 12 | multicastip=239.0.0.1 13 | multicastport=1234 -------------------------------------------------------------------------------- /seq/src/main/resources/seq3.properties: -------------------------------------------------------------------------------- 1 | # raft 2 | datapath=/usr/matchtrading/logs/server3 3 | serveurl=127.0.0.1:8893 4 | serverlist=127.0.0.1:8891,127.0.0.1:8892,127.0.0.1:8893 5 | 6 | # gateways 7 | # bolt stands for the RPC protocol 8 | fetchurls=bolt://127.0.0.1:8890; 9 | 10 | # multicast 11 | #multicastip=230.0.0.1 12 | multicastip=239.0.0.1 13 | multicastport=1234 -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/bean/res/CaptchaRes.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.bean.res; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class CaptchaRes { 11 | 12 | private String id; 13 | private String imageBase64; 14 | } 15 | -------------------------------------------------------------------------------- /cfront/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cfront/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | 25 | #Electron-builder output 26 | /dist_electron -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/cache/CacheType.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.cache; 2 | 3 | public enum CacheType { 4 | 5 | CAPTCHA("captcha:"), ACCOUNT("account:"), ORDER("order:"), TRADE("trade:"), POSI("posi:"); 6 | 7 | private String type; 8 | 9 | CacheType(String type) { 10 | this.type = type; 11 | } 12 | 13 | public String type() { 14 | return this.type; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/bean/CmdPack.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | 4 | import lombok.*; 5 | import thirdpart.order.OrderCmd; 6 | 7 | import java.io.Serializable; 8 | import java.util.List; 9 | 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Getter 13 | @Setter 14 | @ToString 15 | public class CmdPack implements Serializable { 16 | 17 | private long packNo; 18 | 19 | private List orderCmds; 20 | } 21 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/bean/CmdPack.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | 4 | import lombok.*; 5 | import thirdpart.order.OrderCmd; 6 | 7 | import java.io.Serializable; 8 | import java.util.List; 9 | 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Getter 13 | @Setter 14 | @ToString 15 | public class CmdPack implements Serializable { 16 | 17 | private long packNo; 18 | 19 | private List orderCmds; 20 | } 21 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/CounterApplication.java: -------------------------------------------------------------------------------- 1 | package com.star.counter; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author zhaoyiming 8 | */ 9 | @SpringBootApplication 10 | public class CounterApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(CounterApplication.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/bean/Account.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.bean; 2 | 3 | import lombok.*; 4 | 5 | @Data 6 | @ToString 7 | @NoArgsConstructor 8 | @RequiredArgsConstructor 9 | public class Account { 10 | 11 | @NonNull 12 | private int id; 13 | 14 | @NonNull 15 | private long uid; 16 | 17 | @NonNull 18 | private String lastLoginDate; 19 | 20 | @NonNull 21 | private String lastLoginTime; 22 | 23 | private String token; 24 | } 25 | -------------------------------------------------------------------------------- /cfront/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 25 | -------------------------------------------------------------------------------- /seq/src/main/java/com/star/seq/SeqStartup1.java: -------------------------------------------------------------------------------- 1 | package com.star.seq; 2 | 3 | import com.star.seq.bean.SeqConfig; 4 | import thirdpart.codec.impl.BodyCodecImpl; 5 | 6 | import java.io.IOException; 7 | 8 | public class SeqStartup1 { 9 | 10 | public static void main(String[] args) throws IOException { 11 | String configName = "seq1.properties"; 12 | SeqConfig seqConfig = new SeqConfig(configName, new BodyCodecImpl()); 13 | seqConfig.startup(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /seq/src/main/java/com/star/seq/SeqStartup2.java: -------------------------------------------------------------------------------- 1 | package com.star.seq; 2 | 3 | import com.star.seq.bean.SeqConfig; 4 | import thirdpart.codec.impl.BodyCodecImpl; 5 | 6 | import java.io.IOException; 7 | 8 | public class SeqStartup2 { 9 | 10 | public static void main(String[] args) throws IOException { 11 | String configName = "seq2.properties"; 12 | SeqConfig seqConfig = new SeqConfig(configName, new BodyCodecImpl()); 13 | seqConfig.startup(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /seq/src/main/java/com/star/seq/SeqStartup3.java: -------------------------------------------------------------------------------- 1 | package com.star.seq; 2 | 3 | import com.star.seq.bean.SeqConfig; 4 | import thirdpart.codec.impl.BodyCodecImpl; 5 | 6 | import java.io.IOException; 7 | 8 | public class SeqStartup3 { 9 | 10 | public static void main(String[] args) throws IOException { 11 | String configName = "seq3.properties"; 12 | SeqConfig seqConfig = new SeqConfig(configName, new BodyCodecImpl()); 13 | seqConfig.startup(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/mapper/StockMapper.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.mapper; 2 | 3 | import com.star.counter.bean.StockInfo; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | @Mapper 11 | @Repository 12 | public interface StockMapper { 13 | 14 | /** 15 | * 查询所有股票信息 16 | * @return 所有股票信息 17 | */ 18 | List queryAllStockInfo(); 19 | } 20 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/checksum/impl/CheckSumImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.impl; 2 | 3 | import thirdpart.checksum.api.CheckSum; 4 | 5 | public class CheckSumImpl implements CheckSum { 6 | @Override 7 | public byte getCheckSum(byte[] data) { 8 | byte sum = 0; 9 | //将所有字节进行异或的累加 10 | //运算简单快速并且一旦任意字节修改,校验和会改变 11 | //改变字节数较多时有可能出现校验和相同的巧合 12 | for (byte b : data) { 13 | sum ^= b; 14 | } 15 | return sum; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /cfront/src/api/constants.js: -------------------------------------------------------------------------------- 1 | export const constants = { 2 | 3 | //乘数 4 | MULTI_FACTOR: 10000, 5 | 6 | //委托类型 7 | NEW_ORDER: 0, 8 | CANCEL_ORDER: 1, 9 | 10 | //价格类型 11 | LIMIT: 0, 12 | MARKET: 1, 13 | 14 | //买卖方向 15 | BUY: 0, 16 | SELL: 1, 17 | 18 | //委托状态 19 | //未报,撤单,部分撤单,已报,成交,部分成交,废单 20 | NOT_ORDER: -1, 21 | CANCELED: 1, 22 | PART_CANCELED: 2, 23 | ORDERED: 3, 24 | TRADED: 4, 25 | PART_TRADED: 5, 26 | ILLEGAL: 6, 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/checksum/impl/CheckSumImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.impl; 2 | 3 | import thirdpart.checksum.api.CheckSum; 4 | 5 | public class CheckSumImpl implements CheckSum { 6 | @Override 7 | public byte getCheckSum(byte[] data) { 8 | byte sum = 0; 9 | //将所有字节进行异或的累加 10 | //运算简单快速并且一旦任意字节修改,校验和会改变 11 | //改变字节数较多时有可能出现校验和相同的巧合 12 | for (byte b : data) { 13 | sum ^= b; 14 | } 15 | return sum; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/checksum/impl/CheckSumImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.impl; 2 | 3 | import thirdpart.checksum.api.CheckSum; 4 | 5 | public class CheckSumImpl implements CheckSum { 6 | @Override 7 | public byte getCheckSum(byte[] data) { 8 | byte sum = 0; 9 | //将所有字节进行异或的累加 10 | //运算简单快速并且一旦任意字节修改,校验和会改变 11 | //改变字节数较多时有可能出现校验和相同的巧合 12 | for (byte b : data) { 13 | sum ^= b; 14 | } 15 | return sum; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/checksum/impl/CheckSumImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.checksum.impl; 2 | 3 | import thirdpart.checksum.api.CheckSum; 4 | 5 | public class CheckSumImpl implements CheckSum { 6 | @Override 7 | public byte getCheckSum(byte[] data) { 8 | byte sum = 0; 9 | //将所有字节进行异或的累加 10 | //运算简单快速并且一旦任意字节修改,校验和会改变 11 | //改变字节数较多时有可能出现校验和相同的巧合 12 | for (byte b : data) { 13 | sum ^= b; 14 | } 15 | return sum; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/bean/PosiInfo.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.bean; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 持仓信息 10 | */ 11 | @Data 12 | @ToString 13 | @NoArgsConstructor 14 | @EqualsAndHashCode 15 | public class PosiInfo { 16 | private int id; 17 | private long uid; 18 | private int code; 19 | private String name; 20 | private long cost; 21 | private long count; 22 | } 23 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/api/PosiService.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.api; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.star.counter.bean.PosiInfo; 5 | 6 | import java.util.List; 7 | 8 | public interface PosiService { 9 | 10 | List getPosiListByUid(long uid) throws JsonProcessingException; 11 | 12 | void addPosi(long uid, int code, long volume, long price); 13 | 14 | void minusPosi(long uid, int code, long volume, long price); 15 | } 16 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/api/TradeService.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.api; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.star.counter.bean.TradeInfo; 5 | import thirdpart.hq.MatchData; 6 | import thirdpart.order.OrderCmd; 7 | 8 | import java.util.List; 9 | 10 | public interface TradeService { 11 | 12 | void saveTrade(int counterOid, MatchData md, OrderCmd orderCmd); 13 | 14 | List getTradeServiceByUid(long uid) throws JsonProcessingException; 15 | } 16 | -------------------------------------------------------------------------------- /gateway/src/test/java/CheckSumTest.java: -------------------------------------------------------------------------------- 1 | import thirdpart.checksum.impl.CheckSumImpl; 2 | 3 | public class CheckSumTest { 4 | public static void main(String[] args) { 5 | String a = "test1"; 6 | String b = "test2"; 7 | String c = "test1"; 8 | CheckSumImpl checkSum = new CheckSumImpl(); 9 | System.out.println(checkSum.getCheckSum(a.getBytes())); 10 | System.out.println(checkSum.getCheckSum(b.getBytes())); 11 | System.out.println(checkSum.getCheckSum(c.getBytes())); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/codec/api/BodyCodec.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.api; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | 5 | public interface BodyCodec { 6 | 7 | /** 8 | * 将Java对象变成字节数组 9 | * 编码分为3种: 10 | * 1.jdk序列化: 性能不高,不适合网络传输 11 | * 2.转换为json字符串: 容易抓包,但适合浏览器 12 | * 3.自定义编码/解码: 对性能、安全性有要求 13 | */ 14 | byte[] serialize(T obj) throws CodecException; 15 | 16 | /** 17 | * 将字节数组转换为Java对象 18 | */ 19 | T deserialize(byte[] bytes, Class clazz) throws CodecException; 20 | } 21 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/codec/api/BodyCodec.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.api; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | 5 | public interface BodyCodec { 6 | 7 | /** 8 | * 将Java对象变成字节数组 9 | * 编码分为3种: 10 | * 1.jdk序列化: 性能不高,不适合网络传输 11 | * 2.转换为json字符串: 容易抓包,但适合浏览器 12 | * 3.自定义编码/解码: 对性能、安全性有要求 13 | */ 14 | byte[] serialize(T obj) throws CodecException; 15 | 16 | /** 17 | * 将字节数组转换为Java对象 18 | */ 19 | T deserialize(byte[] bytes, Class clazz) throws CodecException; 20 | } 21 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/codec/api/BodyCodec.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.api; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | 5 | public interface BodyCodec { 6 | 7 | /** 8 | * 将Java对象变成字节数组 9 | * 编码分为3种: 10 | * 1.jdk序列化: 性能不高,不适合网络传输 11 | * 2.转换为json字符串: 容易抓包,但适合浏览器 12 | * 3.自定义编码/解码: 对性能、安全性有要求 13 | */ 14 | byte[] serialize(T obj) throws CodecException; 15 | 16 | /** 17 | * 将字节数组转换为Java对象 18 | */ 19 | T deserialize(byte[] bytes, Class clazz) throws CodecException; 20 | } 21 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/codec/api/BodyCodec.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.api; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | 5 | public interface BodyCodec { 6 | 7 | /** 8 | * 将Java对象变成字节数组 9 | * 编码分为3种: 10 | * 1.jdk序列化: 性能不高,不适合网络传输 11 | * 2.转换为json字符串: 容易抓包,但适合浏览器 12 | * 3.自定义编码/解码: 对性能、安全性有要求 13 | */ 14 | byte[] serialize(T obj) throws CodecException; 15 | 16 | /** 17 | * 将字节数组转换为Java对象 18 | */ 19 | T deserialize(byte[] bytes, Class clazz) throws CodecException; 20 | } 21 | -------------------------------------------------------------------------------- /cfront/src/assets/css/color-dark.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #242f42; 3 | } 4 | .login-wrap{ 5 | background: #324157; 6 | } 7 | .plugins-tips{ 8 | background: #eef1f6; 9 | } 10 | .plugins-tips a{ 11 | color: #20a0ff; 12 | } 13 | .el-upload--text em { 14 | color: #20a0ff; 15 | } 16 | .pure-button{ 17 | background: #20a0ff; 18 | } 19 | .tags-li.active { 20 | border: 1px solid #409EFF; 21 | background-color: #409EFF; 22 | } 23 | .message-title{ 24 | color: #20a0ff; 25 | } 26 | .collapse-btn:hover{ 27 | background: rgb(40,52,70); 28 | } -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/hq/MatchData.java: -------------------------------------------------------------------------------- 1 | package thirdpart.hq; 2 | 3 | import lombok.Builder; 4 | import lombok.ToString; 5 | import thirdpart.order.OrderStatus; 6 | 7 | import java.io.Serializable; 8 | 9 | @Builder 10 | @ToString 11 | public class MatchData implements Serializable { 12 | 13 | public long timestamp; 14 | 15 | public short mid; 16 | 17 | public long oid; 18 | 19 | public OrderStatus status; 20 | 21 | public long tid; 22 | 23 | //撤单数量 成交数量 24 | public long volume; 25 | 26 | public long price; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/hq/MatchData.java: -------------------------------------------------------------------------------- 1 | package thirdpart.hq; 2 | 3 | import lombok.Builder; 4 | import lombok.ToString; 5 | import thirdpart.order.OrderStatus; 6 | 7 | import java.io.Serializable; 8 | 9 | @Builder 10 | @ToString 11 | public class MatchData implements Serializable { 12 | 13 | public long timestamp; 14 | 15 | public short mid; 16 | 17 | public long oid; 18 | 19 | public OrderStatus status; 20 | 21 | public long tid; 22 | 23 | //撤单数量 成交数量 24 | public long volume; 25 | 26 | public long price; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/mapper/BalanceMapper.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.springframework.stereotype.Repository; 5 | 6 | @Mapper 7 | @Repository 8 | public interface BalanceMapper { 9 | 10 | /** 11 | * 通过uid获取账户资金 12 | * @param uid 用户id 13 | * @return 用户资金 14 | */ 15 | Long queryBalanceByUid(long uid); 16 | 17 | /** 18 | * 增加用户的资金 19 | * @param uid 用户id 20 | * @param balance 需要增加的资金 21 | */ 22 | void addBalance(long uid, long balance); 23 | } 24 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/uuid/GudyUuid.java: -------------------------------------------------------------------------------- 1 | package thirdpart.uuid; 2 | 3 | public class GudyUuid { 4 | 5 | private static GudyUuid ourInstance = new GudyUuid(); 6 | 7 | public static GudyUuid getInstance() { 8 | return ourInstance; 9 | } 10 | 11 | private GudyUuid() { 12 | } 13 | 14 | public void init(int centerId, int workerId) { 15 | idWorker = new SnowflakeIdWorker(workerId, centerId); 16 | } 17 | 18 | private SnowflakeIdWorker idWorker; 19 | 20 | public long getUUID() { 21 | return idWorker.nextId(); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /counter/src/main/resources/com/star/counter/mapper/StockMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/util/IDConverter.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.util; 2 | 3 | public class IDConverter { 4 | public static long combineIntToLong(int high, int low) { 5 | //int 4 位, long 8 位, 左移 4 * 8位变成long 6 | //高位+低位组合 7 | return ((long) high << 32 & 0xFFFFFFFF00000000L) | ((long) low & 0xFFFFFFFFL); 8 | } 9 | 10 | public static int[] seperateLongToInt(long val) { 11 | int[] res = new int[2]; 12 | res[1] = (int) (0xFFFFFFFFL & val); //低位 13 | res[0] = (int) ((0xFFFFFFFF00000000L & val) >> 32); //高位 14 | return res; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/order/OrderType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderType { 7 | LIMIT(0); // Immediate or Cancel - equivalent to strict-risk market order 8 | 9 | private byte type; 10 | 11 | OrderType(int type) { 12 | this.type = (byte) type; 13 | } 14 | 15 | public static OrderType of(byte type) { 16 | switch (type) { 17 | case 0: 18 | return LIMIT; 19 | default: 20 | throw new IllegalArgumentException("unknown OrderType:" + type); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/order/OrderType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderType { 7 | LIMIT(0); // Immediate or Cancel - equivalent to strict-risk market order 8 | 9 | private byte type; 10 | 11 | OrderType(int type) { 12 | this.type = (byte) type; 13 | } 14 | 15 | public static OrderType of(byte type) { 16 | switch (type) { 17 | case 0: 18 | return LIMIT; 19 | default: 20 | throw new IllegalArgumentException("unknown OrderType:" + type); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/order/OrderType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderType { 7 | LIMIT(0); // Immediate or Cancel - equivalent to strict-risk market order 8 | 9 | private byte type; 10 | 11 | OrderType(int type) { 12 | this.type = (byte) type; 13 | } 14 | 15 | public static OrderType of(byte type) { 16 | switch (type) { 17 | case 0: 18 | return LIMIT; 19 | default: 20 | throw new IllegalArgumentException("unknown OrderType:" + type); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /engine/src/main/resources/c3p0-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | com.mysql.cj.jdbc.Driver 5 | jdbc:mysql://47.113.188.108:3306/match_trading?serverTimezone=Asia/Shanghai 6 | root 7 | Zym.141592 8 | 1 9 | 3 10 | 3000 11 | 12 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/order/OrderType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderType { 7 | LIMIT(0); // Immediate or Cancel - equivalent to strict-risk market order 8 | 9 | private byte type; 10 | 11 | OrderType(int type) { 12 | this.type = (byte) type; 13 | } 14 | 15 | public static OrderType of(byte type) { 16 | switch (type) { 17 | case 0: 18 | return LIMIT; 19 | default: 20 | throw new IllegalArgumentException("unknown OrderType:" + type); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/bean/TradeInfo.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.bean; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 成交信息 10 | */ 11 | @Data 12 | @ToString 13 | @NoArgsConstructor 14 | @EqualsAndHashCode 15 | public class TradeInfo { 16 | 17 | private int id; 18 | private long uid; 19 | private int code; 20 | private String name; 21 | private int direction; 22 | private long price; 23 | private long tcount; 24 | private int oid; 25 | private String date; 26 | private String time; 27 | } 28 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/mapper/TradeMapper.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.mapper; 2 | 3 | import com.star.counter.bean.TradeInfo; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | @Repository 11 | public interface TradeMapper { 12 | 13 | 14 | /** 15 | * 通过用户id查询成交信息 16 | * @param uid 用户id 17 | * @return 用户的成交信息列表 18 | */ 19 | List queryTradeByUid(long uid); 20 | 21 | void savaTrade(int id, long uid, int code, int direction, long price, long tcount, int oid, String date, String time); 22 | } 23 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/property/CounterProperty.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.property; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @ConfigurationProperties(prefix = "counter") 9 | @Data 10 | public class CounterProperty { 11 | private short id; 12 | private long dataCenterId; 13 | private long workerId; 14 | private String sendIp; 15 | private int sendPort; 16 | private short gatewayId; 17 | private String subbusIp; 18 | private int subbusPort; 19 | private int pubPort; 20 | } 21 | -------------------------------------------------------------------------------- /cfront/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/EngineStartup.java: -------------------------------------------------------------------------------- 1 | package com.star.engine; 2 | 3 | import com.star.engine.config.EngineConfig; 4 | import thirdpart.checksum.impl.CheckSumImpl; 5 | import thirdpart.codec.impl.BodyCodecImpl; 6 | import thirdpart.codec.impl.MsgCodecImpl; 7 | 8 | import java.io.IOException; 9 | 10 | public class EngineStartup { 11 | 12 | public static void main(String[] args) throws IOException { 13 | EngineConfig engineConfig = new EngineConfig( 14 | "engine.properties", 15 | new BodyCodecImpl(), 16 | new CheckSumImpl(), 17 | new MsgCodecImpl()); 18 | engineConfig.startUp(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /engine/src/test/java/testEngineConfig.java: -------------------------------------------------------------------------------- 1 | import com.star.engine.config.EngineConfig; 2 | import lombok.extern.slf4j.Slf4j; 3 | import thirdpart.checksum.impl.CheckSumImpl; 4 | import thirdpart.codec.impl.BodyCodecImpl; 5 | import thirdpart.codec.impl.MsgCodecImpl; 6 | 7 | import java.io.IOException; 8 | 9 | @Slf4j 10 | public class testEngineConfig { 11 | public static void main(String[] args) throws IOException { 12 | EngineConfig engineConfig = new EngineConfig( 13 | "engine.properties", 14 | new BodyCodecImpl(), 15 | new CheckSumImpl(), 16 | new MsgCodecImpl()); 17 | engineConfig.startUp(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/config/IdWorkerConfig.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.config; 2 | 3 | import com.star.counter.property.CounterProperty; 4 | import com.star.counter.util.SnowflakeIdWorker; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class IdWorkerConfig { 11 | 12 | @Autowired 13 | CounterProperty counterProperty; 14 | 15 | @Bean 16 | public SnowflakeIdWorker snowflakeIdWorker() { 17 | return new SnowflakeIdWorker(counterProperty.getWorkerId(), counterProperty.getDataCenterId()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/mapper/DBQuery.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.mapper; 2 | 3 | import org.apache.ibatis.annotations.MapKey; 4 | 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | //@SuppressWarnings("MybatisXMapperMethodInspection") 10 | public interface DBQuery { 11 | 12 | /** 13 | * 查询所有用户的资金信息 14 | * @return 用户的资金信息列表 15 | */ 16 | List> queryAllBalance(); 17 | 18 | /** 19 | * 查询所有股票代码 20 | * @return 股票代码的集合 21 | */ 22 | HashSet queryAllStockCode(); 23 | 24 | /** 25 | * 查询所有会员信息 26 | * @return 会员id的数组 27 | */ 28 | List queryAllMemberIds(); 29 | } 30 | -------------------------------------------------------------------------------- /cfront/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | posiData: [], 9 | orderData: [], 10 | tradeData: [], 11 | balance: 0 12 | }, 13 | mutations: { 14 | updatePosi(state, posiInfo) { 15 | state.posiData = posiInfo; 16 | }, 17 | updateOrder(state, orderInfo) { 18 | state.orderData = orderInfo; 19 | }, 20 | updateTrade(state, tradeInfo) { 21 | state.tradeData = tradeInfo; 22 | }, 23 | updateBalance(state, balance) { 24 | state.balance = balance; 25 | } 26 | }, 27 | //异步操作 28 | // actions: { 29 | // }, 30 | 31 | //类似state 32 | // modules: { 33 | // } 34 | }) 35 | -------------------------------------------------------------------------------- /counter/src/main/resources/com/star/counter/mapper/BalanceMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | UPDATE t_user SET balance = balance + #{balance} 15 | WHERE uid = #{uid} 16 | 17 | 18 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/RbCmdFactory.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.lmax.disruptor.EventFactory; 5 | import com.star.engine.bean.command.CmdResultCode; 6 | import com.star.engine.bean.command.RbCmd; 7 | import javafx.event.EventHandler; 8 | import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap; 9 | 10 | public class RbCmdFactory implements EventFactory { 11 | @Override 12 | public RbCmd newInstance() { 13 | return RbCmd.builder() 14 | .resultCode(CmdResultCode.SUCCESS) 15 | .matchEventList(Lists.newArrayList()) 16 | .marketDataMap(new IntObjectHashMap<>()) 17 | .build(); 18 | } 19 | } -------------------------------------------------------------------------------- /cfront/src/views/TradeQuery.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 29 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/bean/OrderInfo.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.bean; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.NoArgsConstructor; 7 | import lombok.ToString; 8 | 9 | /** 10 | * 委托信息 11 | */ 12 | @Data 13 | @ToString 14 | @NoArgsConstructor 15 | @EqualsAndHashCode 16 | @JsonIgnoreProperties(ignoreUnknown = true) 17 | public class OrderInfo { 18 | private int id; 19 | private long uid; 20 | private int code; 21 | private String name; 22 | private int direction; 23 | private int type; 24 | private long price; 25 | private long ocount; 26 | private int status; 27 | private String date; 28 | private String time; 29 | } 30 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/config/SenderConfig.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.config; 2 | 3 | import com.star.counter.property.CounterProperty; 4 | import io.vertx.core.Vertx; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import thirdpart.tcp.TcpDirectSender; 9 | 10 | @Configuration 11 | public class SenderConfig { 12 | 13 | @Autowired 14 | CounterProperty counterProperty; 15 | 16 | @Autowired 17 | Vertx sendVertx; 18 | 19 | @Bean 20 | public TcpDirectSender tcpDirectSender() { 21 | return new TcpDirectSender(counterProperty.getSendIp(), counterProperty.getSendPort(), sendVertx); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/mapper/OrderMapper.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.mapper; 2 | 3 | import com.star.counter.bean.OrderInfo; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | @Mapper 11 | @Repository 12 | public interface OrderMapper { 13 | /** 14 | * 通过用户id查询所有订单信息 15 | * @param uid 用户id 16 | * @return 用户的所有订单列表 17 | */ 18 | List queryOrderByUid(long uid); 19 | 20 | /** 21 | * 将参数map的字段添加到t_order表中,同时传入的params中增加了id值 22 | * @param params 参数列表 23 | * @return 修改的记录数 24 | */ 25 | int insertOrder(Map params); 26 | 27 | void updateOrder(long oid, int status); 28 | } 29 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/codec/impl/BodyCodecImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.impl; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | import com.alipay.remoting.serialization.SerializerManager; 5 | import thirdpart.codec.api.BodyCodec; 6 | 7 | public class BodyCodecImpl implements BodyCodec { 8 | 9 | @Override 10 | public byte[] serialize(T obj) throws CodecException { 11 | byte[] bytes = SerializerManager.getSerializer(SerializerManager.Hessian2).serialize(obj); 12 | return bytes; 13 | } 14 | 15 | @Override 16 | public T deserialize(byte[] bytes, Class clazz) throws CodecException { 17 | return SerializerManager.getSerializer(SerializerManager.Hessian2).deserialize(bytes, clazz.getName()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cfront/src/views/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 31 | 32 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/codec/impl/BodyCodecImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.impl; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | import com.alipay.remoting.serialization.SerializerManager; 5 | import thirdpart.codec.api.BodyCodec; 6 | 7 | public class BodyCodecImpl implements BodyCodec { 8 | 9 | @Override 10 | public byte[] serialize(T obj) throws CodecException { 11 | byte[] bytes = SerializerManager.getSerializer(SerializerManager.Hessian2).serialize(obj); 12 | return bytes; 13 | } 14 | 15 | @Override 16 | public T deserialize(byte[] bytes, Class clazz) throws CodecException { 17 | return SerializerManager.getSerializer(SerializerManager.Hessian2).deserialize(bytes, clazz.getName()); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/codec/impl/BodyCodecImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.impl; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | import com.alipay.remoting.serialization.SerializerManager; 5 | import thirdpart.codec.api.BodyCodec; 6 | 7 | public class BodyCodecImpl implements BodyCodec { 8 | 9 | @Override 10 | public byte[] serialize(T obj) throws CodecException { 11 | byte[] bytes = SerializerManager.getSerializer(SerializerManager.Hessian2).serialize(obj); 12 | return bytes; 13 | } 14 | 15 | @Override 16 | public T deserialize(byte[] bytes, Class clazz) throws CodecException { 17 | return SerializerManager.getSerializer(SerializerManager.Hessian2).deserialize(bytes, clazz.getName()); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/codec/impl/BodyCodecImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.impl; 2 | 3 | import com.alipay.remoting.exception.CodecException; 4 | import com.alipay.remoting.serialization.SerializerManager; 5 | import thirdpart.codec.api.BodyCodec; 6 | 7 | public class BodyCodecImpl implements BodyCodec { 8 | 9 | @Override 10 | public byte[] serialize(T obj) throws CodecException { 11 | byte[] bytes = SerializerManager.getSerializer(SerializerManager.Hessian2).serialize(obj); 12 | return bytes; 13 | } 14 | 15 | @Override 16 | public T deserialize(byte[] bytes, Class clazz) throws CodecException { 17 | return SerializerManager.getSerializer(SerializerManager.Hessian2).deserialize(bytes, clazz.getName()); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/controller/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.controller; 2 | 3 | import com.star.counter.bean.res.CounterRes; 4 | import lombok.extern.log4j.Log4j2; 5 | import org.springframework.web.bind.annotation.ControllerAdvice; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | 11 | @ControllerAdvice 12 | @ResponseBody 13 | @Log4j2 14 | public class GlobalExceptionHandler { 15 | 16 | @ExceptionHandler(value = Exception.class) 17 | public CounterRes exceptionHandler(HttpServletRequest request, Exception e) { 18 | log.error(e); 19 | return new CounterRes(CounterRes.FAIL, "发生错误", null); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /gateway/src/test/java/CodecTest.java: -------------------------------------------------------------------------------- 1 | import com.alipay.remoting.exception.CodecException; 2 | import thirdpart.bean.CommonMsg; 3 | import thirdpart.codec.api.BodyCodec; 4 | import thirdpart.codec.impl.BodyCodecImpl; 5 | 6 | import java.io.UnsupportedEncodingException; 7 | import java.nio.charset.StandardCharsets; 8 | 9 | public class CodecTest { 10 | 11 | public static void main(String[] args) throws UnsupportedEncodingException, CodecException { 12 | CommonMsg commonMsg = new CommonMsg(); 13 | commonMsg.setMsgDst((short) 1); 14 | commonMsg.setErrCode((short) 12); 15 | BodyCodecImpl bodyCodec = new BodyCodecImpl(); 16 | byte[] serialize = bodyCodec.serialize(commonMsg); 17 | System.out.println(bodyCodec.deserialize(serialize, CommonMsg.class)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cfront/src/assets/css/theme-green/color-green.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #07c4a8; 3 | } 4 | .login-wrap{ 5 | background: rgba(56, 157, 170, 0.82);; 6 | } 7 | .plugins-tips{ 8 | background: #f2f2f2; 9 | } 10 | .plugins-tips a{ 11 | color: #00d1b2; 12 | } 13 | .el-upload--text em { 14 | color: #00d1b2; 15 | } 16 | .pure-button{ 17 | background: #00d1b2; 18 | } 19 | .pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus { 20 | background-color: #00d1b2 !important; 21 | border-color: #00d1b2 !important; 22 | } 23 | .tags-li.active { 24 | border: 1px solid #00d1b2; 25 | background-color: #00d1b2; 26 | } 27 | .collapse-btn:hover{ 28 | background: #00d1b2; 29 | } -------------------------------------------------------------------------------- /engine/src/main/resources/com/star/engine/mapper/DBQuery.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /cfront/src/views/OrderQuery.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 31 | 32 | -------------------------------------------------------------------------------- /cfront/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | 6 | //bus 7 | import VueBus from 'vue-bus' 8 | 9 | Vue.use(VueBus); 10 | 11 | //导入 element ui 12 | import ElementUI from 'element-ui' 13 | import 'element-ui/lib/theme-chalk/index.css' 14 | 15 | Vue.use(ElementUI); 16 | 17 | 18 | Vue.config.productionTip = false 19 | 20 | let vue = new Vue({ 21 | router, 22 | store, 23 | render: h => h(App) 24 | }).$mount('#app') 25 | 26 | import {config} from "./api/frontConfig"; 27 | import VertxEventBus from 'vue-vertx3-eventbus-client'; 28 | 29 | Vue.use(VertxEventBus, { 30 | host: config.real_ws_remote.host, 31 | port: config.real_ws_remote.port, 32 | path: config.real_ws_remote.path 33 | }) 34 | vue.$eventBus.enableReconnect(true); 35 | 36 | export default vue -------------------------------------------------------------------------------- /cfront/src/views/HisOrderQuery.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 31 | 32 | -------------------------------------------------------------------------------- /engine/src/test/java/testMyBatis.java: -------------------------------------------------------------------------------- 1 | import com.star.engine.bean.DBUtil; 2 | 3 | import java.util.HashSet; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | public class testMyBatis { 8 | public static void main(String[] args) { 9 | List> maps = DBUtil.getInstance().queryAllBalance(); 10 | for (Map map : maps){ 11 | for (String key : map.keySet()) { 12 | System.out.println("key is: " + key); 13 | System.out.println("value is: " + map.get(key)); 14 | System.out.println("the type of value is: " + map.get(key).getClass()); 15 | } 16 | } 17 | HashSet allStockCode = DBUtil.getInstance().queryAllStockCode(); 18 | System.out.println(allStockCode); 19 | List allMemberIds = DBUtil.getInstance().queryAllMemberIds(); 20 | System.out.println(allMemberIds); 21 | } 22 | } -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/impl/BalanceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.impl; 2 | 3 | import com.star.counter.mapper.BalanceMapper; 4 | import com.star.counter.service.api.BalanceService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | public class BalanceServiceImpl implements BalanceService { 10 | 11 | @Autowired 12 | BalanceMapper balanceMapper; 13 | 14 | @Override 15 | public Long getBalanceByUid(long uid) { 16 | Long balance = balanceMapper.queryBalanceByUid(uid); 17 | return balance; 18 | } 19 | 20 | @Override 21 | public void addBalance(long uid, long balance) { 22 | balanceMapper.addBalance(uid, balance); 23 | } 24 | 25 | @Override 26 | public void minusBalance(long uid, long balance) { 27 | balanceMapper.addBalance(uid, -balance); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /mqtt/src/main/java/com/star/mqtt/MQTTServerStart.java: -------------------------------------------------------------------------------- 1 | package com.star.mqtt; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.mqtt.MqttServer; 5 | 6 | public class MQTTServerStart { 7 | public static void main(String[] args) { 8 | Vertx vertx = Vertx.vertx(); 9 | MqttServer mqttServer = MqttServer.create(vertx); 10 | mqttServer.endpointHandler(endpoint -> { 11 | System.out.println("MQTT client [" + endpoint.clientIdentifier() + "] request to connect, clean session = " + endpoint.isCleanSession()); 12 | endpoint.accept(false); 13 | }).listen(ar -> { 14 | if (ar.succeeded()) { 15 | System.out.println("MQTT server is listening on port " + ar.result().actualPort()); 16 | } else { 17 | System.out.println("Error on starting the server"); 18 | ar.cause().printStackTrace(); 19 | } 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/mapper/AccountMapper.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.mapper; 2 | 3 | import com.star.counter.bean.Account; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | @Mapper 9 | public interface AccountMapper { 10 | 11 | /** 12 | * 查询账户对象 13 | * @param uid 用户id 14 | * @param password 密码 15 | * @return 根据账号密码查询的对象 16 | */ 17 | public Account queryAccount(long uid, String password); 18 | 19 | 20 | /** 21 | * 更新用户最后登录时间信息 22 | * @param uid 用户id 23 | * @param nowDate 当前时期 24 | * @param nowTime 当前时间 25 | */ 26 | public void updateAccountLoginTime(long uid, String nowDate, String nowTime); 27 | 28 | /** 29 | * 修改密码 30 | * @param uid 用户id 31 | * @param oldPwd 老密码 32 | * @param newPwd 新密码 33 | */ 34 | public int updateAccountPassword(long uid, String oldPwd, String newPwd); 35 | } 36 | -------------------------------------------------------------------------------- /counter/src/main/resources/com/star/counter/mapper/TradeMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | INSERT INTO t_trade(id, uid, code, direction, price, tcount, oid, date, time) 17 | VALUES (#{id}, #{uid}, #{code}, #{direction}, #{price}, #{tcount}, #{oid}, #{date}, #{time}) 18 | 19 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/order/OrderCmd.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Builder; 4 | import lombok.ToString; 5 | 6 | import java.io.Serializable; 7 | 8 | @Builder 9 | @ToString 10 | public class OrderCmd implements Serializable { 11 | 12 | public CmdType type; 13 | 14 | public long timestamp; 15 | 16 | /** 17 | * 会员ID 18 | */ 19 | final public short mid; 20 | 21 | /** 22 | * 用户ID 23 | */ 24 | final public long uid; 25 | 26 | /** 27 | * 代码 28 | */ 29 | final public int code; 30 | 31 | /** 32 | * 方向 33 | */ 34 | final public OrderDirection direction; 35 | 36 | /** 37 | * 价格 38 | */ 39 | final public long price; 40 | 41 | /** 42 | * 量 43 | */ 44 | final public long volume; 45 | 46 | /** 47 | * 委托类型 48 | * 1.LIMIT 49 | */ 50 | final public OrderType orderType; 51 | 52 | /** 53 | * 委托编号 54 | */ 55 | public long oid; 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/order/OrderCmd.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Builder; 4 | import lombok.ToString; 5 | 6 | import java.io.Serializable; 7 | 8 | @Builder 9 | @ToString 10 | public class OrderCmd implements Serializable { 11 | 12 | public CmdType type; 13 | 14 | public long timestamp; 15 | 16 | /** 17 | * 会员ID 18 | */ 19 | final public short mid; 20 | 21 | /** 22 | * 用户ID 23 | */ 24 | final public long uid; 25 | 26 | /** 27 | * 代码 28 | */ 29 | final public int code; 30 | 31 | /** 32 | * 方向 33 | */ 34 | final public OrderDirection direction; 35 | 36 | /** 37 | * 价格 38 | */ 39 | final public long price; 40 | 41 | /** 42 | * 量 43 | */ 44 | final public long volume; 45 | 46 | /** 47 | * 委托类型 48 | * 1.LIMIT 49 | */ 50 | final public OrderType orderType; 51 | 52 | /** 53 | * 委托编号 54 | */ 55 | public long oid; 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/order/OrderCmd.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Builder; 4 | import lombok.ToString; 5 | 6 | import java.io.Serializable; 7 | 8 | @Builder 9 | @ToString 10 | public class OrderCmd implements Serializable { 11 | 12 | public CmdType type; 13 | 14 | public long timestamp; 15 | 16 | /** 17 | * 会员ID 18 | */ 19 | final public short mid; 20 | 21 | /** 22 | * 用户ID 23 | */ 24 | final public long uid; 25 | 26 | /** 27 | * 代码 28 | */ 29 | final public int code; 30 | 31 | /** 32 | * 方向 33 | */ 34 | final public OrderDirection direction; 35 | 36 | /** 37 | * 价格 38 | */ 39 | final public long price; 40 | 41 | /** 42 | * 量 43 | */ 44 | final public long volume; 45 | 46 | /** 47 | * 委托类型 48 | * 1.LIMIT 49 | */ 50 | final public OrderType orderType; 51 | 52 | /** 53 | * 委托编号 54 | */ 55 | public long oid; 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/order/OrderCmd.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Builder; 4 | import lombok.ToString; 5 | 6 | import java.io.Serializable; 7 | 8 | @Builder 9 | @ToString 10 | public class OrderCmd implements Serializable { 11 | 12 | public CmdType type; 13 | 14 | public long timestamp; 15 | 16 | /** 17 | * 会员ID 18 | */ 19 | final public short mid; 20 | 21 | /** 22 | * 用户ID 23 | */ 24 | final public long uid; 25 | 26 | /** 27 | * 代码 28 | */ 29 | final public int code; 30 | 31 | /** 32 | * 方向 33 | */ 34 | final public OrderDirection direction; 35 | 36 | /** 37 | * 价格 38 | */ 39 | final public long price; 40 | 41 | /** 42 | * 量 43 | */ 44 | final public long volume; 45 | 46 | /** 47 | * 委托类型 48 | * 1.LIMIT 49 | */ 50 | final public OrderType orderType; 51 | 52 | /** 53 | * 委托编号 54 | */ 55 | public long oid; 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/order/OrderDirection.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderDirection { 7 | //从现金的角度来理解这方面的约定规则,0就是把钱花了,没钱 8 | BUY(0), 9 | SELL(1), 10 | 11 | PLUS_BALANCE(2), 12 | MINUS_BALANCE(3), 13 | 14 | OTHER(-1);//其他类型执行(撤单 等) 15 | 16 | private byte direction; 17 | 18 | OrderDirection(int direction) { 19 | this.direction = (byte) direction; 20 | } 21 | 22 | public static OrderDirection of(byte direction) { 23 | switch (direction) { 24 | case 0: 25 | return BUY; 26 | case 1: 27 | return SELL; 28 | case 2: 29 | return PLUS_BALANCE; 30 | case 3: 31 | return MINUS_BALANCE; 32 | case -1: 33 | return OTHER; 34 | default: 35 | throw new IllegalArgumentException("unknown OrderDirection:" + direction); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/order/OrderDirection.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderDirection { 7 | //从现金的角度来理解这方面的约定规则,0就是把钱花了,没钱 8 | BUY(0), 9 | SELL(1), 10 | 11 | PLUS_BALANCE(2), 12 | MINUS_BALANCE(3), 13 | 14 | OTHER(-1);//其他类型执行(撤单 等) 15 | 16 | private byte direction; 17 | 18 | OrderDirection(int direction) { 19 | this.direction = (byte) direction; 20 | } 21 | 22 | public static OrderDirection of(byte direction) { 23 | switch (direction) { 24 | case 0: 25 | return BUY; 26 | case 1: 27 | return SELL; 28 | case 2: 29 | return PLUS_BALANCE; 30 | case 3: 31 | return MINUS_BALANCE; 32 | case -1: 33 | return OTHER; 34 | default: 35 | throw new IllegalArgumentException("unknown OrderDirection:" + direction); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/order/OrderDirection.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderDirection { 7 | //从现金的角度来理解这方面的约定规则,0就是把钱花了,没钱 8 | BUY(0), 9 | SELL(1), 10 | 11 | PLUS_BALANCE(2), 12 | MINUS_BALANCE(3), 13 | 14 | OTHER(-1);//其他类型执行(撤单 等) 15 | 16 | private byte direction; 17 | 18 | OrderDirection(int direction) { 19 | this.direction = (byte) direction; 20 | } 21 | 22 | public static OrderDirection of(byte direction) { 23 | switch (direction) { 24 | case 0: 25 | return BUY; 26 | case 1: 27 | return SELL; 28 | case 2: 29 | return PLUS_BALANCE; 30 | case 3: 31 | return MINUS_BALANCE; 32 | case -1: 33 | return OTHER; 34 | default: 35 | throw new IllegalArgumentException("unknown OrderDirection:" + direction); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/order/OrderDirection.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Data; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public enum OrderDirection { 8 | //从现金的角度来理解这方面的约定规则,0就是把钱花了,没钱 9 | BUY(0), 10 | SELL(1), 11 | 12 | PLUS_BALANCE(2), 13 | MINUS_BALANCE(3), 14 | 15 | OTHER(-1);//其他类型执行(撤单 等) 16 | 17 | private byte direction; 18 | 19 | OrderDirection(int direction) { 20 | this.direction = (byte) direction; 21 | } 22 | 23 | public static OrderDirection of(byte direction) { 24 | switch (direction) { 25 | case 0: 26 | return BUY; 27 | case 1: 28 | return SELL; 29 | case 2: 30 | return PLUS_BALANCE; 31 | case 3: 32 | return MINUS_BALANCE; 33 | case -1: 34 | return OTHER; 35 | default: 36 | throw new IllegalArgumentException("unknown OrderDirection:" + direction); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/orderbook/MatchEvent.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean.orderbook; 2 | 3 | import lombok.NoArgsConstructor; 4 | import lombok.ToString; 5 | import thirdpart.hq.MatchData; 6 | import thirdpart.order.OrderStatus; 7 | 8 | @NoArgsConstructor 9 | @ToString 10 | public final class MatchEvent { 11 | 12 | public long timestamp; 13 | 14 | public short mid; 15 | 16 | public long oid; 17 | 18 | public OrderStatus status = OrderStatus.NOT_SET; 19 | 20 | public long tid; 21 | 22 | //撤单数量 成交数量 23 | public long volume; 24 | 25 | public long price; 26 | 27 | //将MatchData与MatchEvent区分开,MatchData可以直接发送到总线上去 28 | public MatchData copy() { 29 | return MatchData.builder() 30 | .timestamp(this.timestamp) 31 | .mid(this.mid) 32 | .oid(this.oid) 33 | .status(this.status) 34 | .tid(this.tid) 35 | .volume(this.volume) 36 | .price(this.price) 37 | .build(); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /counter/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8090 3 | spring: 4 | datasource: 5 | # url: jdbc:mysql://47.113.188.108:3306/match_trading?serverTimezone=Asia/Shanghai 6 | url: jdbc:mysql://127.0.0.1:3306/match_trading?serverTimezone=Asia/Shanghai 7 | username: root 8 | password: Zym.141592 9 | driver-class-name: com.mysql.cj.jdbc.Driver 10 | redis: 11 | # url: redis://Zym.141592@47.113.188.108:6379 12 | url: redis://Zym.141592@127.0.0.1:6379 13 | timeout: 6000ms 14 | mybatis: 15 | mapper-locations: classpath:com/star/counter/mapper/*.xml 16 | configuration: 17 | map-underscore-to-camel-case: true 18 | jdbc-type-for-null: null 19 | #缓存过期时间 20 | cacheexpire: 21 | captcha: 100 22 | account: 3600 23 | order: 36000 24 | #机器位置 25 | counter: 26 | id: 12 27 | dataCenterId: 0 #机房ID 28 | workerId: 0 #机柜ID 29 | sendIp: 127.0.0.1 30 | sendPort: 8091 31 | gatewayId: 1001 32 | # subbusIp: 47.113.188.108 #mqtt总线ip 33 | subbusIp: 127.0.0.1 #mqtt总线ip 34 | subbusPort: 1883 #mqtt服务器端口 35 | pubPort: 8501 #与终端交互的端口 -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/util/TimeformatUtil.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.util; 2 | 3 | 4 | import org.apache.commons.lang3.time.DateFormatUtils; 5 | 6 | import java.util.Date; 7 | 8 | public class TimeformatUtil { 9 | 10 | private static final String YYYY_MM_DD = "yyyyMMdd"; 11 | 12 | private static final String HH_MM_SS = "HH:mm:ss"; 13 | 14 | private static final String YYYY_MM_DD_HH_MM_SS = "yyyyMMdd HH:mm:ss"; 15 | 16 | public static String yyyyMMdd(Date date){ 17 | return DateFormatUtils.format(date,YYYY_MM_DD); 18 | } 19 | 20 | public static String yyyyMMdd(long timestamp){ 21 | return DateFormatUtils.format(timestamp,YYYY_MM_DD); 22 | } 23 | 24 | public static String hhMMss(Date date){ 25 | return DateFormatUtils.format(date,HH_MM_SS); 26 | } 27 | 28 | public static String hhMMss(long timestamp){ 29 | return DateFormatUtils.format(timestamp,HH_MM_SS); 30 | } 31 | 32 | 33 | public static String yyyyMMddHHmmss(Date date){ 34 | return DateFormatUtils.format(date,YYYY_MM_DD_HH_MM_SS); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/api/AccountService.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.api; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.star.counter.bean.Account; 5 | import org.springframework.stereotype.Service; 6 | 7 | public interface AccountService { 8 | 9 | /** 10 | * 登录 11 | * @param uid 用户id 12 | * @param password 密码 13 | * @param captcha 验证码 14 | * @param captchaId 验证码Id(UUID) 15 | * @return 查询到的用户对象 16 | */ 17 | Account login(long uid, String password, String captcha, String captchaId) throws JsonProcessingException; 18 | 19 | /** 20 | * 是否存在登录信息(身份校验) 21 | * @param token 用户的标识符 22 | */ 23 | boolean accountExistInCache(String token); 24 | 25 | /** 26 | * 清除token信息,退出登录 27 | * @param token 用户的标识符 28 | */ 29 | void logout(String token); 30 | 31 | /** 32 | * 更新密码 33 | * @param uid 用户id 34 | * @param oldPwd 老密码 35 | * @param newPwd 新密码 36 | * @return 是否修改成功 37 | */ 38 | boolean updatePassword(long uid, String oldPwd, String newPwd); 39 | } 40 | -------------------------------------------------------------------------------- /cfront/src/api/loginApi.js: -------------------------------------------------------------------------------- 1 | import {reqRealEnd, reqRealEndAsync} from './axiosCommon' 2 | 3 | import {config} from './frontConfig' 4 | 5 | import router from '../router' 6 | 7 | //请求验证码 8 | export const queryCaptcha = (callback) => { 9 | 10 | return reqRealEndAsync("post", config.real_domain, 11 | "/login/captcha", {}, callback); 12 | }; 13 | 14 | // 登录 15 | export const login = (params, callback) => { 16 | return reqRealEndAsync("post", config.real_domain, 17 | "/login/userlogin", params, callback); 18 | }; 19 | 20 | //退出登录 21 | export const logout = () =>{ 22 | //移除登录信息 23 | sessionStorage.removeItem("uid"); 24 | sessionStorage.removeItem("token"); 25 | //跳转登录页面 26 | router.replace({ 27 | path: "/", 28 | query: { 29 | msg: "成功退出" 30 | } 31 | }); 32 | 33 | //通知柜台 34 | reqRealEnd("post",config.real_domain,'/login/logout',{}); 35 | 36 | } 37 | 38 | 39 | export const pwdUpdate = (params,callback) =>{ 40 | return reqRealEndAsync("post",config.real_domain, 41 | '/login/pwdupdate',params,callback); 42 | } 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/handler/exception/DisruptorExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.handler.exception; 2 | 3 | import com.lmax.disruptor.ExceptionHandler; 4 | import lombok.AllArgsConstructor; 5 | import lombok.extern.log4j.Log4j2; 6 | 7 | import java.util.function.BiConsumer; 8 | 9 | @Log4j2 10 | @AllArgsConstructor 11 | public class DisruptorExceptionHandler implements ExceptionHandler { 12 | 13 | public final String name; 14 | 15 | //相当于回调函数 16 | public final BiConsumer onException; 17 | 18 | @Override 19 | public void handleEventException(Throwable ex, long sequence, T event) { 20 | if (log.isDebugEnabled()) { 21 | log.debug("Disruptor '{}' seq = {} exist exception", name, sequence); 22 | } 23 | onException.accept(ex, sequence); 24 | } 25 | 26 | @Override 27 | public void handleOnStartException(Throwable ex) { 28 | log.info("Disruptor '{}' start exception", name); 29 | } 30 | 31 | @Override 32 | public void handleOnShutdownException(Throwable ex) { 33 | log.info("Disruptor '{}' shutdown exception", name); 34 | } 35 | } -------------------------------------------------------------------------------- /cfront/src/views/404.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/mapper/PosiMapper.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.mapper; 2 | 3 | import com.star.counter.bean.PosiInfo; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | @Repository 11 | public interface PosiMapper { 12 | 13 | /** 14 | * 通过用户id查询持仓信息 15 | * @param uid 用户id 16 | * @return 该用户对应的持仓列表 17 | */ 18 | List queryPosiByUid(long uid); 19 | 20 | /** 21 | * 增加持仓 22 | * @param uid 用户id 23 | * @param code 增加的持仓股的股票代码 24 | * @param volume 增加量 25 | * @param price 价格 26 | */ 27 | void addPosi(long uid, int code, long volume, long price); 28 | 29 | /** 30 | * 查询某用户对某股票的持仓信息 31 | * @param uid 用户id 32 | * @param code 股票代码 33 | * @return 查到uid的用户对code股票的持仓信息 34 | */ 35 | PosiInfo queryOnePosi(long uid, int code); 36 | 37 | /** 38 | * 增加持仓信息 39 | * @param uid 用户id 40 | * @param code 股票代码 41 | * @param volume 交易量 42 | * @param price 购买价格 43 | */ 44 | void insetPosi(long uid, int code, long volume, long price); 45 | } 46 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/order/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderStatus { 7 | // 正撤:撤单指令已送达公司,正在等待处理,此时不能确定是否已进场; 8 | // 部撤:委托指令已成交一部分,未成交部分被撤销; 9 | // 已撤:委托指令全部被撤消; 10 | 11 | // 正报:委托指令已送达公司,正在等待处理,此时不能确定是否已进场; 12 | // 已报:已收到下单反馈; 13 | 14 | // 已成:委托指令全部成交; 15 | // 部成:委托指令部份成交; 16 | 17 | // 废单,表示撤单指令失败,原因可能是被撤的下单指令已经成交了或场内无法找到这条下单记录; 18 | 19 | // order : NOT_SET --> ORDER_ED --> PART_TRADE --> TRADE_ED 20 | // \--> REJECT 21 | // 正报 --> 已报 --> 部成 --> 成交 22 | 23 | //cancel: NOT_SET --> PART_CANCEL --> CANCEL_ED 24 | // \--> REJECT 25 | // 正撤 26 | 27 | NOT_SET(-1), 28 | 29 | CANCEL_ED(1), 30 | PART_CANCEL(2), 31 | 32 | // ORDER_STANDBY(3), 33 | ORDER_ED(3), 34 | 35 | TRADE_ED(4), 36 | PART_TRADE(5), 37 | 38 | REJECT(6); 39 | 40 | 41 | private int code; 42 | 43 | OrderStatus(int code) { 44 | this.code = code; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /counter/src/main/resources/com/star/counter/mapper/AccountMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | UPDATE t_user SET 21 | modifyDate = #{nowDate}, 22 | modifyTime = #{nowTime} 23 | WHERE uid = #{uid} 24 | 25 | 26 | 27 | UPDATE t_user SET 28 | password = #{newPwd} 29 | WHERE uid = #{uid} AND password = #{oldPwd} 30 | 31 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/order/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderStatus { 7 | // 正撤:撤单指令已送达公司,正在等待处理,此时不能确定是否已进场; 8 | // 部撤:委托指令已成交一部分,未成交部分被撤销; 9 | // 已撤:委托指令全部被撤消; 10 | 11 | // 正报:委托指令已送达公司,正在等待处理,此时不能确定是否已进场; 12 | // 已报:已收到下单反馈; 13 | 14 | // 已成:委托指令全部成交; 15 | // 部成:委托指令部份成交; 16 | 17 | // 废单,表示撤单指令失败,原因可能是被撤的下单指令已经成交了或场内无法找到这条下单记录; 18 | 19 | // order : NOT_SET --> ORDER_ED --> PART_TRADE --> TRADE_ED 20 | // \--> REJECT 21 | // 正报 --> 已报 --> 部成 --> 成交 22 | 23 | //cancel: NOT_SET --> PART_CANCEL --> CANCEL_ED 24 | // \--> REJECT 25 | // 正撤 26 | 27 | NOT_SET(-1), 28 | 29 | CANCEL_ED(1), 30 | PART_CANCEL(2), 31 | 32 | // ORDER_STANDBY(3), 33 | ORDER_ED(3), 34 | 35 | TRADE_ED(4), 36 | PART_TRADE(5), 37 | 38 | REJECT(6); 39 | 40 | 41 | private int code; 42 | 43 | OrderStatus(int code) { 44 | this.code = code; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/order/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderStatus { 7 | // 正撤:撤单指令已送达公司,正在等待处理,此时不能确定是否已进场; 8 | // 部撤:委托指令已成交一部分,未成交部分被撤销; 9 | // 已撤:委托指令全部被撤消; 10 | 11 | // 正报:委托指令已送达公司,正在等待处理,此时不能确定是否已进场; 12 | // 已报:已收到下单反馈; 13 | 14 | // 已成:委托指令全部成交; 15 | // 部成:委托指令部份成交; 16 | 17 | // 废单,表示撤单指令失败,原因可能是被撤的下单指令已经成交了或场内无法找到这条下单记录; 18 | 19 | // order : NOT_SET --> ORDER_ED --> PART_TRADE --> TRADE_ED 20 | // \--> REJECT 21 | // 正报 --> 已报 --> 部成 --> 成交 22 | 23 | //cancel: NOT_SET --> PART_CANCEL --> CANCEL_ED 24 | // \--> REJECT 25 | // 正撤 26 | 27 | NOT_SET(-1), 28 | 29 | CANCEL_ED(1), 30 | PART_CANCEL(2), 31 | 32 | // ORDER_STANDBY(3), 33 | ORDER_ED(3), 34 | 35 | TRADE_ED(4), 36 | PART_TRADE(5), 37 | 38 | REJECT(6); 39 | 40 | 41 | private int code; 42 | 43 | OrderStatus(int code) { 44 | this.code = code; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/order/OrderStatus.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderStatus { 7 | // 正撤:撤单指令已送达公司,正在等待处理,此时不能确定是否已进场; 8 | // 部撤:委托指令已成交一部分,未成交部分被撤销; 9 | // 已撤:委托指令全部被撤消; 10 | 11 | // 正报:委托指令已送达公司,正在等待处理,此时不能确定是否已进场; 12 | // 已报:已收到下单反馈; 13 | 14 | // 已成:委托指令全部成交; 15 | // 部成:委托指令部份成交; 16 | 17 | // 废单,表示撤单指令失败,原因可能是被撤的下单指令已经成交了或场内无法找到这条下单记录; 18 | 19 | // order : NOT_SET --> ORDER_ED --> PART_TRADE --> TRADE_ED 20 | // \--> REJECT 21 | // 正报 --> 已报 --> 部成 --> 成交 22 | 23 | //cancel: NOT_SET --> PART_CANCEL --> CANCEL_ED 24 | // \--> REJECT 25 | // 正撤 26 | 27 | NOT_SET(-1), 28 | 29 | CANCEL_ED(1), 30 | PART_CANCEL(2), 31 | 32 | // ORDER_STANDBY(3), 33 | ORDER_ED(3), 34 | 35 | TRADE_ED(4), 36 | PART_TRADE(5), 37 | 38 | REJECT(6); 39 | 40 | 41 | private int code; 42 | 43 | OrderStatus(int code) { 44 | this.code = code; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/config/CounterConfig.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.config; 2 | 3 | 4 | import com.star.counter.consumer.MqttBusConsumer; 5 | import com.star.counter.property.CounterProperty; 6 | import io.vertx.core.Vertx; 7 | import lombok.Data; 8 | import lombok.extern.log4j.Log4j2; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.annotation.Configuration; 11 | import thirdpart.checksum.api.CheckSum; 12 | import thirdpart.codec.api.MsgCodec; 13 | 14 | import javax.annotation.PostConstruct; 15 | 16 | @Log4j2 17 | @Configuration 18 | @Data 19 | public class CounterConfig { 20 | 21 | @Autowired 22 | CounterProperty counterProperty; 23 | 24 | @Autowired 25 | MsgCodec msgCodec; 26 | 27 | @Autowired 28 | CheckSum checkSum; 29 | 30 | @Autowired 31 | Vertx socketVertx; 32 | 33 | @PostConstruct 34 | private void init() { 35 | new MqttBusConsumer(counterProperty.getSubbusIp(), 36 | counterProperty.getSubbusPort(), 37 | String.valueOf(counterProperty.getId()), 38 | msgCodec, checkSum, socketVertx).startUp(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/order/CmdType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | public enum CmdType { 4 | 5 | ///////////////委托类////////////// 6 | NEW_ORDER(0), 7 | CANCEL_ORDER(1), 8 | 9 | //////权限类(交易所几乎没有用过,都是盘后改,初始化的时候载入新数据)//////// 10 | SUSPEND_USER(2), 11 | RESUME_USER(3), 12 | 13 | ///////////////状态类////////////// 14 | SHUTDOWN_ENGINE(4), 15 | 16 | ///////////////查询类////////////// 17 | BINARY_DATA(5), 18 | ORDER_BOOK_REQUEST(6), 19 | 20 | ///////////////行情类////////////// 21 | HQ_PUB(7), 22 | 23 | 24 | ///////////////资金类////////////// 25 | BALANCE_ADJUSTMENT(8); 26 | 27 | private short type; 28 | 29 | CmdType(int type) { 30 | this.type = (short) type; 31 | } 32 | 33 | public static CmdType of(short type) { 34 | //柜台只能处理三种 35 | switch (type) { 36 | case 0: 37 | return NEW_ORDER; 38 | case 1: 39 | return CANCEL_ORDER; 40 | case 8: 41 | return BALANCE_ADJUSTMENT; 42 | default: 43 | throw new IllegalArgumentException("unknown CmdType:" + type); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/order/CmdType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | public enum CmdType { 4 | 5 | ///////////////委托类////////////// 6 | NEW_ORDER(0), 7 | CANCEL_ORDER(1), 8 | 9 | //////权限类(交易所几乎没有用过,都是盘后改,初始化的时候载入新数据)//////// 10 | SUSPEND_USER(2), 11 | RESUME_USER(3), 12 | 13 | ///////////////状态类////////////// 14 | SHUTDOWN_ENGINE(4), 15 | 16 | ///////////////查询类////////////// 17 | BINARY_DATA(5), 18 | ORDER_BOOK_REQUEST(6), 19 | 20 | ///////////////行情类////////////// 21 | HQ_PUB(7), 22 | 23 | 24 | ///////////////资金类////////////// 25 | BALANCE_ADJUSTMENT(8); 26 | 27 | private short type; 28 | 29 | CmdType(int type) { 30 | this.type = (short) type; 31 | } 32 | 33 | public static CmdType of(short type) { 34 | //柜台只能处理三种 35 | switch (type) { 36 | case 0: 37 | return NEW_ORDER; 38 | case 1: 39 | return CANCEL_ORDER; 40 | case 8: 41 | return BALANCE_ADJUSTMENT; 42 | default: 43 | throw new IllegalArgumentException("unknown CmdType:" + type); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/order/CmdType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | public enum CmdType { 4 | 5 | ///////////////委托类////////////// 6 | NEW_ORDER(0), 7 | CANCEL_ORDER(1), 8 | 9 | //////权限类(交易所几乎没有用过,都是盘后改,初始化的时候载入新数据)//////// 10 | SUSPEND_USER(2), 11 | RESUME_USER(3), 12 | 13 | ///////////////状态类////////////// 14 | SHUTDOWN_ENGINE(4), 15 | 16 | ///////////////查询类////////////// 17 | BINARY_DATA(5), 18 | ORDER_BOOK_REQUEST(6), 19 | 20 | ///////////////行情类////////////// 21 | HQ_PUB(7), 22 | 23 | 24 | ///////////////资金类////////////// 25 | BALANCE_ADJUSTMENT(8); 26 | 27 | private short type; 28 | 29 | CmdType(int type) { 30 | this.type = (short) type; 31 | } 32 | 33 | public static CmdType of(short type) { 34 | //柜台只能处理三种 35 | switch (type) { 36 | case 0: 37 | return NEW_ORDER; 38 | case 1: 39 | return CANCEL_ORDER; 40 | case 8: 41 | return BALANCE_ADJUSTMENT; 42 | default: 43 | throw new IllegalArgumentException("unknown CmdType:" + type); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/order/CmdType.java: -------------------------------------------------------------------------------- 1 | package thirdpart.order; 2 | 3 | public enum CmdType { 4 | 5 | ///////////////委托类////////////// 6 | NEW_ORDER(0), 7 | CANCEL_ORDER(1), 8 | 9 | //////权限类(交易所几乎没有用过,都是盘后改,初始化的时候载入新数据)//////// 10 | SUSPEND_USER(2), 11 | RESUME_USER(3), 12 | 13 | ///////////////状态类////////////// 14 | SHUTDOWN_ENGINE(4), 15 | 16 | ///////////////查询类////////////// 17 | BINARY_DATA(5), 18 | ORDER_BOOK_REQUEST(6), 19 | 20 | ///////////////行情类////////////// 21 | HQ_PUB(7), 22 | 23 | 24 | ///////////////资金类////////////// 25 | BALANCE_ADJUSTMENT(8); 26 | 27 | private short type; 28 | 29 | CmdType(int type) { 30 | this.type = (short) type; 31 | } 32 | 33 | public static CmdType of(short type) { 34 | //柜台只能处理三种 35 | switch (type) { 36 | case 0: 37 | return NEW_ORDER; 38 | case 1: 39 | return CANCEL_ORDER; 40 | case 8: 41 | return BALANCE_ADJUSTMENT; 42 | default: 43 | throw new IllegalArgumentException("unknown CmdType:" + type); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cfront/src/api/formatter.js: -------------------------------------------------------------------------------- 1 | import {constants} from './constants' 2 | 3 | //股票代码 4 | export const codeFormat = (code) => { 5 | // 1 -> 000001 6 | return ('000000' + code).slice(-6); 7 | }; 8 | 9 | //资金 10 | export const moneyFormat = (money) => { 11 | return (money / constants.MULTI_FACTOR).toFixed(2) 12 | }; 13 | 14 | //委托方向 15 | export const directionFormat = (direction) => { 16 | if (direction == constants.BUY) { 17 | return "买入"; 18 | } else if (direction == constants.SELL) { 19 | return "卖出"; 20 | } else { 21 | return "未知"; 22 | } 23 | }; 24 | 25 | //委托状态 26 | export const statusFormat = (status) => { 27 | switch (status) { 28 | case constants.NOT_ORDER: 29 | return '未报'; 30 | case constants.CANCELED: 31 | return '已撤'; 32 | case constants.PART_CANCELED: 33 | return '部撤'; 34 | case constants.ORDERED: 35 | return '已报'; 36 | case constants.TRADED: 37 | return '已成'; 38 | case constants.PART_TRADED: 39 | return '部成'; 40 | case constants.ILLEGAL: 41 | return '废单'; 42 | default: 43 | return '未知'; 44 | } 45 | }; -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/bean/res/CounterRes.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.bean.res; 2 | 3 | /** 4 | * 通用返回格式 5 | */ 6 | public class CounterRes { 7 | 8 | public static final int SUCCESS = 0; 9 | public static final int RELOGIN = 1; 10 | public static final int FAIL = 2; 11 | 12 | private int code; 13 | 14 | private String message; 15 | 16 | private Object data; 17 | 18 | public CounterRes() {} 19 | 20 | public CounterRes(int code, String message, Object data) { 21 | this.code = code; 22 | this.message = message; 23 | this.data = data; 24 | } 25 | 26 | public CounterRes(Object data) { 27 | this(SUCCESS, "", data); 28 | } 29 | 30 | public int getCode() { 31 | return code; 32 | } 33 | 34 | public void setCode(int code) { 35 | this.code = code; 36 | } 37 | 38 | public String getMessage() { 39 | return message; 40 | } 41 | 42 | public void setMessage(String message) { 43 | this.message = message; 44 | } 45 | 46 | public Object getData() { 47 | return data; 48 | } 49 | 50 | public void setData(Object data) { 51 | this.data = data; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/api/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.api; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.star.counter.bean.OrderInfo; 5 | import thirdpart.order.OrderCmd; 6 | import thirdpart.order.OrderStatus; 7 | 8 | import java.util.List; 9 | 10 | public interface OrderService { 11 | 12 | List getOrderListByUid(long uid) throws JsonProcessingException; 13 | 14 | /** 15 | * 保存订单信息 16 | * @param orderCmd 订单信息 17 | * @return 操作状态码 18 | */ 19 | int saveOrder(OrderCmd orderCmd); 20 | 21 | /** 22 | * 发送订单信息 23 | * @param uid 用户id 24 | * @param type 委托指令的类型 25 | * @param timestamp 时间戳 26 | * @param code 股票代码 27 | * @param direction 交易方向 28 | * @param price 价格 29 | * @param volume 量 30 | * @param ordertype 委托类型 31 | * @return 委托信息是否保存成功 32 | */ 33 | boolean sendOrder(long uid, short type, long timestamp, int code, byte direction, long price, long volume, byte ordertype); 34 | 35 | void updateOrder(long uid, int counterOid, OrderStatus finalOrderStatus); 36 | 37 | //撤单 38 | boolean cancelOrder(int uid, int counteroid, int code); 39 | } 40 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/command/RbCmd.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean.command; 2 | 3 | import com.star.engine.bean.orderbook.MatchEvent; 4 | import javafx.event.Event; 5 | import lombok.Builder; 6 | import lombok.ToString; 7 | import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap; 8 | import thirdpart.hq.L1MarketData; 9 | import thirdpart.order.CmdType; 10 | import thirdpart.order.OrderDirection; 11 | import thirdpart.order.OrderType; 12 | 13 | import java.util.List; 14 | 15 | @Builder 16 | @ToString 17 | public class RbCmd { 18 | 19 | public long timestamp; 20 | 21 | public short mid; 22 | 23 | public long uid; 24 | 25 | public CmdType command; 26 | 27 | public int code; 28 | 29 | public OrderDirection direction; 30 | 31 | public long price; 32 | 33 | public long volume; 34 | 35 | public long oid; 36 | 37 | public OrderType orderType; 38 | 39 | // 保存撮合结果 40 | public List matchEventList; 41 | 42 | // 前置风控 --> 撮合 --> 发布 43 | public CmdResultCode resultCode; 44 | 45 | /** 46 | * 保存行情 47 | * key:股票代码 48 | * value:五档行情 49 | */ 50 | public IntObjectHashMap marketDataMap; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/bean/CommonMsg.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | import lombok.*; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 网关内外沟通用消息体 9 | */ 10 | @Data 11 | @ToString 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class CommonMsg implements Serializable { 15 | 16 | // 包头[ 包体长度 int + 校验和 byte + src short+ dst short + 消息类型 short + 消息状态 byte + 包编号 long ] 17 | // 包体[ 数据 byte[] ] 18 | 19 | /** 20 | * 包体长度 21 | */ 22 | private int bodyLength; 23 | 24 | /** 25 | * 校验和 26 | */ 27 | private byte checksum; 28 | 29 | /** 30 | * 数据源 31 | */ 32 | private short msgSrc; 33 | 34 | /** 35 | * 数据目的地 36 | */ 37 | private short msgDst; 38 | 39 | /** 40 | * 消息类型 41 | */ 42 | private short msgType; 43 | 44 | /** 45 | * 消息状态 46 | */ 47 | private byte status; 48 | 49 | /** 50 | * 包编号(UUID) 51 | */ 52 | private long msgNo; 53 | 54 | /** 55 | * 包体 56 | */ 57 | @ToString.Exclude 58 | private byte[] body; 59 | 60 | 61 | //////////////////////////////// 62 | private boolean isLegal; 63 | 64 | private short errCode; 65 | 66 | private long timestamp; 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /gateway/src/main/java/com/star/gateway/GatewayStartup.java: -------------------------------------------------------------------------------- 1 | package com.star.gateway; 2 | 3 | import com.star.gateway.config.GatewayConfig; 4 | import lombok.extern.log4j.Log4j2; 5 | import org.dom4j.DocumentException; 6 | import thirdpart.checksum.impl.CheckSumImpl; 7 | import thirdpart.codec.impl.BodyCodecImpl; 8 | 9 | import java.io.FileInputStream; 10 | import java.io.InputStream; 11 | 12 | @Log4j2 13 | public class GatewayStartup { 14 | public static void main(String[] args) throws DocumentException { 15 | String configFileName = "gateway.xml"; 16 | GatewayConfig config = new GatewayConfig(); 17 | 18 | //将配置的xml文件作为输入流 19 | InputStream inputStream; 20 | try { 21 | inputStream = new FileInputStream(System.getProperty("user.dir") + "\\" + configFileName); 22 | log.info("gateway.xml exist in jar path"); 23 | } catch (Exception e) { 24 | inputStream = GatewayStartup.class.getResourceAsStream("/" + configFileName); 25 | log.info("gateway.xml exist in jar file"); 26 | } 27 | config.initConfig(inputStream); 28 | config.setBodyCodec(new BodyCodecImpl()); 29 | config.setCheckSumImpl(new CheckSumImpl()); 30 | config.startup(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /gateway/src/main/java/com/star/gateway/container/OrderCmdContainer.java: -------------------------------------------------------------------------------- 1 | package com.star.gateway.container; 2 | 3 | import com.google.common.collect.Lists; 4 | import thirdpart.order.OrderCmd; 5 | 6 | import java.util.List; 7 | import java.util.concurrent.BlockingDeque; 8 | import java.util.concurrent.LinkedBlockingDeque; 9 | 10 | /** 11 | * 单例 12 | */ 13 | public class OrderCmdContainer { 14 | 15 | //将实例加载为私有静态 16 | private static OrderCmdContainer ourInstance = new OrderCmdContainer(); 17 | 18 | //私有的构造方法 19 | private OrderCmdContainer(){} 20 | 21 | //公共的getInstance方法 22 | public static OrderCmdContainer getInstance() { 23 | return ourInstance; 24 | } 25 | 26 | private final BlockingDeque deque = new LinkedBlockingDeque<>(); 27 | 28 | public boolean cache(OrderCmd cmd) { 29 | return deque.offer(cmd); 30 | } 31 | 32 | public List getAll() { 33 | List msgList = Lists.newArrayList(); 34 | //drainTo非阻塞并且将所有数据一次性去除并且清空 35 | int count = deque.drainTo(msgList); 36 | if (count == 0) { 37 | //防止返回空列表 38 | return null; 39 | } else { 40 | return msgList; 41 | } 42 | } 43 | 44 | public int size() { 45 | return deque.size(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mqtt/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.star 8 | mqtt 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 8 13 | 8 14 | UTF-8 15 | 16 | 17 | 18 | 19 | io.vertx 20 | vertx-core 21 | 3.8.5 22 | 23 | 24 | io.vertx 25 | vertx-mqtt 26 | 3.8.5 27 | 28 | 29 | org.projectlombok 30 | lombok 31 | 1.18.24 32 | 33 | 34 | -------------------------------------------------------------------------------- /counter/src/main/resources/com/star/counter/mapper/PosiMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | UPDATE t_posi SET count = count + #{volume}, cost = cost + #{volume} * #{price} 17 | WHERE uid = #{uid} AND code = #{code} 18 | 19 | 20 | 25 | 26 | 27 | INSERT INTO t_posi(uid, code, cost, count) 28 | VALUES (#{uid}, #{code}, #{volume} * #{price}, #{volume}) 29 | 30 | 31 | -------------------------------------------------------------------------------- /counter/src/main/resources/com/star/counter/mapper/OrderMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | INSERT INTO t_order(uid, code, direction, type, price, ocount, status, date, time) 17 | VALUES (#{uid}, #{code}, #{direction}, #{type}, #{price}, #{ocount}, #{status}, #{date}, #{time}) 18 | 19 | 20 | 21 | 22 | 23 | 24 | UPDATE t_order SET status = #{status} WHERE id = #{oid} 25 | 26 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/bean/CommonMsg.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * 网关内外沟通用消息体 12 | */ 13 | @Data 14 | @ToString 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class CommonMsg implements Serializable { 18 | 19 | // 包头[ 包体长度 int + 校验和 byte + src short+ dst short + 消息类型 short + 消息状态 byte + 包编号 long ] 20 | // 包体[ 数据 byte[] ] 21 | 22 | /** 23 | * 包体长度 24 | */ 25 | private int bodyLength; 26 | 27 | /** 28 | * 校验和 29 | */ 30 | private byte checksum; 31 | 32 | /** 33 | * 数据源 34 | */ 35 | private short msgSrc; 36 | 37 | /** 38 | * 数据目的地 39 | */ 40 | private short msgDst; 41 | 42 | /** 43 | * 消息类型 44 | */ 45 | private short msgType; 46 | 47 | /** 48 | * 消息状态 49 | */ 50 | private byte status; 51 | 52 | /** 53 | * 包编号(UUID) 54 | */ 55 | private long msgNo; 56 | 57 | /** 58 | * 包体 59 | */ 60 | @ToString.Exclude 61 | private byte[] body; 62 | 63 | 64 | //////////////////////////////// 65 | private boolean isLegal; 66 | 67 | private short errCode; 68 | 69 | private long timestamp; 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/bean/CommonMsg.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * 网关内外沟通用消息体 12 | */ 13 | @Data 14 | @ToString 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class CommonMsg implements Serializable { 18 | 19 | // 包头[ 包体长度 int + 校验和 byte + src short + dst short + 消息类型 short + 消息状态 byte + 包编号 long ] 20 | // 包体[ 数据 byte[] ] 21 | 22 | /** 23 | * 包体长度 24 | */ 25 | private int bodyLength; 26 | 27 | /** 28 | * 校验和 29 | */ 30 | private byte checksum; 31 | 32 | /** 33 | * 数据源 34 | */ 35 | private short msgSrc; 36 | 37 | /** 38 | * 数据目的地 39 | */ 40 | private short msgDst; 41 | 42 | /** 43 | * 消息类型 44 | */ 45 | private short msgType; 46 | 47 | /** 48 | * 消息状态 49 | */ 50 | private byte status; 51 | 52 | /** 53 | * 包编号(UUID) 54 | */ 55 | private long msgNo; 56 | 57 | /** 58 | * 包体 59 | */ 60 | @ToString.Exclude 61 | private byte[] body; 62 | 63 | 64 | //////////////////////////////// 65 | private boolean isLegal; 66 | 67 | private short errCode; 68 | 69 | private long timestamp; 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/bean/CommonMsg.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * 网关内外沟通用消息体 12 | */ 13 | @Data 14 | @ToString 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class CommonMsg implements Serializable { 18 | 19 | // 包头[ 包体长度 int + 校验和 byte + src short+ dst short + 消息类型 short + 消息状态 byte + 包编号 long ] 20 | // 包体[ 数据 byte[] ] 21 | 22 | /** 23 | * 包体长度 24 | */ 25 | private int bodyLength; 26 | 27 | /** 28 | * 校验和 29 | */ 30 | private byte checksum; 31 | 32 | /** 33 | * 数据源 34 | */ 35 | private short msgSrc; 36 | 37 | /** 38 | * 数据目的地 39 | */ 40 | private short msgDst; 41 | 42 | /** 43 | * 消息类型 44 | */ 45 | private short msgType; 46 | 47 | /** 48 | * 消息状态 49 | */ 50 | private byte status; 51 | 52 | /** 53 | * 包编号(UUID) 54 | */ 55 | private long msgNo; 56 | 57 | /** 58 | * 包体 59 | */ 60 | @ToString.Exclude 61 | private byte[] body; 62 | 63 | 64 | //////////////////////////////// 65 | private boolean isLegal; 66 | 67 | private short errCode; 68 | 69 | private long timestamp; 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /cfront/src/views/Buy.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 49 | 50 | -------------------------------------------------------------------------------- /cfront/src/views/Sell.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 49 | 50 | -------------------------------------------------------------------------------- /cfront/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cfront", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "electron:build": "vue-cli-service electron:build", 9 | "electron:serve": "vue-cli-service electron:serve", 10 | "postinstall": "electron-builder install-app-deps", 11 | "postuninstall": "electron-builder install-app-deps" 12 | }, 13 | "main": "background.js", 14 | "dependencies": { 15 | "axios": "^1.3.2", 16 | "core-js": "^3.8.3", 17 | "element-ui": "^2.15.12", 18 | "js-md5": "^0.7.3", 19 | "moment": "^2.24.0", 20 | "qs": "^6.11.0", 21 | "vue": "^2.6.14", 22 | "vue-bus": "^1.2.1", 23 | "vue-router": "^3.5.1", 24 | "vue-vertx3-eventbus-client": "^3.5.3", 25 | "vuex": "^3.6.2" 26 | }, 27 | "devDependencies": { 28 | "@vue/cli-plugin-babel": "~5.0.0", 29 | "@vue/cli-plugin-router": "~5.0.0", 30 | "@vue/cli-plugin-vuex": "~5.0.0", 31 | "@vue/cli-service": "~5.0.0", 32 | "electron": "^13.0.0", 33 | "electron-devtools-installer": "^3.1.0", 34 | "sass": "^1.32.7", 35 | "sass-loader": "^12.0.0", 36 | "vue-cli-plugin-electron-builder": "~2.1.1", 37 | "vue-devtools": "^5.1.4", 38 | "vue-template-compiler": "^2.6.14" 39 | }, 40 | "browserslist": [ 41 | "> 1%", 42 | "last 2 versions", 43 | "not dead" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/hq/L1MarketData.java: -------------------------------------------------------------------------------- 1 | package thirdpart.hq; 2 | 3 | import lombok.ToString; 4 | 5 | import java.io.Serializable; 6 | 7 | @ToString 8 | public class L1MarketData implements Serializable { 9 | /** 10 | * 5档 11 | */ 12 | @ToString.Exclude 13 | public static final int L1_SIZE = 5; 14 | 15 | public int code; 16 | 17 | public long newPrice; 18 | 19 | /** 20 | * 买卖实际档位数量 21 | */ 22 | @ToString.Exclude 23 | public transient int buySize; 24 | 25 | @ToString.Exclude 26 | public transient int sellSize; 27 | 28 | public long[] buyPrices; 29 | public long[] buyVolumes; 30 | public long[] sellPrices; 31 | public long[] sellVolumes; 32 | 33 | public long timestamp; 34 | 35 | public L1MarketData(long[] buyPrices, long[] buyVolumes, 36 | long[] sellPrices, long[] sellVolumes) { 37 | this.buyPrices = buyPrices; 38 | this.buyVolumes = buyVolumes; 39 | this.sellPrices = sellPrices; 40 | this.sellVolumes = sellVolumes; 41 | 42 | this.buySize = buyPrices.length; 43 | this.sellSize = sellPrices.length; 44 | } 45 | 46 | public L1MarketData(int buySize, int sellSize) { 47 | this.buyPrices = new long[buySize]; 48 | this.buyVolumes = new long[buySize]; 49 | this.sellPrices = new long[sellSize]; 50 | this.sellVolumes = new long[sellSize]; 51 | } 52 | } -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/hq/L1MarketData.java: -------------------------------------------------------------------------------- 1 | package thirdpart.hq; 2 | 3 | import lombok.ToString; 4 | 5 | import java.io.Serializable; 6 | 7 | @ToString 8 | public class L1MarketData implements Serializable { 9 | /** 10 | * 5档 11 | */ 12 | @ToString.Exclude 13 | public static final int L1_SIZE = 5; 14 | 15 | public int code; 16 | 17 | public long newPrice; 18 | 19 | /** 20 | * 买卖实际档位数量 21 | */ 22 | @ToString.Exclude 23 | public transient int buySize; 24 | 25 | @ToString.Exclude 26 | public transient int sellSize; 27 | 28 | public long[] buyPrices; 29 | public long[] buyVolumes; 30 | public long[] sellPrices; 31 | public long[] sellVolumes; 32 | 33 | public long timestamp; 34 | 35 | public L1MarketData(long[] buyPrices, long[] buyVolumes, 36 | long[] sellPrices, long[] sellVolumes) { 37 | this.buyPrices = buyPrices; 38 | this.buyVolumes = buyVolumes; 39 | this.sellPrices = sellPrices; 40 | this.sellVolumes = sellVolumes; 41 | 42 | this.buySize = buyPrices.length; 43 | this.sellSize = sellPrices.length; 44 | } 45 | 46 | public L1MarketData(int buySize, int sellSize) { 47 | this.buyPrices = new long[buySize]; 48 | this.buyVolumes = new long[buySize]; 49 | this.sellPrices = new long[sellSize]; 50 | this.sellVolumes = new long[sellSize]; 51 | } 52 | } -------------------------------------------------------------------------------- /engine/src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/config/GatewayConfig.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.config; 2 | 3 | import com.star.counter.property.CounterProperty; 4 | import io.vertx.core.Vertx; 5 | import lombok.extern.log4j.Log4j2; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import thirdpart.checksum.api.CheckSum; 10 | import thirdpart.checksum.impl.CheckSumImpl; 11 | import thirdpart.codec.api.BodyCodec; 12 | import thirdpart.codec.api.MsgCodec; 13 | import thirdpart.codec.impl.BodyCodecImpl; 14 | import thirdpart.codec.impl.MsgCodecImpl; 15 | import thirdpart.tcp.TcpDirectSender; 16 | 17 | @Log4j2 18 | @Configuration 19 | public class GatewayConfig { 20 | 21 | @Autowired 22 | CounterProperty counterProperty; 23 | 24 | @Bean 25 | public CheckSum checkSum() { 26 | return new CheckSumImpl(); 27 | } 28 | 29 | @Bean 30 | public BodyCodec bodyCodec() { 31 | return new BodyCodecImpl(); 32 | } 33 | 34 | @Bean 35 | public MsgCodec msgCodec() { 36 | return new MsgCodecImpl(); 37 | } 38 | 39 | // @Bean 40 | // public Vertx sendVertx() { 41 | // return Vertx.vertx(); 42 | // }; 43 | // 44 | // @Bean 45 | // public Vertx socketVertx() { 46 | // return Vertx.vertx(); 47 | // } 48 | 49 | @Bean 50 | public Vertx vertx() { 51 | return Vertx.vertx(); 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/handler/match/StockMatchHandler.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.handler.match; 2 | 3 | import com.star.engine.bean.command.CmdResultCode; 4 | import com.star.engine.bean.command.RbCmd; 5 | import com.star.engine.bean.orderbook.api.OrderBook; 6 | import com.star.engine.handler.BaseHandler; 7 | import lombok.NonNull; 8 | import lombok.RequiredArgsConstructor; 9 | import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap; 10 | 11 | @RequiredArgsConstructor 12 | public class StockMatchHandler extends BaseHandler { 13 | 14 | @NonNull 15 | private final IntObjectHashMap orderBookMap; 16 | 17 | @Override 18 | public void onEvent(RbCmd cmd, long sequence, boolean endOfBatch) throws Exception { 19 | if (cmd.resultCode.getCode() < 0) { //小于0均为非法状态 20 | return; 21 | } 22 | cmd.resultCode = processCmd(cmd); 23 | } 24 | 25 | private CmdResultCode processCmd(RbCmd cmd) { 26 | switch (cmd.command) { 27 | case NEW_ORDER: 28 | return orderBookMap.get(cmd.code).newOrder(cmd); 29 | case CANCEL_ORDER: 30 | return orderBookMap.get(cmd.code).cancelOrder(cmd); 31 | case HQ_PUB: 32 | orderBookMap.forEachKeyValue((code, orderBook) -> { 33 | cmd.marketDataMap.put(code, orderBook.getL1MarketDataSnapshot()); 34 | }); 35 | default: 36 | return CmdResultCode.SUCCESS; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /gateway/src/main/java/com/star/gateway/handler/MsgHandler.java: -------------------------------------------------------------------------------- 1 | package com.star.gateway.handler; 2 | 3 | import com.star.gateway.container.OrderCmdContainer; 4 | import io.vertx.core.net.NetSocket; 5 | import lombok.AllArgsConstructor; 6 | import lombok.NoArgsConstructor; 7 | import lombok.extern.log4j.Log4j2; 8 | import thirdpart.bean.CommonMsg; 9 | import thirdpart.codec.api.BodyCodec; 10 | import thirdpart.order.OrderCmd; 11 | 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @Log4j2 15 | public class MsgHandler { 16 | 17 | private BodyCodec bodyCodec; 18 | 19 | void onConnect(NetSocket socket) { 20 | 21 | } 22 | 23 | void onDisConnect(NetSocket socket) { 24 | 25 | } 26 | 27 | void onException(NetSocket socket, Throwable e) { 28 | 29 | } 30 | 31 | void onCounterData(CommonMsg msg) { 32 | OrderCmd orderCmd; 33 | try { 34 | //将包体内容转为OrderCmd对象 35 | orderCmd = bodyCodec.deserialize(msg.getBody(), OrderCmd.class); 36 | //正式开发环境中不能在运行时输出 37 | log.info("recv cmd:{}", orderCmd); 38 | log.info(orderCmd.toString()); 39 | //写入内存:将OrderCmd对象存储到静态OrderCmdContainer内,失败时日志输出 40 | if (!OrderCmdContainer.getInstance().cache(orderCmd)) { 41 | log.error("gateway queue insert fail, queue length:{}, order:{}", OrderCmdContainer.getInstance().size(), orderCmd); 42 | } 43 | } catch (Exception e) { 44 | log.error("decode order cmd error", e); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /gateway/dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.star 5 | gateway 6 | 1.0-SNAPSHOT 7 | 8 | gateway-1.0-SNAPSHOT 9 | 10 | 11 | maven-shade-plugin 12 | 3.2.4 13 | 14 | 15 | package 16 | 17 | shade 18 | 19 | 20 | 21 | 22 | com.star.gateway.GatewayStartup 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.projectlombok 34 | lombok 35 | 1.18.26 36 | provided 37 | 38 | 39 | 40 | UTF-8 41 | 8 42 | 8 43 | 44 | 45 | -------------------------------------------------------------------------------- /seq/src/main/java/com/star/seq/bean/Node.java: -------------------------------------------------------------------------------- 1 | package com.star.seq.bean; 2 | 3 | import com.alipay.sofa.jraft.rhea.LeaderStateListener; 4 | import com.alipay.sofa.jraft.rhea.client.DefaultRheaKVStore; 5 | import com.alipay.sofa.jraft.rhea.client.RheaKVStore; 6 | import com.alipay.sofa.jraft.rhea.options.RheaKVStoreOptions; 7 | import lombok.Data; 8 | import lombok.NonNull; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.log4j.Log4j2; 11 | 12 | import java.util.concurrent.atomic.AtomicLong; 13 | 14 | @Log4j2 15 | @RequiredArgsConstructor 16 | @Data 17 | public class Node { 18 | 19 | @NonNull 20 | private final RheaKVStoreOptions options; 21 | 22 | private RheaKVStore rheaKVStore; 23 | 24 | private final AtomicLong leaderTerm = new AtomicLong(-1); 25 | 26 | public boolean isLeader() { 27 | //LeaderTerm值大于0则说明此节点为主节点 28 | return leaderTerm.get() > 0; 29 | } 30 | 31 | public void stop(){ 32 | rheaKVStore.shutdown(); 33 | } 34 | 35 | public void start(){ 36 | //初始化KVStore 37 | rheaKVStore = new DefaultRheaKVStore(); 38 | rheaKVStore.init(this.options); 39 | //监听节点状态 40 | rheaKVStore.addLeaderStateListener(-1, new LeaderStateListener() { 41 | @Override 42 | public void onLeaderStart(long newTerm) { 43 | log.info("node become leader"); 44 | leaderTerm.set(newTerm); 45 | } 46 | 47 | @Override 48 | public void onLeaderStop(long oldTerm) { 49 | //<0时说明已经不是leader节点 50 | leaderTerm.set(-1); 51 | } 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/codec/impl/MsgCodecImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.impl; 2 | 3 | import io.vertx.core.buffer.Buffer; 4 | import thirdpart.bean.CommonMsg; 5 | import thirdpart.codec.api.MsgCodec; 6 | 7 | public class MsgCodecImpl implements MsgCodec { 8 | @Override 9 | public Buffer encodeToBuffer(CommonMsg msg) { 10 | return Buffer.buffer() 11 | .appendInt(msg.getBodyLength()) 12 | .appendByte(msg.getChecksum()) 13 | .appendShort(msg.getMsgSrc()) 14 | .appendShort(msg.getMsgDst()) 15 | .appendShort(msg.getMsgType()) 16 | .appendByte(msg.getStatus()) 17 | .appendLong(msg.getMsgNo()) 18 | .appendBytes(msg.getBody()); 19 | } 20 | 21 | @Override 22 | public CommonMsg decodeFromBuffer(Buffer buffer) { 23 | int bodyLength = buffer.getInt(0); 24 | byte checkSum = buffer.getByte(4); 25 | short msgSrc = buffer.getShort(5); 26 | short msgDst = buffer.getShort(7); 27 | short msgType = buffer.getShort(9); 28 | byte status = buffer.getByte(11); 29 | long msgNo = buffer.getLong(12); 30 | byte[] body = buffer.getBytes(20, 20 + bodyLength); 31 | CommonMsg commonMsg = new CommonMsg(); 32 | commonMsg.setBodyLength(bodyLength); 33 | commonMsg.setChecksum(checkSum); 34 | commonMsg.setMsgSrc(msgSrc); 35 | commonMsg.setMsgDst(msgDst); 36 | commonMsg.setMsgType(msgType); 37 | commonMsg.setStatus(status); 38 | commonMsg.setMsgNo(msgNo); 39 | commonMsg.setBody(body); 40 | return commonMsg; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/codec/impl/MsgCodecImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.impl; 2 | 3 | import io.vertx.core.buffer.Buffer; 4 | import thirdpart.bean.CommonMsg; 5 | import thirdpart.codec.api.MsgCodec; 6 | 7 | public class MsgCodecImpl implements MsgCodec { 8 | @Override 9 | public Buffer encodeToBuffer(CommonMsg msg) { 10 | return Buffer.buffer() 11 | .appendInt(msg.getBodyLength()) 12 | .appendByte(msg.getChecksum()) 13 | .appendShort(msg.getMsgSrc()) 14 | .appendShort(msg.getMsgDst()) 15 | .appendShort(msg.getMsgType()) 16 | .appendByte(msg.getStatus()) 17 | .appendLong(msg.getMsgNo()) 18 | .appendBytes(msg.getBody()); 19 | } 20 | 21 | @Override 22 | public CommonMsg decodeFromBuffer(Buffer buffer) { 23 | int bodyLength = buffer.getInt(0); 24 | byte checkSum = buffer.getByte(4); 25 | short msgSrc = buffer.getShort(5); 26 | short msgDst = buffer.getShort(7); 27 | short msgType = buffer.getShort(9); 28 | byte status = buffer.getByte(11); 29 | long msgNo = buffer.getLong(12); 30 | byte[] body = buffer.getBytes(20, 20 + bodyLength); 31 | CommonMsg commonMsg = new CommonMsg(); 32 | commonMsg.setBodyLength(bodyLength); 33 | commonMsg.setChecksum(checkSum); 34 | commonMsg.setMsgSrc(msgSrc); 35 | commonMsg.setMsgDst(msgDst); 36 | commonMsg.setMsgType(msgType); 37 | commonMsg.setStatus(status); 38 | commonMsg.setMsgNo(msgNo); 39 | commonMsg.setBody(body); 40 | return commonMsg; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/codec/impl/MsgCodecImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.codec.impl; 2 | 3 | import io.vertx.core.buffer.Buffer; 4 | import thirdpart.bean.CommonMsg; 5 | import thirdpart.codec.api.MsgCodec; 6 | 7 | public class MsgCodecImpl implements MsgCodec { 8 | @Override 9 | public Buffer encodeToBuffer(CommonMsg msg) { 10 | return Buffer.buffer() 11 | .appendInt(msg.getBodyLength()) 12 | .appendByte(msg.getChecksum()) 13 | .appendShort(msg.getMsgSrc()) 14 | .appendShort(msg.getMsgDst()) 15 | .appendShort(msg.getMsgType()) 16 | .appendByte(msg.getStatus()) 17 | .appendLong(msg.getMsgNo()) 18 | .appendBytes(msg.getBody()); 19 | } 20 | 21 | @Override 22 | public CommonMsg decodeFromBuffer(Buffer buffer) { 23 | int bodyLength = buffer.getInt(0); 24 | byte checkSum = buffer.getByte(4); 25 | short msgSrc = buffer.getShort(5); 26 | short msgDst = buffer.getShort(7); 27 | short msgType = buffer.getShort(9); 28 | byte status = buffer.getByte(11); 29 | long msgNo = buffer.getLong(12); 30 | byte[] body = buffer.getBytes(20, 20 + bodyLength); 31 | CommonMsg commonMsg = new CommonMsg(); 32 | commonMsg.setBodyLength(bodyLength); 33 | commonMsg.setChecksum(checkSum); 34 | commonMsg.setMsgSrc(msgSrc); 35 | commonMsg.setMsgDst(msgDst); 36 | commonMsg.setMsgType(msgType); 37 | commonMsg.setStatus(status); 38 | commonMsg.setMsgNo(msgNo); 39 | commonMsg.setBody(body); 40 | return commonMsg; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /seq/src/main/java/thirdpart/bean/MsgConstants.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | public class MsgConstants { 4 | 5 | 6 | //消息来源 7 | // public static final byte COUNTER = 0; 8 | // public static final byte GATEWAY = 1; 9 | // public static final byte SEQUENCER = 2; 10 | // public static final byte MATCH = 3; 11 | 12 | /////////////////////////////////////////////////// 13 | 14 | 15 | //来自柜台 IN 0 -5000 16 | public static final short COUNTER_CONNECT = 0; 17 | public static final short COUNTER_DISCONNECT = 1; 18 | public static final short COUNTER_NEW_ORDER = 2; 19 | public static final short COUNTER_CANCEL_ORDER = 3; 20 | public static final short COUNTER_PING = 4; 21 | 22 | public static final short COUNTER_MSG_TYPE_MIN = 0; 23 | public static final short COUNTER_MSG_TYPE_MAX = 5000; 24 | 25 | 26 | //来自撮合核心5001-10000 27 | public static final short MATCH_ORDER_DATA = 5001; 28 | public static final short MATCH_HQ_DATA = 5002; 29 | 30 | public static final short MATCH_MSG_TYPE_MIN = 5001; 31 | public static final short MATCH_MSG_TYPE_MAX = 10000; 32 | 33 | 34 | //其他10001- 35 | public static final short ERROR = 10001; 36 | public static final short TEST = 10002; 37 | 38 | /////////////////////////////////////////////////// 39 | 40 | //消息状态 41 | public static final byte NORMAL = 0; 42 | public static final byte CS_NOT_MATCH = 1; 43 | public static final byte GW_OFF = 2; 44 | public static final byte CACHE_FULL = 3; 45 | public static final byte REJECTED = 4; 46 | 47 | 48 | //////////////////////交易所状态/////////////////////// 49 | public static final int ON = 1; 50 | 51 | public static final int OFF = 0; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /counter/src/main/java/thirdpart/bean/MsgConstants.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | public class MsgConstants { 4 | 5 | 6 | //消息来源 7 | // public static final byte COUNTER = 0; 8 | // public static final byte GATEWAY = 1; 9 | // public static final byte SEQUENCER = 2; 10 | // public static final byte MATCH = 3; 11 | 12 | /////////////////////////////////////////////////// 13 | 14 | 15 | //来自柜台 IN 0 -5000 16 | public static final short COUNTER_CONNECT = 0; 17 | public static final short COUNTER_DISCONNECT = 1; 18 | public static final short COUNTER_NEW_ORDER = 2; 19 | public static final short COUNTER_CANCEL_ORDER = 3; 20 | public static final short COUNTER_PING = 4; 21 | 22 | public static final short COUNTER_MSG_TYPE_MIN = 0; 23 | public static final short COUNTER_MSG_TYPE_MAX = 5000; 24 | 25 | 26 | //来自撮合核心5001-10000 27 | public static final short MATCH_ORDER_DATA = 5001; 28 | public static final short MATCH_HQ_DATA = 5002; 29 | 30 | public static final short MATCH_MSG_TYPE_MIN = 5001; 31 | public static final short MATCH_MSG_TYPE_MAX = 10000; 32 | 33 | 34 | //其他10001- 35 | public static final short ERROR = 10001; 36 | public static final short TEST = 10002; 37 | 38 | /////////////////////////////////////////////////// 39 | 40 | //消息状态 41 | public static final byte NORMAL = 0; 42 | public static final byte CS_NOT_MATCH = 1; 43 | public static final byte GW_OFF = 2; 44 | public static final byte CACHE_FULL = 3; 45 | public static final byte REJECTED = 4; 46 | 47 | 48 | //////////////////////交易所状态/////////////////////// 49 | public static final int ON = 1; 50 | 51 | public static final int OFF = 0; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/bean/MsgConstants.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | public class MsgConstants { 4 | 5 | 6 | //消息来源 7 | // public static final byte COUNTER = 0; 8 | // public static final byte GATEWAY = 1; 9 | // public static final byte SEQUENCER = 2; 10 | // public static final byte MATCH = 3; 11 | 12 | /////////////////////////////////////////////////// 13 | 14 | 15 | //来自柜台 IN 0 -5000 16 | public static final short COUNTER_CONNECT = 0; 17 | public static final short COUNTER_DISCONNECT = 1; 18 | public static final short COUNTER_NEW_ORDER = 2; 19 | public static final short COUNTER_CANCEL_ORDER = 3; 20 | public static final short COUNTER_PING = 4; 21 | 22 | public static final short COUNTER_MSG_TYPE_MIN = 0; 23 | public static final short COUNTER_MSG_TYPE_MAX = 5000; 24 | 25 | 26 | //来自撮合核心5001-10000 27 | public static final short MATCH_ORDER_DATA = 5001; 28 | public static final short MATCH_HQ_DATA = 5002; 29 | 30 | public static final short MATCH_MSG_TYPE_MIN = 5001; 31 | public static final short MATCH_MSG_TYPE_MAX = 10000; 32 | 33 | 34 | //其他10001- 35 | public static final short ERROR = 10001; 36 | public static final short TEST = 10002; 37 | 38 | /////////////////////////////////////////////////// 39 | 40 | //消息状态 41 | public static final byte NORMAL = 0; 42 | public static final byte CS_NOT_MATCH = 1; 43 | public static final byte GW_OFF = 2; 44 | public static final byte CACHE_FULL = 3; 45 | public static final byte REJECTED = 4; 46 | 47 | 48 | //////////////////////交易所状态/////////////////////// 49 | public static final int ON = 1; 50 | 51 | public static final int OFF = 0; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /gateway/src/main/java/thirdpart/bean/MsgConstants.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bean; 2 | 3 | public class MsgConstants { 4 | 5 | 6 | //消息来源 7 | // public static final byte COUNTER = 0; 8 | // public static final byte GATEWAY = 1; 9 | // public static final byte SEQUENCER = 2; 10 | // public static final byte MATCH = 3; 11 | 12 | /////////////////////////////////////////////////// 13 | 14 | 15 | //来自柜台 IN 0 -5000 16 | public static final short COUNTER_CONNECT = 0; 17 | public static final short COUNTER_DISCONNECT = 1; 18 | public static final short COUNTER_NEW_ORDER = 2; 19 | public static final short COUNTER_CANCEL_ORDER = 3; 20 | public static final short COUNTER_PING = 4; 21 | 22 | public static final short COUNTER_MSG_TYPE_MIN = 0; 23 | public static final short COUNTER_MSG_TYPE_MAX = 5000; 24 | 25 | 26 | //来自撮合核心5001-10000 27 | public static final short MATCH_ORDER_DATA = 5001; 28 | public static final short MATCH_HQ_DATA = 5002; 29 | 30 | public static final short MATCH_MSG_TYPE_MIN = 5001; 31 | public static final short MATCH_MSG_TYPE_MAX = 10000; 32 | 33 | 34 | //其他10001- 35 | public static final short ERROR = 10001; 36 | public static final short TEST = 10002; 37 | 38 | /////////////////////////////////////////////////// 39 | 40 | //消息状态 41 | public static final byte NORMAL = 0; 42 | public static final byte CS_NOT_MATCH = 1; 43 | public static final byte GW_OFF = 2; 44 | public static final byte CACHE_FULL = 3; 45 | public static final byte REJECTED = 4; 46 | 47 | 48 | //////////////////////交易所状态/////////////////////// 49 | public static final int ON = 1; 50 | 51 | public static final int OFF = 0; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /engine/dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.star 5 | engine 6 | 1.0-SNAPSHOT 7 | 8 | engine-1.0-SNAPSHOT 9 | 10 | 11 | maven-shade-plugin 12 | 3.2.4 13 | 14 | 15 | package 16 | 17 | shade 18 | 19 | 20 | 21 | 22 | *:* 23 | 24 | META-INF/*.SF 25 | META-INF/*.DSA 26 | META-INF/*.RSA 27 | 28 | 29 | 30 | 31 | 32 | com.star.engine.EngineStartup 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | UTF-8 43 | 8 44 | 8 45 | 46 | 47 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/orderbook/api/OrderBook.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean.orderbook.api; 2 | 3 | import com.star.engine.bean.command.CmdResultCode; 4 | import com.star.engine.bean.command.RbCmd; 5 | import com.star.engine.bean.orderbook.impl.OrderBookImpl; 6 | import lombok.Getter; 7 | import thirdpart.hq.L1MarketData; 8 | 9 | import static thirdpart.hq.L1MarketData.L1_SIZE; 10 | 11 | public interface OrderBook { 12 | 13 | //新增委托 14 | CmdResultCode newOrder(RbCmd cmd); 15 | 16 | //撤单 17 | CmdResultCode cancelOrder(RbCmd rbCmd); 18 | 19 | //查询行情快照 20 | default L1MarketData getL1MarketDataSnapshot() { 21 | final int buySize = limitBuyBucketSize(L1_SIZE); 22 | final int sellSize = limitSellBucketSize(L1_SIZE); 23 | final L1MarketData data = new L1MarketData(buySize, sellSize); 24 | fillBuys(buySize, data); 25 | fillSells(sellSize, data); 26 | fillCode(data); 27 | 28 | data.timestamp = System.currentTimeMillis(); 29 | 30 | return data; 31 | } 32 | 33 | void fillCode(L1MarketData data); 34 | 35 | void fillSells(int size, L1MarketData data); 36 | 37 | void fillBuys(int size, L1MarketData data); 38 | 39 | int limitBuyBucketSize(int maxSize); 40 | 41 | int limitSellBucketSize(int maxSize); 42 | 43 | static OrderBook create(OrderBookImplType type) { 44 | switch (type) { 45 | case GUDY: 46 | return new OrderBookImpl(); 47 | default: 48 | throw new IllegalArgumentException(); 49 | } 50 | } 51 | 52 | @Getter 53 | enum OrderBookImplType { 54 | GUDY(0); 55 | 56 | private byte code; 57 | 58 | OrderBookImplType(int code) { 59 | this.code = (byte) code; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /seq/dependency-reduced-pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.star 5 | seq 6 | 1.0-SNAPSHOT 7 | 8 | seq-1.0-SNAPSHOT 9 | 10 | 11 | maven-shade-plugin 12 | 3.2.4 13 | 14 | 15 | package 16 | 17 | shade 18 | 19 | 20 | 21 | 22 | com.star.seq.SeqStartup3 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | junit 34 | junit 35 | 4.12 36 | test 37 | 38 | 39 | hamcrest-core 40 | org.hamcrest 41 | 42 | 43 | 44 | 45 | 46 | UTF-8 47 | 8 48 | 8 49 | 50 | 51 | -------------------------------------------------------------------------------- /engine/src/test/java/testBodyCodec.java: -------------------------------------------------------------------------------- 1 | import com.alipay.remoting.exception.CodecException; 2 | import net.openhft.chronicle.core.util.Time; 3 | import thirdpart.bean.CmdPack; 4 | import thirdpart.codec.api.BodyCodec; 5 | import thirdpart.codec.impl.BodyCodecImpl; 6 | import thirdpart.order.CmdType; 7 | import thirdpart.order.OrderCmd; 8 | import thirdpart.order.OrderDirection; 9 | import thirdpart.order.OrderType; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Date; 13 | import java.util.List; 14 | import java.util.Timer; 15 | 16 | public class testBodyCodec { 17 | public static void main(String[] args) throws CodecException { 18 | Date date = new Date(); 19 | long nowTime = date.getTime(); 20 | OrderCmd orderCmd1 = OrderCmd.builder() 21 | .direction(OrderDirection.BUY) 22 | .mid((short) 12) 23 | .oid(123454L) 24 | .code(123) 25 | .price(120000L) 26 | .volume(120) 27 | .orderType(OrderType.LIMIT) 28 | .oid(123213L) 29 | .build(); 30 | OrderCmd orderCmd2 = OrderCmd.builder() 31 | .direction(OrderDirection.BUY) 32 | .mid((short) 12) 33 | .oid(123454L) 34 | .code(123) 35 | .price(120000L) 36 | .volume(120) 37 | .orderType(OrderType.LIMIT) 38 | .oid(123213L) 39 | .build(); 40 | List list = new ArrayList<>(); 41 | list.add(orderCmd1); 42 | list.add(orderCmd2); 43 | CmdPack cmdPack = new CmdPack(1L, list); 44 | BodyCodec bodyCodec = new BodyCodecImpl(); 45 | byte[] serialize = bodyCodec.serialize(cmdPack); 46 | CmdPack deserialize = bodyCodec.deserialize(serialize, CmdPack.class); 47 | System.out.println(deserialize); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cfront/src/api/orderApi.js: -------------------------------------------------------------------------------- 1 | import {reqRealEnd, reqRealEndAsync} from './axiosCommon' 2 | 3 | import {config} from './frontConfig' 4 | 5 | import store from '../store/index' 6 | 7 | //查资金 8 | export const queryBalance = () => { 9 | reqRealEndAsync("post", config.real_domain, 10 | '/api/balance', 11 | {uid: sessionStorage.getItem('uid')}, 12 | (code, msg, data) => { 13 | // store.state.posiData = data; 14 | store.commit("updateBalance", data) 15 | }) 16 | }; 17 | 18 | //查持仓 19 | export const queryPosi = () => { 20 | reqRealEndAsync("post", config.real_domain, 21 | '/api/posiinfo', 22 | {uid: sessionStorage.getItem('uid')}, 23 | (code, msg, data) => { 24 | // store.state.posiData = data; 25 | store.commit("updatePosi", data) 26 | }) 27 | }; 28 | 29 | //查股票代码 30 | export const queryCodeName = (params) => { 31 | return reqRealEnd("post", 32 | config.real_domain, '/api/code', params); 33 | }; 34 | 35 | //查委托 36 | export const queryOrder = () => { 37 | reqRealEndAsync("post", config.real_domain, 38 | '/api/orderinfo', 39 | {uid: sessionStorage.getItem('uid')}, 40 | (code, msg, data) => { 41 | store.commit("updateOrder", data) 42 | }) 43 | }; 44 | 45 | //查成交 46 | export const queryTrade = () => { 47 | reqRealEndAsync("post", config.real_domain, 48 | '/api/tradeinfo', 49 | {uid: sessionStorage.getItem('uid')}, 50 | (code, msg, data) => { 51 | store.commit("updateTrade", data) 52 | }) 53 | }; 54 | 55 | //发送委托 56 | export const sendOrder = (params,callback) =>{ 57 | return reqRealEndAsync("post",config.real_domain, 58 | '/api/sendorder',params,callback); 59 | } 60 | 61 | // 委托 62 | export const cancelOrder = (params,callback) => { 63 | return reqRealEndAsync("post", config.real_domain, '/api/cancelorder', params, callback); 64 | }; -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/handler/risk/ExistRiskHandler.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.handler.risk; 2 | 3 | import com.star.engine.bean.command.CmdResultCode; 4 | import com.star.engine.bean.command.RbCmd; 5 | import com.star.engine.handler.BaseHandler; 6 | import lombok.NonNull; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.log4j.Log4j2; 9 | import org.eclipse.collections.api.set.primitive.MutableIntSet; 10 | import org.eclipse.collections.api.set.primitive.MutableLongSet; 11 | import thirdpart.order.CmdType; 12 | 13 | @RequiredArgsConstructor 14 | @Log4j2 15 | public class ExistRiskHandler extends BaseHandler { 16 | 17 | @NonNull 18 | private MutableLongSet uidSet; 19 | 20 | @NonNull 21 | private MutableIntSet codeSet; 22 | 23 | /** 24 | * 发布行情Event,新委托Event,撤单Event,权限控制等 25 | * @param cmd RbCmd类:published to the {@link com.lmax.disruptor.RingBuffer} 26 | * @param sequence of the event being processed 27 | * @param endOfBatch flag to indicate if this is the last event in a batch from the {@link com.lmax.disruptor.RingBuffer} 28 | */ 29 | @Override 30 | public void onEvent(RbCmd cmd, long sequence, boolean endOfBatch) throws Exception { 31 | //指令为系统产生的行情发布指令,则不用经过前置风控 32 | if (cmd.command == CmdType.HQ_PUB) { 33 | return; 34 | } 35 | if (cmd.command == CmdType.NEW_ORDER || cmd.command == CmdType.CANCEL_ORDER) { 36 | //非法用户ID 37 | if (!uidSet.contains(cmd.uid)) { 38 | log.info("illegal uid: {}", cmd.uid); 39 | cmd.resultCode = CmdResultCode.RISK_INVALID_CODE; 40 | return; 41 | } 42 | //非法股票代码 43 | if (!codeSet.contains(cmd.code)) { 44 | log.error("illegal code [{}] exist", cmd.code); 45 | cmd.resultCode = CmdResultCode.RISK_INVALID_CODE; 46 | return; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/orderbook/api/OrderBucket.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean.orderbook.api; 2 | 3 | import com.star.engine.bean.command.RbCmd; 4 | import com.star.engine.bean.orderbook.Order; 5 | import com.star.engine.bean.orderbook.impl.OrderBucketImpl; 6 | import lombok.Getter; 7 | import lombok.NonNull; 8 | 9 | import java.util.concurrent.atomic.AtomicLong; 10 | import java.util.function.Consumer; 11 | 12 | /** 13 | * 该接口继承Comparable,使其具有排序的功能 14 | */ 15 | public interface OrderBucket extends Comparable{ 16 | 17 | //编号生成器 18 | AtomicLong tidGen = new AtomicLong(0); 19 | 20 | /** 21 | * 新增订单 22 | * @param order 订单簿里封装的Order类 23 | */ 24 | void put(Order order); 25 | 26 | /** 27 | * 移除订单 28 | * @param oid 订单序号 29 | */ 30 | Order remove(long oid); 31 | 32 | /** 33 | * 订单撮合 34 | * @param volumeLeft 需要处理的订单量 35 | * @param triggerCmd 发送过来的委托 36 | * @param removeOrderCallback 回调函数,处理完成后的操作 37 | * @return 38 | */ 39 | long match(long volumeLeft, RbCmd triggerCmd, Consumer removeOrderCallback); 40 | 41 | /////////////行情发布相关///////////// 42 | long getPrice(); 43 | void setPrice(long price); 44 | long getTotalVolume(); 45 | 46 | //////////////初始化选项////////////// 47 | static OrderBucket create(OrderBucketImplType type) { 48 | switch (type) { 49 | case GUDY: 50 | return new OrderBucketImpl(); 51 | default: 52 | throw new IllegalArgumentException(); 53 | } 54 | } 55 | 56 | @Getter 57 | enum OrderBucketImplType { 58 | GUDY(0); 59 | 60 | private byte code; 61 | 62 | OrderBucketImplType(int code) { 63 | this.code = (byte) code; 64 | } 65 | } 66 | 67 | @Override 68 | default int compareTo(@NonNull OrderBucket other) { 69 | return Long.compare(this.getPrice(), other.getPrice()); 70 | } 71 | } -------------------------------------------------------------------------------- /cfront/src/api/axiosCommon.js: -------------------------------------------------------------------------------- 1 | import router from '../router' 2 | //let a = {name: hello , age : 10} 3 | //qs.Stringfy(a) 4 | //name=hello&age=13 5 | import Qs from 'qs'; 6 | 7 | //包装了ajax ,方便http调用 8 | import axios from 'axios'; 9 | 10 | //通用公共方法(包含回调) 11 | export const reqRealEndAsync = (method, baseUrl, 12 | url, params, callback) => { 13 | params.token = sessionStorage.getItem('token'); 14 | return axios({ 15 | timeout: 5000, 16 | baseURL: baseUrl, 17 | method: method, 18 | url: url, 19 | headers: { 20 | 'Content-type': 'application/x-www-form-urlencoded', 21 | }, 22 | data: Qs.stringify(params), 23 | //false -- split 24 | //true -- List 25 | traditional: true, 26 | }).then(res => { 27 | let result = res.data; 28 | //{code : 0 -- 成功的 1/2/其他 -- 失败,message: , data:{{}}} 29 | if (result.code == 1) { 30 | //验证失败 31 | router.replace({ 32 | path: "login", 33 | query: { 34 | msg: result.message 35 | } 36 | }); 37 | } else if (result.code == 0) { 38 | //成功回调 39 | if (callback != undefined) { 40 | callback(result.code, result.message, result.data); 41 | } 42 | }else if (result.code == 2) { 43 | //成功回调 44 | if (callback != undefined) { 45 | callback(result.code, result.message, result.data); 46 | } 47 | } 48 | }); 49 | }; 50 | 51 | //通用公共方法(不包含回调) 52 | export const reqRealEnd = (method, baseUrl, 53 | url, params) => { 54 | params.token = sessionStorage.getItem('token'); 55 | return axios({ 56 | timeout: 5000, 57 | baseURL: baseUrl, 58 | method: method, 59 | url: url, 60 | headers:{ 61 | 'Content-type': 'application/x-www-form-urlencoded', 62 | }, 63 | data: Qs.stringify(params), 64 | //false -- split 65 | //true -- List 66 | traditional: true, 67 | }); 68 | }; -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/filter/SessionCheckFilter.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.filter; 2 | 3 | import com.google.common.collect.Sets; 4 | import com.star.counter.service.api.AccountService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | 8 | import javax.servlet.*; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.util.Arrays; 13 | import java.util.Set; 14 | 15 | /** 16 | * @author zhaoyiming 17 | */ 18 | @Component 19 | public class SessionCheckFilter implements Filter { 20 | 21 | @Autowired 22 | private AccountService accountService; 23 | 24 | private Set whiteRootPaths = Sets.newHashSet("login", "msgsocket", "test"); 25 | 26 | @Override 27 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 28 | //解决ajax跨域问题 29 | HttpServletResponse response = (HttpServletResponse) servletResponse; 30 | response.setHeader("Access-Control-Allow-Origin", "*"); 31 | HttpServletRequest request = (HttpServletRequest) servletRequest; 32 | String path = request.getRequestURI(); 33 | String[] split = path.split("/"); 34 | //白名单模式,解决页面访问权限问题(同时保证会话有效时间) 35 | if (split.length < 2) { 36 | request.getRequestDispatcher("/login/loginfail").forward(servletRequest, servletResponse); 37 | } else { 38 | if (!whiteRootPaths.contains(split[1])) { 39 | //缓存中存在用户token信息 40 | if (accountService.accountExistInCache(request.getParameter("token"))) { 41 | //放行 42 | filterChain.doFilter(servletRequest, servletResponse); 43 | } else { 44 | request.getRequestDispatcher("/login/loginfail").forward(servletRequest, servletResponse); 45 | } 46 | } else { 47 | //放行 48 | filterChain.doFilter(servletRequest, servletResponse); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/bus/impl/MQTTBusSenderImpl.java: -------------------------------------------------------------------------------- 1 | package thirdpart.bus.impl; 2 | 3 | import io.netty.handler.codec.mqtt.MqttQoS; 4 | import io.vertx.core.Vertx; 5 | import io.vertx.mqtt.MqttClient; 6 | import io.vertx.mqtt.MqttClientOptions; 7 | import lombok.NonNull; 8 | import lombok.RequiredArgsConstructor; 9 | import lombok.extern.log4j.Log4j2; 10 | import thirdpart.bean.CommonMsg; 11 | import thirdpart.bus.api.BusSender; 12 | import thirdpart.codec.api.MsgCodec; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | @Log4j2 17 | @RequiredArgsConstructor 18 | public class MQTTBusSenderImpl implements BusSender { 19 | 20 | @NonNull 21 | private String ip; 22 | 23 | @NonNull 24 | private int port; 25 | 26 | @NonNull 27 | private MsgCodec msgCodec; 28 | 29 | private Vertx vertx = Vertx.vertx(); 30 | 31 | @Override 32 | public void startUp() { 33 | //连接总线 34 | mqttConnect(); 35 | } 36 | 37 | private void mqttConnect() { 38 | MqttClientOptions options = new MqttClientOptions() 39 | .setMaxInflightQueue(Integer.MAX_VALUE); 40 | 41 | MqttClient mqttClient = MqttClient.create(vertx, options); 42 | mqttClient.connect(port, ip, res -> { 43 | if (res.succeeded()) { 44 | sender = mqttClient; 45 | log.info("connect to mqtt bus[ip:{}, port:{}] succeed", ip, port); 46 | } else { 47 | log.info("connect to mqtt bus[ip:{}, port:{}] fail", ip, port); 48 | mqttConnect(); 49 | } 50 | }); 51 | 52 | mqttClient.closeHandler(h -> { 53 | try { 54 | TimeUnit.SECONDS.sleep(5); 55 | } catch (Exception e) { 56 | log.error(e); 57 | } 58 | mqttConnect(); 59 | }); 60 | } 61 | 62 | private volatile MqttClient sender; 63 | 64 | @Override 65 | public void publish(CommonMsg commonMsg) { 66 | sender.publish(Short.toString(commonMsg.getMsgDst()), //发往的柜台id 67 | msgCodec.encodeToBuffer(commonMsg), 68 | MqttQoS.AT_LEAST_ONCE, //总线保证至少到达一次 69 | false, //不判断是否重复 70 | false); //不判断是否保存 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /cfront/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | 60 | -------------------------------------------------------------------------------- /cfront/src/components/CodeInput.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 73 | 74 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/cache/RedisStringCache.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.cache; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.data.redis.core.StringRedisTemplate; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | 10 | @Component 11 | public class RedisStringCache { 12 | 13 | @Autowired 14 | private StringRedisTemplate template; 15 | 16 | @Value("${cacheexpire.captcha}") 17 | private int captchaExpireTime; 18 | 19 | @Value("${cacheexpire.account}") 20 | private int accountExpireTime; 21 | 22 | @Value("${cacheexpire.order}") 23 | private int orderExpireTime; 24 | 25 | public int getCaptchaExpireTime() { 26 | return captchaExpireTime; 27 | } 28 | 29 | public void setCaptchaExpireTime(int captchaExpireTime) { 30 | this.captchaExpireTime = captchaExpireTime; 31 | } 32 | 33 | public int getAccountExpireTime() { 34 | return accountExpireTime; 35 | } 36 | 37 | public void setAccountExpireTime(int accountExpireTime) { 38 | this.accountExpireTime = accountExpireTime; 39 | } 40 | 41 | public int getOrderExpireTime() { 42 | return orderExpireTime; 43 | } 44 | 45 | public void setOrderExpireTime(int orderExpireTime) { 46 | this.orderExpireTime = orderExpireTime; 47 | } 48 | 49 | //增加缓存 50 | public void cache(String key, String value, CacheType cacheType) { 51 | int expireTime; 52 | switch (cacheType) { 53 | case ACCOUNT: 54 | expireTime = getAccountExpireTime(); 55 | break; 56 | case CAPTCHA: 57 | expireTime = getCaptchaExpireTime(); 58 | break; 59 | case ORDER: 60 | case TRADE: 61 | case POSI: 62 | expireTime = getOrderExpireTime(); 63 | break; 64 | default: 65 | expireTime = 10; 66 | } 67 | template.opsForValue().set(cacheType.type() + key, value, expireTime, TimeUnit.SECONDS); 68 | } 69 | 70 | //查询缓存 71 | public String get(String key, CacheType cacheType) { 72 | return template.opsForValue().get(cacheType.type() + key); 73 | } 74 | 75 | //删除缓存 76 | public void remove(String key, CacheType cacheType) { 77 | template.delete(cacheType.type() + key); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/config/WebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.config; 2 | 3 | import com.star.counter.property.CounterProperty; 4 | import io.vertx.core.Vertx; 5 | import io.vertx.ext.bridge.BridgeEventType; 6 | 7 | import io.vertx.ext.bridge.PermittedOptions; 8 | import io.vertx.ext.web.Router; 9 | 10 | import io.vertx.ext.web.handler.sockjs.BridgeOptions; 11 | import io.vertx.ext.web.handler.sockjs.SockJSBridgeOptions; 12 | import io.vertx.ext.web.handler.sockjs.SockJSHandler; 13 | 14 | import lombok.extern.log4j.Log4j2; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.context.annotation.Configuration; 17 | 18 | import javax.annotation.PostConstruct; 19 | 20 | @Log4j2 21 | @Configuration 22 | public class WebSocketConfig { 23 | 24 | public static final String L1_MARKET_DATA_PREFIX = "l1-market-data"; 25 | 26 | public final static String TRADE_NOTIFY_ADDR_PREFIX = "tradechange-"; 27 | 28 | public final static String ORDER_NOTIFY_ADDR_PREFIX = "orderchange-"; 29 | 30 | @Autowired 31 | private CounterProperty counterProperty; 32 | 33 | @Autowired 34 | Vertx socketVertx; 35 | 36 | @PostConstruct 37 | private void init() { 38 | 39 | Router router = Router.router(socketVertx); 40 | 41 | // 只允许成交 委托的变动通过websocket总线往外发送 42 | SockJSBridgeOptions options = new SockJSBridgeOptions() 43 | .addInboundPermitted(new PermittedOptions().setAddress(L1_MARKET_DATA_PREFIX)) 44 | .addOutboundPermitted(new PermittedOptions().setAddressRegex("orderchange-[0-9]+")) 45 | .addOutboundPermitted(new PermittedOptions().setAddressRegex("tradechange-[0-9]+")); 46 | 47 | SockJSHandler sockJSHandler = SockJSHandler.create(socketVertx); 48 | sockJSHandler.bridge(options, event -> { 49 | if (event.type() == BridgeEventType.SOCKET_CREATED) { 50 | log.info("client : {} connected", event.socket().remoteAddress()); 51 | } else if (event.type() == BridgeEventType.SOCKET_CLOSED) { 52 | log.info("client : {} closed", event.socket().remoteAddress()); 53 | } 54 | event.complete(true); 55 | }); 56 | router.route("/eventbus/*").handler(sockJSHandler); 57 | log.info("The router info: {}", router.toString()); 58 | 59 | socketVertx.createHttpServer() 60 | .requestHandler(router) 61 | .listen(counterProperty.getPubPort()); 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/consumer/MarketDataConsumer.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.consumer; 2 | 3 | import com.alipay.sofa.rpc.common.utils.JSONUtils; 4 | import com.star.counter.config.GatewayConfig; 5 | import io.vertx.core.Vertx; 6 | import io.vertx.core.buffer.Buffer; 7 | import io.vertx.core.eventbus.EventBus; 8 | import lombok.extern.log4j.Log4j2; 9 | import org.apache.commons.lang3.ArrayUtils; 10 | import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | import thirdpart.codec.api.BodyCodec; 14 | import thirdpart.hq.L1MarketData; 15 | 16 | import javax.annotation.PostConstruct; 17 | 18 | import static com.star.counter.config.WebSocketConfig.L1_MARKET_DATA_PREFIX; 19 | import static com.star.counter.consumer.MqttBusConsumer.INNER_MARKET_DATA_CACHE_ADDR; 20 | 21 | @Log4j2 22 | @Component 23 | public class MarketDataConsumer { 24 | 25 | private IntObjectHashMap l1Cache = new IntObjectHashMap<>(); 26 | 27 | @Autowired 28 | BodyCodec bodyCodec; 29 | 30 | @Autowired 31 | Vertx socketVertx; 32 | 33 | @PostConstruct 34 | private void init() { 35 | EventBus eventBus = socketVertx.eventBus(); 36 | 37 | //处理核心发来的请求 38 | eventBus.consumer(INNER_MARKET_DATA_CACHE_ADDR).handler(buffer -> { 39 | Buffer body = (Buffer) buffer.body(); 40 | if (body.length() == 0) { 41 | return; 42 | } 43 | L1MarketData[] marketData = null; 44 | try { 45 | marketData = bodyCodec.deserialize(body.getBytes(), L1MarketData[].class); 46 | } catch (Exception e) { 47 | log.error(e); 48 | } 49 | if (ArrayUtils.isEmpty(marketData)) { 50 | return; 51 | } 52 | for (L1MarketData md : marketData) { 53 | L1MarketData data = l1Cache.get(md.code); 54 | if (data == null || data.timestamp < md.timestamp) { 55 | l1Cache.put(md.code, md); 56 | } else { 57 | log.error("L1MarketData is null or L1MarketData.timestamp < md.timestamp"); 58 | } 59 | } 60 | }); 61 | 62 | eventBus.consumer(L1_MARKET_DATA_PREFIX).handler(h -> { 63 | int code = Integer.parseInt(h.headers().get("code")); 64 | L1MarketData data = l1Cache.get(code); 65 | h.reply(JSONUtils.toJSONString(data)); 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /cfront/src/background.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import { app, protocol, BrowserWindow } from 'electron' 4 | import { 5 | createProtocol, 6 | installVueDevtools 7 | } from 'vue-cli-plugin-electron-builder/lib' 8 | const isDevelopment = process.env.NODE_ENV !== 'production' 9 | 10 | // Keep a global reference of the window object, if you don't, the window will 11 | // be closed automatically when the JavaScript object is garbage collected. 12 | let win 13 | 14 | // Scheme must be registered before the app is ready 15 | protocol.registerSchemesAsPrivileged([{scheme: 'app', privileges: { secure: true, standard: true } }]) 16 | 17 | function createWindow () { 18 | // Create the browser window. 19 | win = new BrowserWindow({ width: 800, height: 600, webPreferences: { 20 | nodeIntegration: true 21 | } }) 22 | 23 | if (process.env.WEBPACK_DEV_SERVER_URL) { 24 | // Load the url of the dev server if in development mode 25 | win.loadURL(process.env.WEBPACK_DEV_SERVER_URL) 26 | if (!process.env.IS_TEST) win.webContents.openDevTools() 27 | } else { 28 | createProtocol('app') 29 | // Load the index.html when not in development 30 | win.loadURL('app://./index.html') 31 | } 32 | 33 | win.on('closed', () => { 34 | win = null 35 | }) 36 | } 37 | 38 | // Quit when all windows are closed. 39 | app.on('window-all-closed', () => { 40 | // On macOS it is common for applications and their menu bar 41 | // to stay active until the user quits explicitly with Cmd + Q 42 | if (process.platform !== 'darwin') { 43 | app.quit() 44 | } 45 | }) 46 | 47 | app.on('activate', () => { 48 | // On macOS it's common to re-create a window in the app when the 49 | // dock icon is clicked and there are no other windows open. 50 | if (win === null) { 51 | createWindow() 52 | } 53 | }) 54 | 55 | // This method will be called when Electron has finished 56 | // initialization and is ready to create browser windows. 57 | // Some APIs can only be used after this event occurs. 58 | app.on('ready', async () => { 59 | if (isDevelopment && !process.env.IS_TEST) { 60 | // Install Vue Devtools 61 | try { 62 | await installVueDevtools() 63 | } catch (e) { 64 | console.error('Vue Devtools failed to install:', e.toString()) 65 | } 66 | 67 | } 68 | createWindow() 69 | }) 70 | 71 | // Exit cleanly on request from parent process in development mode. 72 | if (isDevelopment) { 73 | if (process.platform === 'win32') { 74 | process.on('message', data => { 75 | if (data === 'graceful-exit') { 76 | app.quit() 77 | } 78 | }) 79 | } else { 80 | process.on('SIGTERM', () => { 81 | app.quit() 82 | }) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/core/EngineApi.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.core; 2 | 3 | import com.lmax.disruptor.EventTranslatorOneArg; 4 | import com.lmax.disruptor.RingBuffer; 5 | import com.star.engine.bean.command.CmdResultCode; 6 | import com.star.engine.bean.command.RbCmd; 7 | import lombok.extern.log4j.Log4j2; 8 | import thirdpart.order.CmdType; 9 | import thirdpart.order.OrderCmd; 10 | 11 | @Log4j2 12 | public class EngineApi { 13 | 14 | private final RingBuffer ringBuffer; 15 | 16 | public EngineApi(RingBuffer ringBuffer) { 17 | this.ringBuffer = ringBuffer; 18 | } 19 | 20 | /** 21 | * 完成放入撮合引擎的方法 22 | * 将订单信息放入到撮合核心里 23 | * @param cmd 委托信息 24 | */ 25 | public void submitCommand(OrderCmd cmd) { 26 | switch (cmd.type) { 27 | case HQ_PUB: 28 | ringBuffer.publishEvent(HQ_PUB_TRANSLATOR, cmd); 29 | break; 30 | case NEW_ORDER: 31 | ringBuffer.publishEvent(NEW_ORDER_TRANSLATOR, cmd); 32 | break; 33 | case CANCEL_ORDER: 34 | ringBuffer.publishEvent(CANCEL_ORDER_TRANSLATOR, cmd); 35 | break; 36 | default: 37 | throw new IllegalArgumentException("Unsupported cmdType: " + cmd.getClass().getSimpleName()); 38 | } 39 | } 40 | 41 | private static final EventTranslatorOneArg HQ_PUB_TRANSLATOR = (rbCmd, seq, hqPub) -> { 42 | rbCmd.command = CmdType.HQ_PUB; 43 | rbCmd.resultCode = CmdResultCode.SUCCESS; 44 | }; 45 | 46 | private static final EventTranslatorOneArg NEW_ORDER_TRANSLATOR = (rbCmd, seq, newOrder) -> { 47 | rbCmd.command = CmdType.NEW_ORDER; 48 | rbCmd.timestamp = newOrder.timestamp; 49 | rbCmd.mid = newOrder.mid; 50 | rbCmd.uid = newOrder.uid; 51 | rbCmd.code = newOrder.code; 52 | rbCmd.direction = newOrder.direction; 53 | rbCmd.price = newOrder.price; 54 | rbCmd.volume = newOrder.volume; 55 | rbCmd.orderType = newOrder.orderType; 56 | rbCmd.oid = newOrder.oid; 57 | rbCmd.resultCode = CmdResultCode.SUCCESS; 58 | }; 59 | 60 | private static final EventTranslatorOneArg CANCEL_ORDER_TRANSLATOR = (rbCmd, seq, cancelOrder) -> { 61 | rbCmd.command = CmdType.CANCEL_ORDER; 62 | rbCmd.timestamp = cancelOrder.timestamp; 63 | rbCmd.mid = cancelOrder.mid; 64 | rbCmd.uid = cancelOrder.uid; 65 | rbCmd.code = cancelOrder.code; 66 | rbCmd.oid = cancelOrder.oid; 67 | rbCmd.resultCode = CmdResultCode.SUCCESS; 68 | }; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/DBUtil.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean; 2 | 3 | import com.star.engine.mapper.DBQuery; 4 | import lombok.extern.log4j.Log4j2; 5 | import org.apache.ibatis.io.Resources; 6 | import org.apache.ibatis.session.SqlSession; 7 | import org.apache.ibatis.session.SqlSessionFactory; 8 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.HashSet; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | /** 17 | * 单例模式 18 | */ 19 | @Log4j2 20 | public class DBUtil { 21 | 22 | private static DBUtil ourInstance = new DBUtil(); 23 | 24 | private DBUtil() {} 25 | 26 | public static DBUtil getInstance() { 27 | return ourInstance; 28 | } 29 | 30 | private static SqlSessionFactory sqlSessionFactory; 31 | 32 | static { 33 | log.info("构建SqlSessionFactory..."); 34 | String resource = "mybatis-config.xml"; 35 | InputStream inputStream; 36 | try { 37 | inputStream = Resources.getResourceAsStream(resource); 38 | } catch (IOException e) { 39 | throw new RuntimeException(e); 40 | } 41 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 42 | log.info(sqlSessionFactory); 43 | } 44 | 45 | public List> queryAllBalance() { 46 | try (SqlSession session = sqlSessionFactory.openSession()) { 47 | DBQuery mapper = session.getMapper(DBQuery.class); 48 | List> maps = mapper.queryAllBalance(); 49 | return maps; 50 | } catch (Exception e) { 51 | log.error("Exception in queryAllBalance", e); 52 | } 53 | return null; 54 | } 55 | 56 | public HashSet queryAllStockCode() { 57 | try (SqlSession session = sqlSessionFactory.openSession()) { 58 | DBQuery mapper = session.getMapper(DBQuery.class); 59 | HashSet allStockCode = mapper.queryAllStockCode(); 60 | return allStockCode; 61 | } catch (Exception e) { 62 | log.error("Exception in queryAllStockCode", e); 63 | } 64 | return null; 65 | } 66 | 67 | public List queryAllMemberIds() { 68 | try (SqlSession session = sqlSessionFactory.openSession()) { 69 | DBQuery mapper = session.getMapper(DBQuery.class); 70 | List memberIds = mapper.queryAllMemberIds(); 71 | return memberIds; 72 | } catch (Exception e) { 73 | log.error("Exception in queryAllMemberIds", e); 74 | } 75 | return null; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/orderbook/Order.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean.orderbook; 2 | 3 | import lombok.*; 4 | import org.apache.commons.lang.builder.EqualsBuilder; 5 | import org.apache.commons.lang.builder.HashCodeBuilder; 6 | import thirdpart.order.OrderDirection; 7 | 8 | //只在OrderBook内部使用 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @Builder 12 | @Getter 13 | @Setter 14 | @ToString 15 | public final class Order { 16 | 17 | /** 18 | * 会员ID 19 | */ 20 | private short mid; 21 | 22 | /** 23 | * 用户ID 24 | */ 25 | private long uid; 26 | 27 | /** 28 | * 代码 29 | */ 30 | private int code; 31 | 32 | /** 33 | * 方向 34 | */ 35 | private OrderDirection direction; 36 | 37 | /** 38 | * 价格 39 | */ 40 | private long price; 41 | 42 | /** 43 | * 量 44 | */ 45 | private long volume; 46 | 47 | /** 48 | * 已成交量 49 | */ 50 | private long tvolume; 51 | 52 | /** 53 | * 委托编号 54 | */ 55 | private long oid; 56 | 57 | /** 58 | * 时间戳 59 | */ 60 | private long timestamp; 61 | 62 | /** 63 | * 内部排序顺序 64 | */ 65 | private long innerOid; 66 | 67 | //时间戳在此类重写的hashCode和equals方法的计算范围内 68 | @Override 69 | public int hashCode() { 70 | return new HashCodeBuilder(17, 37) 71 | .append(mid) 72 | .append(uid) 73 | .append(code) 74 | .append(direction) 75 | .append(price) 76 | .append(volume) 77 | .append(tvolume) 78 | .append(oid) 79 | // .append(timestamp) 80 | .toHashCode(); 81 | } 82 | 83 | /** 84 | * timestamp is not included into hashCode() and equals() for repeatable results 85 | */ 86 | @Override 87 | public boolean equals(Object o) { 88 | if (this == o) return true; 89 | 90 | if (o == null || getClass() != o.getClass()) return false; 91 | 92 | Order order = (Order) o; 93 | 94 | return new EqualsBuilder() 95 | .append(mid, order.mid) 96 | .append(uid, order.uid) 97 | .append(code, order.code) 98 | .append(price, order.price) 99 | .append(volume, order.volume) 100 | .append(tvolume, order.tvolume) 101 | .append(oid, order.oid) 102 | // .append(timestamp, order.timestamp) 103 | .append(direction, order.direction) 104 | .isEquals(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/gateway/MsgTrans.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.gateway; 2 | 3 | import com.star.counter.property.CounterProperty; 4 | import com.star.counter.util.SnowflakeIdWorker; 5 | import lombok.extern.log4j.Log4j2; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | import thirdpart.bean.CommonMsg; 9 | import thirdpart.checksum.api.CheckSum; 10 | import thirdpart.codec.api.BodyCodec; 11 | import thirdpart.codec.api.MsgCodec; 12 | import thirdpart.order.OrderCmd; 13 | import thirdpart.tcp.TcpDirectSender; 14 | 15 | import javax.annotation.PostConstruct; 16 | 17 | import static thirdpart.bean.MsgConstants.COUNTER_NEW_ORDER; 18 | import static thirdpart.bean.MsgConstants.NORMAL; 19 | 20 | @Log4j2 21 | @Component 22 | public class MsgTrans { 23 | 24 | @Autowired 25 | TcpDirectSender tcpDirectSender; 26 | 27 | @Autowired 28 | BodyCodec bodyCodec; 29 | 30 | @Autowired 31 | private CheckSum checkSum; 32 | 33 | @Autowired 34 | private CounterProperty counterProperty; 35 | 36 | @Autowired 37 | SnowflakeIdWorker snowflakeIdWorker; 38 | 39 | @Autowired 40 | MsgCodec msgCodec; 41 | 42 | @PostConstruct 43 | private void init() { 44 | tcpDirectSender.startUp(); 45 | log.info("TCPDirectSender start"); 46 | } 47 | 48 | private CommonMsg generateMsg(byte[] data, short msgSrc, short msgDst, short msgType, byte status, long msgNo) { 49 | if (data == null) { 50 | log.error("empty body, not send"); 51 | return null; 52 | } 53 | CommonMsg msg = new CommonMsg(); 54 | msg.setBodyLength(data.length); 55 | msg.setChecksum(checkSum.getCheckSum(data)); 56 | msg.setMsgSrc(msgSrc); 57 | msg.setMsgDst(msgDst); 58 | msg.setMsgType(msgType); 59 | msg.setStatus(status); 60 | msg.setMsgNo(msgNo); 61 | msg.setBody(data); 62 | return msg; 63 | } 64 | 65 | public void sendOrder(OrderCmd orderCmd) { 66 | //将OrderCmd打包为CommonMsg 67 | byte[] data; 68 | try { 69 | data = bodyCodec.serialize(orderCmd); //将对象转为字节码放到报体中(Hessian2编码方式) 70 | } catch (Exception e) { 71 | log.error("encode error for ordercmd:{}", orderCmd, e); 72 | return; 73 | } 74 | CommonMsg commonMsg = generateMsg(data, counterProperty.getId(), counterProperty.getGatewayId(), COUNTER_NEW_ORDER, NORMAL, snowflakeIdWorker.nextId()); 75 | //将封装好的CommonMsg编码为Buffer(按字节索引组装) 76 | boolean send = tcpDirectSender.send(msgCodec.encodeToBuffer(commonMsg)); 77 | log.info("ordercmd has bean sent? {}", send); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/impl/PosiServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.impl; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.core.type.TypeReference; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.google.common.collect.Lists; 7 | import com.star.counter.bean.PosiInfo; 8 | import com.star.counter.cache.CacheType; 9 | import com.star.counter.cache.RedisStringCache; 10 | import com.star.counter.mapper.PosiMapper; 11 | import com.star.counter.service.api.PosiService; 12 | import org.apache.commons.lang3.StringUtils; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.util.CollectionUtils; 16 | 17 | import java.util.List; 18 | 19 | @Service 20 | public class PosiServiceImpl implements PosiService { 21 | 22 | @Autowired 23 | RedisStringCache redisStringCache; 24 | 25 | @Autowired 26 | PosiMapper posiMapper; 27 | 28 | @Override 29 | public List getPosiListByUid(long uid) throws JsonProcessingException { 30 | String suid = Long.toString(uid); 31 | String posiS = redisStringCache.get(suid, CacheType.POSI); 32 | if (StringUtils.isEmpty(posiS)) { 33 | //缓存中没有查到 34 | List posiInfos = posiMapper.queryPosiByUid(uid); 35 | List result = CollectionUtils.isEmpty(posiInfos) ? Lists.newArrayList() : posiInfos; 36 | //将持仓信息转换为json并写入缓存 37 | ObjectMapper objectMapper = new ObjectMapper(); 38 | String resultJson = objectMapper.writeValueAsString(result); 39 | redisStringCache.cache(suid, resultJson, CacheType.POSI); 40 | return posiInfos; 41 | } else { 42 | //命中缓存 43 | ObjectMapper objectMapper = new ObjectMapper(); 44 | List posiInfos = objectMapper.readValue(posiS, new TypeReference>() {}); 45 | return posiInfos; 46 | } 47 | } 48 | 49 | @Override 50 | public void addPosi(long uid, int code, long volume, long price) { 51 | redisStringCache.remove(Long.toString(uid), CacheType.POSI); 52 | //判断持仓是否已经存在 53 | PosiInfo posiInfo = posiMapper.queryOnePosi(uid, code); 54 | if (posiInfo == null) { 55 | //新增持仓 56 | posiMapper.insetPosi(uid, code, volume, price); 57 | } else { 58 | //修改持仓 59 | posiMapper.addPosi(uid, code, volume, price); 60 | } 61 | } 62 | 63 | @Override 64 | public void minusPosi(long uid, int code, long volume, long price) { 65 | addPosi(uid, code, -volume, price); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/bean/command/CmdResultCode.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.bean.command; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum CmdResultCode { 7 | 8 | SUCCESS(1), 9 | 10 | 11 | /////////////////////////orderbook///////////////////////////// 12 | 13 | INVALID_ORDER_ID(-1),//不合法委托ID 14 | INVALID_ORDER_PRICE(-2),//不合法委托价格 15 | DUPLICATE_ORDER_ID(-3),//重复委托编号 16 | UNKNOWN_MATCH_CMD(-4),//未知撮合指令 17 | INVALID_ORDER_BOOK_ID(-5),//未知订单簿 18 | 19 | ///////////////////////risk///////////////////////////// 20 | RISK_INVALID_USER(-100),//用户不存在 21 | RISK_INVALID_CODE(-101),//代码不存在 22 | RISK_INVALID_BALANCE(-102),//资金不正确 23 | 24 | ///////////////////////match///////////////////////////// 25 | MATCHING_INVALID_STOCK(-200), 26 | 27 | // VALID_FOR_MATCHING_ENGINE(1), 28 | // 29 | // SUCCESS(100), 30 | // ACCEPTED(110), 31 | // 32 | // AUTH_INVALID_USER(-1001), 33 | // AUTH_TOKEN_EXPIRED(-1002), 34 | // 35 | // INVALID_SYMBOL(-1201), 36 | // INVALID_PRICE_STEP(-1202), 37 | // 38 | // RISK_NSF(-2001), 39 | // 40 | // MATCHING_UNKNOWN_ORDER_ID(-3002), 41 | // MATCHING_DUPLICATE_ORDER_ID(-3003), 42 | // MATCHING_UNSUPPORTED_COMMAND(-3004), 43 | // INVALID_ORDER_BOOK_ID(-3005), 44 | // MATCHING_ORDER_BOOK_ALREADY_EXISTS(-3006), 45 | //// MATCHING_MOVE_REJECTED_DIFFERENT_PRICE(-3040), 46 | // MATCHING_MOVE_FAILED_PRICE_OVER_RISK_LIMIT(-3041), 47 | // 48 | // USER_MGMT_USER_ALREADY_EXISTS(-4001), 49 | // 50 | //// USER_MGMT_ACCOUNT_BALANCE_ADJUSTMENT_ZERO(-4100), 51 | // USER_MGMT_ACCOUNT_BALANCE_ADJUSTMENT_ALREADY_APPLIED_SAME(-4101), 52 | // USER_MGMT_ACCOUNT_BALANCE_ADJUSTMENT_ALREADY_APPLIED_MANY(-4102), 53 | // USER_MGMT_ACCOUNT_BALANCE_ADJUSTMENT_NSF(-4103), 54 | // USER_MGMT_NON_ZERO_ACCOUNT_BALANCE(-4104), 55 | // 56 | // USER_MGMT_USER_NOT_SUSPENDABLE_HAS_POSITIONS(-4130), 57 | // USER_MGMT_USER_NOT_SUSPENDABLE_NON_EMPTY_ACCOUNTS(-4131), 58 | // USER_MGMT_USER_NOT_SUSPENDED(-4132), 59 | // USER_MGMT_USER_ALREADY_SUSPENDED(-4133), 60 | // 61 | // USER_MGMT_USER_NOT_FOUND(-4201), 62 | // 63 | // SYMBOL_MGMT_SYMBOL_ALREADY_EXISTS(-5001), 64 | // 65 | // BINARY_COMMAND_FAILED(-8001), 66 | // STATE_HASH_FAILED(-8003), 67 | // STATE_PERSIST_RISK_ENGINE_FAILED(-8010), 68 | // STATE_PERSIST_MATCHING_ENGINE_FAILED(-8020), 69 | 70 | DROP(-9999); 71 | 72 | // codes below -10000 are reserved for gateways 73 | 74 | 75 | private int code; 76 | 77 | CmdResultCode(int code) { 78 | this.code = code; 79 | } 80 | 81 | } 82 | 83 | -------------------------------------------------------------------------------- /engine/src/main/java/com/star/engine/core/EngineCore.java: -------------------------------------------------------------------------------- 1 | package com.star.engine.core; 2 | 3 | import com.lmax.disruptor.BlockingWaitStrategy; 4 | import com.lmax.disruptor.dsl.Disruptor; 5 | import com.lmax.disruptor.dsl.ProducerType; 6 | import com.star.engine.bean.RbCmdFactory; 7 | import com.star.engine.bean.command.RbCmd; 8 | import com.star.engine.handler.BaseHandler; 9 | import com.star.engine.handler.exception.DisruptorExceptionHandler; 10 | import lombok.Data; 11 | import lombok.NonNull; 12 | import lombok.extern.log4j.Log4j2; 13 | import net.openhft.affinity.AffinityStrategies; 14 | import net.openhft.affinity.AffinityThreadFactory; 15 | import thirdpart.order.CmdType; 16 | import thirdpart.order.OrderCmd; 17 | 18 | import java.util.Timer; 19 | import java.util.TimerTask; 20 | 21 | import static com.star.engine.handler.pub.L1PubHandler.HQ_PUB_RATE; 22 | 23 | @Log4j2 24 | @Data 25 | public class EngineCore { 26 | 27 | private final Disruptor disruptor; 28 | 29 | private static final int RING_BUFFER_SIZE = 1024; 30 | 31 | @NonNull 32 | private final EngineApi engineApi; 33 | 34 | public EngineCore(@NonNull final BaseHandler riskHandler, 35 | @NonNull final BaseHandler matchHandler, 36 | @NonNull final BaseHandler pubHandler 37 | ) { 38 | this.disruptor = new Disruptor( 39 | new RbCmdFactory(), //产生实例的工厂方法 40 | RING_BUFFER_SIZE, //size:2的n次方 41 | new AffinityThreadFactory("aft_engine_core", AffinityStrategies.ANY), //线程池(线程产生策略理论上在SAME_CORE时效率最高) 42 | ProducerType.SINGLE, //只有一个生产者线程 43 | new BlockingWaitStrategy() 44 | ); 45 | this.engineApi = new EngineApi(disruptor.getRingBuffer()); 46 | 47 | //全局异常处理器 48 | final DisruptorExceptionHandler exceptionHandler = new DisruptorExceptionHandler<>( 49 | "main", //撮合核心的名字 50 | (ex, seq) -> { //出现异常后的回调函数 51 | log.error("exception thrown on seq = {}", seq, ex); 52 | } 53 | ); 54 | disruptor.setDefaultExceptionHandler(exceptionHandler); 55 | 56 | //处理器处理顺序前置风控-->撮合-->发布数据 57 | disruptor.handleEventsWith(riskHandler) 58 | .then(matchHandler) 59 | .then(pubHandler); 60 | 61 | //启动 62 | disruptor.start(); 63 | log.info("match engine start successfully!"); 64 | 65 | //定时任务:发布行情 66 | new Timer().schedule(new HqPubTask(), 1000, HQ_PUB_RATE); 67 | } 68 | 69 | private class HqPubTask extends TimerTask { 70 | @Override 71 | public void run() { 72 | engineApi.submitCommand(OrderCmd.builder() 73 | .type(CmdType.HQ_PUB) 74 | .build()); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /cfront/src/views/PwdSetting.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 84 | 85 | -------------------------------------------------------------------------------- /cfront/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 94 | -------------------------------------------------------------------------------- /gateway/src/main/java/com/star/gateway/config/GatewayConfig.java: -------------------------------------------------------------------------------- 1 | package com.star.gateway.config; 2 | 3 | import com.alipay.sofa.rpc.config.ProviderConfig; 4 | import com.alipay.sofa.rpc.config.ServerConfig; 5 | import com.star.gateway.container.OrderCmdContainer; 6 | import com.star.gateway.handler.ConnHandler; 7 | import io.vertx.core.Vertx; 8 | import io.vertx.core.net.NetServer; 9 | import lombok.Data; 10 | import lombok.extern.log4j.Log4j2; 11 | import org.dom4j.Document; 12 | import org.dom4j.DocumentException; 13 | import org.dom4j.Element; 14 | import org.dom4j.io.SAXReader; 15 | import thirdpart.checksum.impl.CheckSumImpl; 16 | import thirdpart.codec.api.BodyCodec; 17 | import thirdpart.fetchserv.api.FetchService; 18 | 19 | import java.io.File; 20 | import java.io.InputStream; 21 | 22 | @Log4j2 23 | @Data 24 | public class GatewayConfig { 25 | 26 | //网关ID 27 | private short id; 28 | 29 | //外网端口 30 | private int recvPort; 31 | 32 | //排队机抓取服务端口 33 | private int fetchServPort; 34 | 35 | private BodyCodec bodyCodec; 36 | 37 | private CheckSumImpl checkSumImpl; 38 | 39 | private Vertx vertx = Vertx.vertx(); 40 | 41 | public void initConfig(InputStream inputStream) throws DocumentException { 42 | //dom4j对xml进行解析 43 | SAXReader reader = new SAXReader(); 44 | Document document = reader.read(inputStream); 45 | Element root = document.getRootElement(); 46 | this.id = Short.parseShort(root.element("id").getText()); 47 | this.recvPort = Integer.parseInt(root.element("recvport").getText()); 48 | this.fetchServPort = Integer.parseInt(root.element("fetchservport").getText()); 49 | log.info("GateWay ID:{}, Port:{}, FetchServPort: {}", id, recvPort, fetchServPort); 50 | } 51 | 52 | public void startup() { 53 | //启动TCP监听 54 | initRecv(); 55 | 56 | //排队机交互 57 | ServerConfig serverConfig = new ServerConfig() 58 | .setPort(fetchServPort) 59 | .setProtocol("bolt"); 60 | ProviderConfig providerConfig = new ProviderConfig() 61 | .setInterfaceId(FetchService.class.getName()) //Provider指定接口的名字暴露给Consumer 62 | //指定FetchService实现类来实现响应(直接从单例的Container获取即可),理论上应该传入FetchService的实现类 63 | .setRef(() -> OrderCmdContainer.getInstance().getAll()) 64 | .setServer(serverConfig); 65 | providerConfig.export(); //发布服务 66 | log.info("gateway startup fetchServ success at port: {}", fetchServPort); 67 | } 68 | 69 | public void initRecv() { 70 | NetServer netServer = vertx.createNetServer(); 71 | netServer.connectHandler(new ConnHandler(this)); 72 | netServer.listen(recvPort, res -> { 73 | if (res.succeeded()) { 74 | log.info("gateway startup at port: {}", recvPort); 75 | } else { 76 | log.error("gateway startup fail"); 77 | } 78 | }); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /cfront/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | Vue.use(VueRouter) 5 | 6 | const routes = [ 7 | { 8 | path: '/', 9 | name: 'Login', 10 | component: () => import('../views/Login.vue') 11 | }, 12 | { 13 | path: '/', 14 | name: 'Home', 15 | component: () => import('../views/Home.vue'), 16 | children: [ 17 | { 18 | path: '/dashboard', 19 | name: 'Dashboard', 20 | component: () => import('../views/Dashboard.vue') 21 | }, 22 | { 23 | path: '/pwdsetting', 24 | name: 'PwdSetting', 25 | component: () => import('../views/PwdSetting.vue'), 26 | meta: {requiredAuth: false} 27 | }, 28 | { 29 | path: '/transfer', 30 | name: 'Transfer', 31 | component: () => import('../views/Transfer.vue'), 32 | meta: {requiredAuth: false} 33 | }, 34 | { 35 | path: '/orderquery', 36 | name: 'OrderQuery', 37 | component: () => import('../views/OrderQuery.vue'), 38 | meta: {requiredAuth: false} 39 | }, 40 | { 41 | path: '/tradequery', 42 | name: 'TradeQuery', 43 | component: () => import('../views/TradeQuery.vue'), 44 | meta: {requiredAuth: false} 45 | }, 46 | { 47 | path: '/hisorderquery', 48 | name: 'HisOrderQuery', 49 | component: () => import('../views/HisOrderQuery.vue'), 50 | meta: {requiredAuth: false} 51 | }, 52 | { 53 | path: '/buy', 54 | name: 'Buy', 55 | component: () => import('../views/Buy.vue'), 56 | meta: {requiredAuth: false} 57 | }, 58 | { 59 | path: '/sell', 60 | name: 'Sell', 61 | component: () => import('../views/Sell.vue'), 62 | meta: {requiredAuth: false} 63 | }, 64 | ] 65 | }, 66 | { 67 | path: '/404', 68 | component: () => import('../views/404.vue') 69 | }, 70 | { 71 | path: '*', 72 | redirect: '/404' 73 | }, 74 | 75 | ] 76 | 77 | const router = new VueRouter({ 78 | mode: 'history', 79 | base: process.env.BASE_URL, 80 | routes 81 | }); 82 | 83 | //路由拦截器 84 | router.beforeEach((to,from,next) =>{ 85 | if(to.meta.requiredAuth){ 86 | if(Boolean(sessionStorage.getItem("uid"))){ 87 | next(); 88 | }else { 89 | next({ 90 | path: '/', 91 | }) 92 | } 93 | }else { 94 | next(); 95 | } 96 | }); 97 | 98 | 99 | export default router 100 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/service/impl/TradeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.service.impl; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.core.type.TypeReference; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.google.common.collect.Lists; 7 | import com.google.common.collect.Maps; 8 | import com.star.counter.bean.TradeInfo; 9 | import com.star.counter.cache.CacheType; 10 | import com.star.counter.cache.RedisStringCache; 11 | import com.star.counter.mapper.TradeMapper; 12 | import com.star.counter.service.api.TradeService; 13 | import com.star.counter.util.TimeformatUtil; 14 | import org.apache.commons.lang3.StringUtils; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Service; 17 | import org.springframework.util.CollectionUtils; 18 | import thirdpart.hq.MatchData; 19 | import thirdpart.order.OrderCmd; 20 | 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | @Service 25 | public class TradeServiceImpl implements TradeService { 26 | 27 | @Autowired 28 | RedisStringCache redisStringCache; 29 | 30 | @Autowired 31 | TradeMapper tradeMapper; 32 | 33 | @Override 34 | public void saveTrade(int counterOid, MatchData md, OrderCmd orderCmd) { 35 | if (orderCmd == null) { 36 | return; 37 | } 38 | int id = md.mid; 39 | long uid = orderCmd.uid; 40 | int code = orderCmd.code; 41 | int direction = orderCmd.direction.getDirection(); 42 | long price = md.price; 43 | long tcount = md.volume; 44 | String date = TimeformatUtil.yyyyMMdd(md.timestamp); 45 | String time = TimeformatUtil.hhMMss(md.timestamp); 46 | tradeMapper.savaTrade(id, uid, code, direction, price, tcount, counterOid, date, time); 47 | 48 | //更新缓存 49 | redisStringCache.remove(Long.toString(orderCmd.uid), CacheType.TRADE); 50 | } 51 | 52 | @Override 53 | public List getTradeServiceByUid(long uid) throws JsonProcessingException { 54 | String suid = Long.toString(uid); 55 | String tradeS = redisStringCache.get(suid, CacheType.TRADE); 56 | if (StringUtils.isEmpty(tradeS)) { 57 | //缓存中没有查到 58 | List tradeInfos = tradeMapper.queryTradeByUid(uid); 59 | List result = CollectionUtils.isEmpty(tradeInfos) ? Lists.newArrayList() : tradeInfos; 60 | //将持仓信息转换为json并写入缓存 61 | ObjectMapper objectMapper = new ObjectMapper(); 62 | String resultJson = objectMapper.writeValueAsString(result); 63 | redisStringCache.cache(suid, resultJson, CacheType.ORDER); 64 | return tradeInfos; 65 | } else { 66 | //命中缓存 67 | ObjectMapper objectMapper = new ObjectMapper(); 68 | List tradeInfos = objectMapper.readValue(tradeS, new TypeReference>() {}); 69 | return tradeInfos; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /counter/src/main/java/com/star/counter/cache/StockCache.java: -------------------------------------------------------------------------------- 1 | package com.star.counter.cache; 2 | 3 | import com.google.common.collect.HashMultimap; 4 | import com.google.common.collect.Lists; 5 | import com.star.counter.bean.StockInfo; 6 | import com.star.counter.mapper.StockMapper; 7 | import lombok.Data; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.util.CollectionUtils; 11 | 12 | import java.util.*; 13 | 14 | @Component 15 | @Data 16 | public class StockCache { 17 | 18 | private StockMapper stockMapper; 19 | 20 | //倒排索引 21 | //Map> 22 | // 6 --> 600086,600025... 23 | private Map> invertIndex = new HashMap<>(); 24 | 25 | @Autowired 26 | public StockCache(StockMapper stockMapper) { 27 | this.stockMapper = stockMapper; 28 | System.out.println("加载股票数据..."); 29 | long st = System.currentTimeMillis(); 30 | List stockInfos = stockMapper.queryAllStockInfo(); 31 | if (CollectionUtils.isEmpty(stockInfos)) { 32 | System.out.println("未找到股票数据"); 33 | return; 34 | } 35 | for (StockInfo stockInfo : stockInfos){ 36 | int code = stockInfo.getCode(); 37 | String abbrname = stockInfo.getAbbrName(); 38 | List codeMetas = splitData(String.format("%06d", code)); 39 | List abbrNameMetas = splitData(abbrname); 40 | //将股票代码索引和缩写索引合并 41 | codeMetas.addAll(abbrNameMetas); 42 | //去重 43 | Set set = new HashSet<>(codeMetas); 44 | List newCodeMetas = new ArrayList<>(set); 45 | for (String key : newCodeMetas) { 46 | if (!invertIndex.containsKey(key)) { 47 | invertIndex.put(key, new ArrayList<>()); 48 | } 49 | //限制索引数据列表长度(防止索引对应股票太长,例如以6开头的都是上证股票) 50 | List stockList = invertIndex.get(key); 51 | if (!CollectionUtils.isEmpty(stockList) && stockList.size() > 10) { 52 | continue; 53 | } 54 | stockList.add(stockInfo); 55 | } 56 | } 57 | long time = System.currentTimeMillis() - st; 58 | System.out.println("股票索引初始化花费时间为:" + time); 59 | } 60 | 61 | /** 62 | * 拆分股票代码/缩写对应的所有索引 63 | * @param code 股票代码或缩写 64 | * @return 索引列表 65 | */ 66 | private List splitData(String code) { 67 | // payh --> 68 | // p pa pay payh 69 | // a ay ayh 70 | // y yh 71 | // h 72 | List list = Lists.newArrayList(); 73 | int outLength = code.length(); 74 | for (int i = 0; i < outLength; i++) { 75 | int inLength = outLength + 1; 76 | for (int j = i + 1; j < inLength; j++) { 77 | list.add(code.substring(i, j)); 78 | } 79 | } 80 | return list; 81 | } 82 | 83 | public List getStocksByKey(String key) { 84 | return invertIndex.get(key); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /engine/src/main/java/thirdpart/tcp/TcpDirectSender.java: -------------------------------------------------------------------------------- 1 | package thirdpart.tcp; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Handler; 5 | import io.vertx.core.Vertx; 6 | import io.vertx.core.buffer.Buffer; 7 | import io.vertx.core.net.NetSocket; 8 | import lombok.NonNull; 9 | import lombok.RequiredArgsConstructor; 10 | import lombok.extern.log4j.Log4j2; 11 | 12 | import java.util.concurrent.BlockingQueue; 13 | import java.util.concurrent.LinkedBlockingDeque; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | @Log4j2 17 | @RequiredArgsConstructor 18 | public class TcpDirectSender { 19 | 20 | /** 21 | * BlockingQueue 22 | * 缓存队列,每次让socket从缓存中获取数据 23 | * 当队列为空时,取出时会阻塞,直到向队列中添加新元素 24 | * 当队列处于临界时,向队列中添加元素时会阻塞 25 | */ 26 | private final BlockingQueue sendCache = new LinkedBlockingDeque<>(); 27 | 28 | //volatile的作用是每次从内存中取到最新的 29 | private volatile NetSocket socket; 30 | 31 | @NonNull 32 | private String ip; 33 | 34 | @NonNull 35 | private int port; 36 | 37 | @NonNull 38 | private Vertx vertx; 39 | 40 | public void startUp() { 41 | log.info("vertx has bean loaded: {}", vertx); 42 | log.info("the port is: {}", port); 43 | log.info("the ip is: {}", ip); 44 | vertx.createNetClient().connect(port, ip, new ClientConnHandler()); 45 | //线程轮询缓存,缓存中有数据便发送 46 | new Thread(() -> { 47 | log.info("query thread start"); 48 | while (true) { 49 | try { 50 | //阻塞超过5秒则会返回null 51 | Buffer msgBuffer = sendCache.poll(5, TimeUnit.SECONDS); 52 | // log.info("searching for ordercmd information"); 53 | if (msgBuffer != null && msgBuffer.length() > 0 && socket != null) { 54 | socket.write(msgBuffer); 55 | log.info("msg has bean sent to gateway!"); 56 | } 57 | } catch (Exception e) { 58 | log.error("msg send fail, continue"); 59 | } 60 | } 61 | }).start(); 62 | } 63 | 64 | public boolean send(Buffer bufferMsg) { 65 | return sendCache.offer(bufferMsg); 66 | } 67 | 68 | private class ClientConnHandler implements Handler> { 69 | @Override 70 | public void handle(AsyncResult result) { 71 | if (result.succeeded()) { 72 | log.info("connect success to remote {}: {}", ip, port); 73 | socket = result.result(); 74 | //关闭处理器 75 | socket.closeHandler(close -> { 76 | log.info("connect to remote {} closed", socket.remoteAddress()); 77 | //重连 78 | reconnect(); 79 | }); 80 | } else { 81 | } 82 | } 83 | 84 | private void reconnect() { 85 | vertx.setTimer(5000, r -> { 86 | log.info("try reconnect to server to {}: {} failed", ip, port); 87 | vertx.createNetClient().connect(port, ip, new ClientConnHandler()); 88 | }); 89 | } 90 | } 91 | 92 | } 93 | --------------------------------------------------------------------------------