高頻交易系統怎樣在多線程和埠通訊之間取捨?

如題,比如在tick data處理和後續交易信號分析之間交換數據,採用多線程系統的延遲小,但不利於代碼功能區分;多個程序之間埠通訊的方法則代碼比較清晰,但顯然會增加延遲。如何取捨?


如果通訊方式一樣,比如都用共享內存,那麼多線程和多進程間的主要區別就只有程序崩潰時的隔離特性,多線程一崩潰就全完蛋,多進程只會影響一部分。

如果還考慮軟體工程意義,不同進程通常意味著不同的程序,甚至不同的項目,操作風險會降低,這是很多交易系統做兩個進程而不是一個進程的重要原因,風控進程和策略進程軟體工程意義上隔離,改策略不會增加亂報單的可能性。

這兩點考慮到了之後,進程數越少越好。不同邏輯流(線程)間的同步越少越好。低計算量下,最低延遲通常是單線程邏輯得到的。

做低延遲都需要考慮I/O blocking到被喚醒執行所耗費的時間,用Socket等需要syscall和context switch的當然更應該能避免則避免了。

當然這一切都是基於高頻交易,更準確的說是低延遲交易領域。不是所有電子交易系統都處於這一領域,其他領域的架構根據不同的需求可能完全不同。


首先我同意軟體解藕的方法很多,按進程拆分不過是其中一種,但不必然是最好的一種。事實上要提高開發效率和降低維護難度,是一項需要根據團隊成員的技術特點不斷摸索的藝術,不必預先把自己的思維模式限制死了,嘗試一下其他方法(比如 OO ,Functional )也許有更好的效果。

根據我(多年打雜)的經驗來看,交易系統也是特別符合《人月神話》中推薦的外科手術團隊的開發模式。開發這種高精密系統人多了其實有負面作用,最好的辦法是以一兩個高水平程序員為主力設計和開發,再加幾個雜兵跑堂就可以了。所以解決這個問題有一個四海一家的終極大法:讓老闆漲工資高薪聘請一流的技術專家。當你有一個一流高手坐鎮主攻的時候,解藕就從多人協作變成一項個人品味的問題了,只要根據主攻手的口味選擇方案就好。

當然我明白人在江湖,身不由己。以上建議對於已經有很多歷史遺留或者起了一半的項目來說顯然是遠水解不了近渴。所以下面嘗試給點實際的建議。

首先進程間通信(IPC)有很多種方法,埠通訊(Socket)絕對不是最快的那種。Named pipe 和共享內存都可以做的更好,事實上最快的辦法是共享內存+獨佔 CPU core,可以參考 Java-Chronicle 的實現。這種方法做到幾十鈉秒的通信延遲是沒問題的,見:fastest (low latency) method for Inter Process Communication between Java and C/C++。

關於埠通訊為什麼慢,只要看這篇文章就可以理解:Know your TCP system call sequences,見下圖:

即便你用的是本地介面(localhost),一樣要經過系統調用(system call)切換進 kernel space,中間經過無數內存拷貝,協議檢查之類浪費時間的事情。這些問題在共享內存方案下都不存在。所以一個簡單的做法是重寫你們的通信模塊,採用這些更快的通信方法。

如果你的攤子實在太爛以至於修改通信代碼也是不能承受之重,那麼還有一手秘籍叫做替換系統調用。簡言之就是用修改函數指針的方式把系統調用入口換成自己的程序,比如用共享內存來實現埠通訊的 API。這樣你可以在不改動現有程序的基礎上改變通信方式來提高通信速度。具體怎麼做可以參考流行的開源實現 OpenOnload,雖然它主要是替換 TCP/IP 協議棧,但思路是一樣的。

其實這個時候是最能體現 Java 等基於虛擬機位元組碼的語言的優勢的。如果你用 Java,那麼替換系統調用就很容易,對 JVM 上 instrumentation 即可,嫌麻煩可以直接用 JMockit 之類的庫,用法很簡單(請允許我對於深陷 C++ 囹圄中苦苦掙扎的同學們表示一下同情)。


一點經驗分享:

1. 交易系統或是高頻交易系統必然是多線程的,原因略去,有時間我再修改加上去。

2. 直接分享我寫高頻程序的經驗(在不影響我策略的基礎上盡量分享),僅供參考。

以下所有層都是單獨運作,互相之間沒有Dependencies,數據區共享。

A : 單向數據取得層,(深度,成交量等..來源:網路,延時時間:不確定),基本是每個數據項開一個「無限」 循環去取數據放入公共數據區(內存數據,如果數據量巨大,可以考慮基於內存的資料庫。)

B: 數據加工層: 數據來源,內存(A),延時,基本無延時,數據輸出--&>&>依然是公共數據區,內存。

C: 主邏輯層:數據來源,內存(B 加工後的數據,avg..spread..top value..之類的),根據你的策略作出買賣之類的動作(開啟線程D,), 主邏輯層依然做自己的事。

D1: 訂單跟蹤層: 數據來源,網路,跟蹤訂單狀態及其後續要採取的動作。。

D2:............

D3...........

D4...........

P.S..如果樓主指的是本地到網路的埠,而不是線程之間的埠。那一個普通PC就有好幾萬。如果還是不夠。我們再討論。


回頭看了下自己的答案,過於關注在模塊化這個編程視角了,沒有跟行業需求結合,覺得有些簡單粗暴了,修改一下。

@董可人@盧旺彬回答都很詳細,分別提到了遺留系統的處理方法和分析多線程和通訊層面的優劣比較,非常有借鑒意義。

補充一下,由於題主對高頻系統的具體信息甚少,也不清楚是否只需要接一個交易所,因此大多數人只能按低延遲系統來回答,我這邊稍微發散一下,引出幾個相關的信息,供大家深入討論。

首先, 系統各業務功能的模塊化與主程序採用什麼樣的部署運行狀態(多線程或多進程)是不矛盾的,在各部分系統用同一種編程語言的前提下,兩者可以輕鬆地同時得到。這也是大家在答案中都提到過的解耦,但如果是多語言開發的系統,彼此之間還是需要數據通訊,或者是多個策略需要共用一個前端數據源,比如交易所只允許接一個連接,多個策略系統要用,可能沒辦法部署在一台機器上,這樣的情況下網路通訊都不可避免,可以升級通過內部網路和機器硬體來處理,換句話說,得具體問題具體分析和優化。

其次,要分析下程序造成延遲的主要原因,或者從需求來講需要低延遲的主要因素在哪兒,需要具體分析下,任何需求的滿足都是要付出代價的,尤其是一些非功能性的需求,有時會導致整個系統成本急劇地上升。在高頻交易中,具體高頻到什麼程度,是否網路間的數據傳輸延遲是最大的瓶頸?是在內網還是外網,如果是外網,託管機器就可消除網路傳輸的延遲,如果是內網,改善網路設備和機器也是可行方案,這些相關的環節都是需要分析的問題,曾經我們的一個客戶,在這個方面糾結了很久,但後來發現,如果演算法上做出些改進,系統一下子減少了上百個ms的延遲,所以抓住主要矛盾才是解決問題的關鍵。

再次,回歸到題主的具體問題,假定只集中在這個問題上, tick data已經有了,分析tick data的模塊和tick data採集之間如何交換數據,實際上高頻交易數據部分的傳輸是單向的,tick data的數據採集是生產者,分析部分是消費者,很簡單的計算模型,用共享內存的方式即可解決,因為交易所數據是不斷推過來的,數據分析部分必須在下一條數據到來之前完成處理,否則看緩衝區的處理方式可能會有堆積或數據丟失,建議採用類似於操作系統對硬體中斷的兩步處理模式,把分析任務細分解一下,什麼時候數據足夠了啟動分析,和讀取數據之間做個平衡處理,在數據分析方面儘可能地改進演算法,減少它的延遲才是關鍵,如果它的計算時間少於tick data數據的間隔,很多複雜的優化工作就可以省了。

最後,一點建議,跟我們最近的一個R語言的策略開發SDK實例相關,R語言層面寫的策略只能是單線程的,而後端需要支持多個交易所的行情數據採集源、交易通道介面,必須是多線程,前後之間通過用C++開發R語言擴展包來銜接,中間就是採用的共享內存數據來通訊的,供借鑒參考。

-------以下是原回答 ------------

作為程序員,很不明白樓主的問題,多線程怎麼就不能做到代碼功能的區分了呢? 模塊化跟是否用多線程,還是部署成多個程序,用網路通信沒有關係的,主要在於程序員對業務的理解程度,以及能否把這個需求用編程技術優雅地實現出來的功力。

只有一個程序,哪怕源代碼只有一個文件,也可以做到很好的模塊化。


1. 不要過度追求「distribution architecture」

2. 堅定不要過度追求

3. 打散你的code,分不同的module

3.1 可以學習C是怎麼做的,哪怕是non-OO語言,也是可以打散的

4. 乾貨時間, martin fowler的microservices: Microservices

4.1 理解透了,你也知道哪些應該「單獨」進程,哪些放在一個進程里multi thread處理即可

PS: 我很不喜歡下面的一些答案,不管咋就噴,從我的經驗來看我覺得這個問題挺好的:

market data 和 策略order之間的協調是永遠的難點之一。


題主應該是The Art of Unix Programming這類書看到溝里去了吧,言必稱進程,視線程和面向對象為毒物。


1.怎麼感覺在【高頻交易】這個話題下的問題的技術水平如此低下?錯覺么?

2.既然主要需求是極端高的性能,以及極端低的延遲,那麼整個系統的設計原則肯定是:怎麼高性能怎麼來,怎麼簡單怎麼來。所以:

3.代碼功能區分(其實是模塊化,低耦合,低硬編碼)、多個程序之間埠通訊的方法(難道是埠復用?或者是基於TCP/UDP的進程間通信?)等這些顯然會增加延遲的技術,那就肯定不用。

甚至...甚至...甚至....嗯嗯......

4444444.有條件的最好用FPGA、DSP來代替低性能的普通PC機、工作站或伺服器,有研發技術實力的研究所或公司甚至可以用Hyper?IFR51(基於光信量子技術的51單片機)來進行超速計算。有條件的單位可以使用微波通信來代替普通光纖網路,有海量資金的高端企業甚至可以通過核心人脈去租用電信最新最保密的軍用級P3OEMod25k(基於核子共振技術的25k極速撥號電話網路)來進行超速通信。噗....


All process should be single thread.

You should use cup isolation to pin a process to a core.

They communicate thru shared memory if they are execution related processes, otherwise should be multicast, like risk related processes.


題主說「採用多線程系統的延遲小,但不利於代碼功能區分」有個隱性前提未說明:基於傳統Web或簡陋Socket模式進行交易的系統架構設計。


我們自己開發的系統基本上還是用socket為主,確實考慮到開發成本的問題。如果數據量大的時候,偶發有線程互斥等其他問題。這也是沒辦法的事情,一來覺得交易所的數據給的就慢。你本地提高几十毫秒未見得對整體系統有多大提升,換其他的方式還需要各種測試。綜合來看,socket易用,也便宜。有些問題可以靠演算法來優化,只要穩定,國內基本都ok,國內的數據慢,也不用想太多。


以前在法國巴黎銀行的打雜時,專門做高頻交易系統的那個團隊,據說重寫了STL,然後用FPGA實現部分核心演算法,並把交易伺服器儘可能搬到了交易所附近。


&> 多線程系統的延遲小,但不利於代碼功能區分

為嘛不利於代碼功能區分?

&> 多個程序之間埠通訊的方法則代碼比較清晰,但顯然會增加延遲

增加多大的延遲?是不可接受的么?莫非你的系統需要到微妙以內?

你的目的是解決問題,而不是提出一些不存在的問題。


不要用多線程,現在一般使用單線程模式,即一顆CPU一個線程,努力把CPU跑滿,如果計算能力不夠就採用分散式。


推薦閱讀:

quant是否是一個江河日下的職業?
用 Trading System Lab 自動生成的交易策略,怎麼保證它不是遺傳演算法過度優化的產物?
機器學習、大數據、雲計算會端掉量化寬客的飯碗嗎?
如何通俗易懂地向一個外行解釋 Quant 是怎麼幫助金融機構賺錢的?
在外資投行的國內quant組工作是什麼體驗?

TAG:Python | 寬客Quant | Java | 高頻交易 |