撮合引擎開發 完結篇

2021-10-01 06:37:09 字數 3352 閱讀 2624

撮合引擎開發:開篇

撮合引擎開發:mvp版本

撮合引擎開發:資料結構設計

撮合引擎開發:對接黑箱

撮合引擎開發:解密黑箱流程

撮合引擎開發:流程的**實現

撮合引擎開發:快取和mq

撮合引擎開發:日誌輸出

撮合引擎開發:完結篇

本小節是該系列文章的最後一篇了,將講解剩下的一些東西,包括交易委託賬本中訂單佇列的實現邏輯、更多訂單型別的實現邏輯。另外,不少朋友在問,完結後所有**是否會開源放上 github?我只能說,長期大概率會開源,但短期內還沒打算開源。

交易委託賬本其實就是由兩個訂單佇列組成的,乙個買單佇列,乙個賣單佇列。任何對交易委託賬本的查詢和操作,實際上都是查詢和操作這兩個佇列。訂單佇列的設計也直接影響了撮合的效能,前面文章講資料結構設計時也有簡單聊了訂單佇列的設計,我們主要是用二維鏈結結合 map 來儲存所有訂單的,依賴的是container/list包。

訂單佇列的結構體如下:

type orderqueue struct

sortby指定**排序的方向,買單佇列是降序的,而賣單佇列則是公升序的。parentlist儲存整個二維鍊錶的所有訂單,第一維以**排序,第二維以時間排序。elementmap則是 key 為**、value 為第二維訂單鍊錶的鍵值對。

初始化函式就比較簡單了,對幾個字段賦值而已,**如下:

func

(q *orderqueue)

init

(sortby enum.sortdirection)

除了初始化函式,還提供了另外五個函式:

這個流程確實有一點複雜,可以多看幾遍好好消化,最好自己動手將其轉為**實現。

其他幾個函式就簡單了,關於最後乙個函式需要補充說明一下。讀取深度**是為了方便處理 market-opponent、market-top5、market-top10 等型別的訂單時判斷上限**。請看該函式的**以理解該函式的邏輯和用法:

func

(q *orderqueue)

getdepthprice

(depth int)(

string

,int

) p := q.parentlist.

front()

i :=

1for

; i < depth; i

else

} o := p.value.

(*list.list)

.front()

.value.

(*order)

return o.price.

string()

, i}

我們引擎總共支援了六種訂單型別,之前的文章有簡單介紹過,但沒有深入講解這幾種不同型別的具體業務邏輯應該是怎樣的,因此,在此將這部分內容補充上。

處理邏輯就是:

判斷新訂單是買單還是賣單。

如果是買單,那從 orderbook 中讀取出頭部賣單,即賣單佇列中的頭部訂單;如果是賣單,那從 orderbook 中讀取出頭部買單,即買單佇列中的頭部訂單。

新訂單為買單時,如果頭部訂單為空,或者新訂單小於頭部訂單,即無法成交,那就把新訂單新增到買單佇列中,處理結束;新訂單為賣單時,如果頭部訂單為空,或者新訂單大於頭部訂單,即無法成交,那就把新訂單新增到賣單佇列中,處理結束。

否則,符合匹配條件,新訂單和頭部訂單進行撮合成交。

撮合完成後,如果新訂單剩餘數量為零則結束,如果還大於零,則回到第2步繼續取下乙個頭部訂單,如此迴圈。

ioc 限價與普通限價不同的地方只有乙個,如果新訂單和頭部訂單不匹配時,普通限價單會被新增到訂單佇列中,而 ioc 限價則是作撤單處理,請看下圖:

缺省市價單的邏輯也比較簡單,它不需要判斷**,只要頭部訂單不為空,就直接和頭部訂單匹配成交,其處理邏輯如下圖:

最優五檔/十檔市價單與缺省市價單的邏輯也是類似的,不同點在於:預設市價的成交**沒有上限或下限,但最優五檔/十檔市價則存在**上限或下限,超過上下限的委託單不會成交。畫圖太累,還是直接貼**吧,以下是處理買單的:

func

dealbuymarkettop

(order *order, book *orderbook, lasttradeprice *decimal.decimal, depth int

) limitprice,

_:= decimal.

newfromstring

(pricestr)

loop:

headorder := book.

getheadsellorder()

if headorder !=

nil&& limitprice.

greaterthanorequal

(headorder.price)

}else

}

最後一種型別,對手方最優價,該型別只與對手方一檔的價位成交,但與最優五檔/十檔還有一點不一樣:最優五檔/十檔未成交的部分是作撤單處理的,而對手方最優價最後未成交的部分則是轉為限價單。請看**:

func

dealbuymarketopponent

(order *order, book *orderbook, lasttradeprice *decimal.decimal)

limitprice,

_:= decimal.

newfromstring

(pricestr)

loop:

headorder := book.

getheadsellorder()

if headorder !=

nil&& limitprice.

greaterthanorequal

(headorder.price)

}else

}

至此,整個系列就此完結。不過,我的撮合程式依然會繼續迭代公升級,另外,也將開始開發其他元件,將會和當前這個撮合引擎結合來用。歡迎關注後續動態。

作者的個人部落格

機房完結篇

做著做著這個大一點的專案就被我做完了。從開始的不知從何入手,到後來的對大多數問題應對自如,這個過程只有自己親身體會過了才能深刻感受到自己真的學到了不少。既然是完結篇,我就總結一下完成之前做的最後的工作吧 1 建立mdi窗體。一開始沒有意識到這個問題,最後優化的時候加上mdi窗體發現子窗體都出不來了。...

CSS基礎完結篇

position 它的英文意思 位置 的意思 它在css中主要是用來實現對乙個元素的定位 在css中定位有三種方式 固定定位 position fixed 相對定位 position relative 絕對定位 position absolute 注意 要實現乙個元素的定位 那麼一定使用 定位的座標...

包頭的生活完結篇

隨著火車的開動,我在包頭一周的生活也隨之結束了。在火車上我有一種如釋重負的感覺,包頭的生活讓我覺的太累了。每天紅腫著眼睛,用兩條腿來回在商行和資訊中心,包頭的天氣很冷,尤其是風很大。吹的讓人受不了。在包頭的工作到不是很緊張,只是去商行看看有什麼新的需要,然後記下來或改一下就可以,但包頭宿舍的居住環境...