Node.js股票模擬交易後臺 原 薦

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

基本功能

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

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

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

這個後臺程序以一個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行代碼。 首先就是一系列的判斷,是否可以創建訂單。

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

撤單

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

模擬交易主進程

系統每隔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;
        }

執行成交

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

信息查詢

普通數據庫查詢,這裏不多贅述了。

除權、除息

由於模擬交易系統無法第一時間自動得到除權和除息的消息,所以當需要進行除權和除息的操作的時候,可能用戶已經發生成交的訂單。這時候需要根據持倉記錄變更表進行一些計算,恢復正確的持倉,如果是除息就是根據現金記錄變更表,進行資金重新計算。最後我們把這次操作的日誌記錄下來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章