Node.js股票模擬交易後臺

我曾經花了一週時間開發了一個股票模擬交易後臺程序,使用Node.js。代碼量不多,能完成基本功能。下面給你們介紹一下其實現步驟。node

基本功能

  • 開戶
  • 搜索股票
  • 掛單(多單、空單)
  • 撤單(主動、被動)
  • 成交(非撮合)
  • 除權、除息
  • 查詢
    • 訂單狀態
    • 持倉
    • 今日委託
    • 今日成交
    • 歷史委託
    • 歷史成交
    • 掛單列表
    • 帳戶詳情(總收益,收益率,總資產)

其中模擬交易和真實交易最大的不一樣是,真實交易採用撮合制,邏輯較爲複雜。模擬交易採用更簡單的即時成交機制,只要符合條件,訂單當即成交。redis

這個後臺程序一共就兩個js文件,一個用於處理成交,即判斷成交條件,寫數據庫。另外一個處理其餘邏輯。固然這裏面沒有提到獲取股票實時價格的問題,這是另外一個系統完成,咱們經過消息隊列實時獲取咱們所關心的股票的價格,這是另外一個話題了。sql

這個後臺程序以一個node.js進程的方式運行,一個10秒一次的定時器執行成交判斷。(真實交易所的撮合器也是10秒鐘一次)數據庫

此外有一個WebAPI Server接受來自客戶端的請求。因此整體架構,能夠當作是一個微服務組成的系統。緩存

架構圖

數據庫設計

帳戶表

`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '模擬帳戶',
  `MemberCode` varchar(20) DEFAULT '' COMMENT '用戶編號',
  `AccountNo` varchar(255) DEFAULT NULL COMMENT '帳號',
  `TranAmount` int(11) DEFAULT NULL COMMENT '模擬帳戶入資金額',
  `CommissionLimit` decimal(20,4) DEFAULT '2.9900' COMMENT '最低佣金',
  `CommissionRate` decimal(20,4) DEFAULT '0.0125' COMMENT '佣金比例',
  `Cash` decimal(20,4) DEFAULT '0.0000' COMMENT '現金',
  `UsableCash` decimal(20,4) DEFAULT '0.0000' COMMENT '可用資金',
  `Status` tinyint(4) DEFAULT '1' COMMENT '帳號狀態:1正常',
  `AccountType` tinyint(4) DEFAULT '1' COMMENT '帳號類型:1現金帳號,2保證金帳號',
  `CreateTime` datetime DEFAULT NULL COMMENT '建立時間',
  PRIMARY KEY (`Id`)

其中一個用戶能夠對應多個帳戶,因此有一個AccountNo做爲區分。 TranAmount爲初始資金,用於重置帳戶。佣金字段用於模擬交易的手續費和稅費。可用資金字段是,當用戶掛單的時候有一部分資金處於凍結狀態,可用資金就是去除凍結資金的金額。架構

訂單表

`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '模擬交易訂單表',
  `MemberCode` varchar(20) DEFAULT '' COMMENT '用戶編號',
  `AccountNo` varchar(20) DEFAULT '' COMMENT '模擬帳號',
  `SecuritiesType` varchar(10) DEFAULT '' COMMENT '股票類型:us,hk,sh,sz',
  `SecuritiesNo` varchar(20) DEFAULT '' COMMENT '股票編號',
  `CPrice` decimal(20,4) DEFAULT '0.0000' COMMENT '委託價',
  `Price` decimal(20,4) DEFAULT '0.0000' COMMENT '價格',
  `OrderQty` decimal(20,4) DEFAULT '0.0000' COMMENT '股票數據量',
  `Side` char(1) DEFAULT '' COMMENT '交易類型:B買、S賣',
  `OrdType` tinyint(4) DEFAULT '1' COMMENT '訂單類型:1市場訂單、2限價訂單、3止損訂單、4作空市場訂單、5作空限價訂單、6作空止損訂單',
  `execType` tinyint(4) DEFAULT '1' COMMENT '執行類型:0新的,1成交、2取消、3拒絕',
  `Commission` decimal(20,4) DEFAULT '2.9900' COMMENT '佣金',
  `Reason` tinyint(4) DEFAULT '0' COMMENT '訂單拒絕理由:0正常、1資金不足、2倉位不足、3超時失效',
  `Amount` decimal(20,4) DEFAULT '0.0000' COMMENT '金額',
  `EndTime` datetime DEFAULT NULL COMMENT '訂單截止時間',
  `CreateTime` datetime DEFAULT NULL COMMENT '訂單時間',
  `TurnoverTime` datetime DEFAULT NULL COMMENT '成交時間',
  PRIMARY KEY (`Id`)

這是最重要的兩張表,其餘幾張表就不羅列詳細的內容,只作簡單說明數據庫設計

  • 資產表(記錄浮動盈虧,持倉金額,各類時間範圍的收益率)
  • 額外津貼記錄表(記錄除權,除息)
  • 資金記錄表(記錄特殊資金變更)
  • 倉位表
  • 倉位記錄表(記錄倉位變化)
  • 作空倉位記錄表
  • 排行榜

掛單

掛單的核心就是向數據庫插入一條記錄,不過即使是簡潔的js代碼,也差很少寫了80行代碼。 首先就是一系列的判斷,是否能夠建立訂單。ide

  • 參數是否在取值範圍內。
  • 市價單類型,判斷是否開市,未開盤時間段不能建立訂單。
  • 帳戶異常狀態不能建立訂單。
  • 若是是賣多單,或者買空單,則要把倉位數據取出來判斷,是否倉位夠扣。
  • 若是是買多單,或者賣空單,則要計算扣除佣金(手續費)後可用資金夠不夠。
  • 若是是限價單或者是止損單,則判斷價格設置是否在有效範圍內。 而後執行一個數據庫事務,插入一條訂單記錄,同時修改可交易倉位或者可用資金。

撤單

撤單比掛單簡單許多。主要步驟就是先判斷訂單是否存在,而後修改訂單狀態,同時修改可交易倉位或者可用資金。微服務

模擬交易主進程

系統每隔10秒執行一次邏輯。設計

全部訂單緩存策略

若是每隔10秒鐘從數據庫讀取全部訂單的話,效率會很低,並且過多佔用數據庫IO資源。因此訂單數據都緩存在成交判斷的進程內存中。未來也能夠升級爲使用redis等內存數據庫來存儲。 當有訂單建立的時候,經過消息隊列通知進程。當進程重啓的時候,從數據庫讀取數據進行初始化。

超時訂單處理

有些訂單一直沒有知足成交條件,但已經超過交易時間,因此要進行處理。(訂單狀態設置爲拒絕)

成交判斷

未開盤則跳過。 根據訂單類型判斷是否達到成交條件

'訂單類型:1市場訂單、2限價訂單、3止損訂單、4作空市場訂單、5作空限價訂單、6作空止損訂單' Price:訂單設置的價格 price:當前股價 B:買入 S:賣出

let trigge = false
        switch (OrdType) {
            case 1:
                trigge = true;
                break;
            case 2:
            case 3:
                trigge = Side == "BS" [OrdType - 2] ? (Price >= price) : (Price <= price)
                break;
            case 4:
                trigge = true;
                break;
            case 5:
            case 6:
                trigge = Side == "BS" [6 - OrdType] ? (Price >= price) : (Price <= price)
                break;
        }

執行成交

最初是用程序執行的,後來爲了執行效率和數據一致性,採用存儲過程。 首先,咱們須要查詢出帳戶的現金和可用資金,以及倉位信息。 若是是賣多或者買空(減小持倉,增長現金),咱們計算出此時須要增長的金額,固然這個時候可能出現倉位不夠的狀況,就拒絕訂單。 若是是買多或者賣空(增長持倉,減小現金),咱們就須要計算此時須要扣除的金額,若是出現可用金額不足,就拒絕訂單。 最後,咱們修改帳戶的實際金額和可用金額,寫入持倉記錄和現金變化記錄,修改訂單狀態爲已成交狀態。

信息查詢

普通數據庫查詢,這裏很少贅述了。

除權、除息

因爲模擬交易系統沒法第一時間自動獲得除權和除息的消息,因此當須要進行除權和除息的操做的時候,可能用戶已經發生成交的訂單。這時候須要根據持倉記錄變動表進行一些計算,恢復正確的持倉,若是是除息就是根據現金記錄變動表,進行資金從新計算。最後咱們把此次操做的日誌記錄下來。

相關文章
相關標籤/搜索