羅 超 許紅星 段 然
(云南大學(xué)軟件學(xué)院 云南 昆明 650504)
經(jīng)濟(jì)市場快速發(fā)展,帶來資本市場的快速發(fā)展。傳統(tǒng)的手工交易方式存在著效率低、盲目投資、實(shí)效性差等問題,導(dǎo)致手工交易越來越無法滿足人們的需求。在手動(dòng)交易的基礎(chǔ)上,人們開發(fā)出了量化交易的方式,以先進(jìn)的數(shù)學(xué)模型替代人為的主觀判斷,利用數(shù)據(jù)挖掘、機(jī)器學(xué)習(xí)、深度學(xué)習(xí)等計(jì)算機(jī)技術(shù)從龐大的歷史數(shù)據(jù)中海選能帶來超額收益的多種“大概率”事件以制定策略[1-4],極大地減少了投資者情緒波動(dòng)的影響,避免在市場極度狂熱或悲觀的情況下做出非理性的投資決策。
在研究量化模型和交易策略的過程中,使用的數(shù)據(jù)主要是時(shí)間序列數(shù)據(jù)。這種數(shù)據(jù)如果直接以數(shù)字方式呈現(xiàn),會(huì)導(dǎo)致難以分析數(shù)據(jù)的特點(diǎn),難以直觀看出變化規(guī)律,對(duì)策略的制定會(huì)有很大的限制。如果只涉及一般大盤和股票數(shù)據(jù),研究者可以選擇市面上成熟的股票行情軟件作為輔助參考,但這難以滿足研究者的個(gè)性化需求。例如在研究中自定義了新指標(biāo)的計(jì)算模型、自合成了新板塊數(shù)據(jù)時(shí),不僅要求能靜態(tài)地顯示數(shù)據(jù),還要能在策略回測(cè)、實(shí)盤交易時(shí)動(dòng)態(tài)地更新并顯示數(shù)據(jù),但是常見的量化平臺(tái)并不提供此類個(gè)性化的可視化接口,這給研究工作造成了阻礙。
對(duì)于上述個(gè)性化的需求,研究者通常采用兩種方法解決:股票公司訂制數(shù)據(jù)、自己編程實(shí)現(xiàn)。第一種方法最為直接,但是在研究過程中模型和策略的變動(dòng)比較頻繁,訂制的內(nèi)容可能跟不上需求的變更,而且如果是小型研究團(tuán)隊(duì)或個(gè)人研究者,這也增加了研究成本。第二種方法對(duì)編程能力提出了要求,可以使用可視化工具包做出圖形[5-6],但一般復(fù)用性較差、容錯(cuò)率較低,只能依托固定的平臺(tái)或程序,不能適應(yīng)數(shù)據(jù)的高速變化,甚至沒有考慮數(shù)據(jù)的動(dòng)態(tài)更新,且市面上缺乏完整的可供調(diào)用的可視化模型或框架,也缺少對(duì)圖形繪制的詳細(xì)描述,這無形中降低了研究效率。
因此,我們從實(shí)際出發(fā),針對(duì)存在問題和市場需求,建立了一套金融時(shí)間序列數(shù)據(jù)可視化框架,兼容大部分圖形和金融指標(biāo)的顯示,也允許用戶添加自定義指標(biāo),支持?jǐn)?shù)據(jù)動(dòng)態(tài)更新的同時(shí),還考慮到了回測(cè)和實(shí)盤過程中該類數(shù)據(jù)具有高實(shí)時(shí)性、高并發(fā)性、瞬時(shí)數(shù)據(jù)量大的特點(diǎn),改進(jìn)了數(shù)據(jù)刷新方式,為下游用戶做數(shù)據(jù)分析與量化交易策略研究提供了可靠且高效的上游數(shù)據(jù)可視化支持。且框架本身也可作為同類型軟件UI設(shè)計(jì)部分的參考,可以在不同平臺(tái)用不同編程語言實(shí)現(xiàn)。最后以實(shí)際工作為參考,將框架與各類常見的量化交易平臺(tái)相結(jié)合,驗(yàn)證了框架的實(shí)用性、高效性和跨平臺(tái)性。
Tick是交易數(shù)據(jù)流的一種快照,是金融時(shí)間序列數(shù)據(jù)的基本單位。以期貨市場為例,交易系統(tǒng)會(huì)實(shí)時(shí)收到交易所每秒2次的Tick行情推送,其行情信息有最新價(jià)、成交量、成交額等,不同市場或不同量化平臺(tái)提供的Tick數(shù)據(jù),在數(shù)據(jù)結(jié)構(gòu)和推送頻率上都有所不同。我們將一個(gè)Tick數(shù)據(jù)定義為一個(gè)基本單位t,t的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)意在滿足所有信息能完整獲得的情況下,做到每次傳輸?shù)臄?shù)據(jù)量最小化。作為一種需要高頻刷新的數(shù)據(jù),其本身的信息攜帶量過大,會(huì)導(dǎo)致傳輸性能的降低和傳輸成本的增加。因此,Tick數(shù)據(jù)的結(jié)構(gòu)設(shè)計(jì),只保留交易中的基本數(shù)據(jù),其他關(guān)鍵數(shù)據(jù),可由基本數(shù)據(jù)計(jì)算出來。綜上所述,t被設(shè)計(jì)為一個(gè)四元組:
t=[′price′,′datetime′,′volume′,′amount′]
(1)
式中:price為最新價(jià);datetime為Tick的創(chuàng)建時(shí)間;volume為瞬時(shí)成交量;amount為瞬時(shí)成交額。
K線模型是最常用的數(shù)據(jù)可視化模型,其數(shù)據(jù)由單位時(shí)間內(nèi)的Tick數(shù)據(jù)生成。K線的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)為一個(gè)多元組:
bar=[′datetime′,′open′,′high′,′low′,
′close′,′volume′,′amount′]
(2)
式中:datetime為K線數(shù)據(jù)的起始時(shí)間(或結(jié)束時(shí)間);open為單位時(shí)間內(nèi)的開盤價(jià);high為單位時(shí)間內(nèi)的最高交易價(jià)格;low為單位時(shí)間內(nèi)的最低交易價(jià)格;close為單位時(shí)間內(nèi)的收盤價(jià);volume和amount分別為單位時(shí)間內(nèi)的成交量和成交額的總和。
定義T=[t1,t2,…,tN]為Tick數(shù)據(jù)的集合,間隔頻率為x。設(shè)K線的單位時(shí)間為y,N為單位時(shí)間內(nèi)Tick數(shù)據(jù)的個(gè)數(shù),若xN=y,則K線數(shù)據(jù)可以由集合T通過以下公式合成:
bar[′datetime′]=t1[′datetime′]
(3)
bar[′open′]=t1[′price′]
(4)
bar[′close′]=tN[′price′]
(5)
bar[′high′]=Max(T[′price′])
(6)
bar[′low′]=Min(T[′price′])
(7)
bar[′volume′]=∑T[′volume′]
(8)
bar[′amount′]=∑T[′amount′]
(9)
可視化框架的架構(gòu)分為3層,分別是底層接口、中層引擎和上層應(yīng)用,如圖1所示。
圖1 可視化框架架構(gòu)
中層引擎的設(shè)計(jì)參考了vn.py框架的設(shè)計(jì)思路[7],包括數(shù)據(jù)引擎和事件引擎,往下對(duì)接各種數(shù)據(jù)輸入接口,往上服務(wù)于各種應(yīng)用模塊。
底層接口負(fù)責(zé)對(duì)接輸入數(shù)據(jù),主要是時(shí)間序列數(shù)據(jù)、金融技術(shù)指標(biāo)和計(jì)算模型。上層應(yīng)用包括可視化模塊和功能模塊、可視化模塊負(fù)責(zé)圖形的繪制、功能模塊涉及與用戶的動(dòng)態(tài)交互。
2.2.1 可視化模塊計(jì)算模型
根據(jù)大多數(shù)交易員的使用習(xí)慣,可視化部分依然采用主流的設(shè)計(jì),即1個(gè)主圖、2個(gè)副圖的形式。主圖用來顯示K線圖與均線圖,副圖根據(jù)需要可切換顯示各種指標(biāo)。我們以顯示區(qū)域的左上角為坐標(biāo)(0,0),右下角坐標(biāo)為(x,y)建立一個(gè)矩形顯示區(qū)域并劃分3個(gè)子圖區(qū),如圖2所示。3個(gè)子圖區(qū)有各自的縱坐標(biāo)和比例,但是3個(gè)圖區(qū)的橫坐標(biāo)是同步的。
圖2 可視化模塊
設(shè)有一組金融時(shí)間序列數(shù)據(jù)B=[bar1,bar2,…,barN],若此時(shí)模塊可顯示的K線個(gè)數(shù)為N,即將B全部繪制到顯示區(qū)域,需要以下幾個(gè)步驟:
(1) 確立子圖的坐標(biāo)系。計(jì)算橫縱坐標(biāo)軸的上下界、比例和顯示間隔。
橫坐標(biāo):將子圖的橫坐標(biāo)等分N+1份,可得到N條刻度,刻度的值由此位置所在K線的datetime確定。
主圖縱坐標(biāo):首先將輸入數(shù)據(jù)中四個(gè)維度[′open′,′high′,′low′,′close′]的所有數(shù)據(jù)看作一個(gè)集合,獲取集合中的最大值和最小值作為主圖縱坐標(biāo)的上下界,并計(jì)算兩者差值d。模塊中預(yù)先設(shè)定了15個(gè)檔位的坐標(biāo)軸間隔,以及每個(gè)檔位對(duì)應(yīng)的數(shù)據(jù)取舍精度,如表1所示。
計(jì)算d與各間隔的比值,選擇比值最接近10的一檔作為主圖縱坐標(biāo)的間隔,表2使用5組具體數(shù)據(jù)以說明整個(gè)計(jì)算過程。
表2 坐標(biāo)軸間隔及上下界計(jì)算示例
副圖縱坐標(biāo):常見的副圖圖形主要有柱狀圖和折線圖兩種,在確立副圖縱坐標(biāo)時(shí)需要考慮輸入數(shù)據(jù)的分布。一種情況是數(shù)據(jù)只分布在X軸一側(cè),即全為正數(shù)數(shù)據(jù)或全為負(fù)數(shù)數(shù)據(jù),此時(shí)取數(shù)據(jù)絕對(duì)值的最大值計(jì)算比例即可。另一種情況是數(shù)據(jù)分布在X軸兩側(cè),此時(shí)X軸需要繪制到區(qū)域中心,兩側(cè)比例取數(shù)據(jù)絕對(duì)值的最大值計(jì)算。
(2) 計(jì)算圖形坐標(biāo)。將之前確立的坐標(biāo)系與顯示區(qū)域(屏幕)的坐標(biāo)系作轉(zhuǎn)換,主要繪制的圖形有K線圖、柱狀圖和折線圖。
圖3 K線圖形坐標(biāo)計(jì)算
2.2.2 功能模塊計(jì)算模型
功能模塊要實(shí)現(xiàn)的是數(shù)據(jù)圖形在顯示區(qū)域內(nèi)的縮放、左右移動(dòng)以及光標(biāo)十字線等內(nèi)容,本質(zhì)上是接受操作輸入,觸發(fā)可視化模塊的重繪機(jī)制,實(shí)現(xiàn)與用戶交互的過程。
(1) 縮放與平移功能??蚣軆?nèi)置兩個(gè)參數(shù),count用于控制顯示區(qū)域可繪制圖形的個(gè)數(shù),start用于記錄顯示區(qū)域第一個(gè)繪制的圖形的下標(biāo),2.2.1節(jié)中所描述的“設(shè)有一組金融時(shí)間序列數(shù)據(jù)B=[bar1,bar2,…,barN],將B全部繪制到顯示區(qū)域”,就是對(duì)應(yīng)于count=N,start=1的情況。數(shù)據(jù)B傳入框架時(shí)不是直接通過可視化模塊繪制,而是以參數(shù)count和start構(gòu)成的“滑動(dòng)窗口”在輸入數(shù)據(jù)B上進(jìn)行截取,然后再傳入可視化模塊進(jìn)行繪制,過程如圖4所示。改變count值就可以實(shí)現(xiàn)動(dòng)態(tài)放大縮小的可視化效果,同理固定count值并改變start值就可以實(shí)現(xiàn)平移效果。
圖4 縮放及平移功能
(2) 光標(biāo)十字線功能。隨著光標(biāo)在顯示區(qū)域中的移動(dòng),實(shí)時(shí)地以光標(biāo)為中心繪制水平與垂直兩條直線,并有一個(gè)浮動(dòng)窗口顯示光標(biāo)所指處圖形數(shù)據(jù)信息的功能。此功能有助于用戶更精準(zhǔn)快速地查看數(shù)據(jù),核心在于通過光標(biāo)的顯示區(qū)域坐標(biāo)計(jì)算出圖形數(shù)據(jù)在“滑動(dòng)窗口”中的下標(biāo),進(jìn)而獲取到數(shù)據(jù),過程如圖5所示。
圖5 光標(biāo)獲取數(shù)據(jù)
圖中設(shè)光標(biāo)的坐標(biāo)值為(x′,y′),通過式(10)和式(11)可計(jì)算出截取數(shù)據(jù)的下標(biāo)f(x′),進(jìn)而獲取數(shù)據(jù)。
(10)
(11)
中層引擎的功能是將程序中的各個(gè)組件,例如數(shù)據(jù)庫接口、多線程等整合到一個(gè)對(duì)象中,便于上層應(yīng)用的調(diào)用。下面對(duì)事件引擎和數(shù)據(jù)引擎的工作原理及流程做介紹。
2.3.1 事件引擎
事件引擎工作流程如圖6所示。
圖6 事件引擎工作流程
事件引擎是整個(gè)框架的核心組件,也是大多數(shù)交易系統(tǒng)或回測(cè)引擎,甚至大多數(shù)交互程序的設(shè)計(jì)基礎(chǔ)。事件引擎的設(shè)計(jì)基于事件驅(qū)動(dòng),事件驅(qū)動(dòng)簡單來說就是用戶點(diǎn)什么按鈕(即產(chǎn)生什么事件),計(jì)算機(jī)就執(zhí)行什么操作(即調(diào)用什么函數(shù))[9]。事件引擎主要完成的功能是收集事件對(duì)象(底層接口數(shù)據(jù)推送、用戶輸入)存入事件隊(duì)列,并依次傳入數(shù)據(jù)引擎作出相應(yīng)處理。目前本框架中數(shù)據(jù)引擎承擔(dān)了所有事件的處理工作,但仍把事件引擎和數(shù)據(jù)引擎的設(shè)計(jì)分隔開,是為以后框架更新、加入更多處理引擎做準(zhǔn)備。
2.3.2 數(shù)據(jù)引擎
數(shù)據(jù)引擎主要負(fù)責(zé)維護(hù)數(shù)據(jù)在整個(gè)框架中的讀寫、傳遞與計(jì)算,包括計(jì)算模塊、緩存模塊、數(shù)據(jù)庫接口模塊三個(gè)子模塊。主要完成以下兩個(gè)工作:
(1) 底層接口數(shù)據(jù)推送的處理。底層接口以某個(gè)頻率不斷向中層引擎推送tick數(shù)據(jù),由事件引擎?zhèn)魅霐?shù)據(jù)引擎后,將tick數(shù)據(jù)保存到數(shù)據(jù)庫并計(jì)數(shù),直到tick數(shù)據(jù)的個(gè)數(shù)滿足合成bar數(shù)據(jù)的要求,則計(jì)算模塊將這一段tick數(shù)據(jù)取出合成bar數(shù)據(jù)。如底層接口以3秒的頻率推送tick數(shù)據(jù),顯示模塊使用1分鐘級(jí)別的bar數(shù)據(jù),則每20個(gè)tick數(shù)據(jù)為一組合成bar數(shù)據(jù),合成方法如式(3)-式(9)所示。合成新的bar數(shù)據(jù)后,添加到緩存模塊,以內(nèi)置參數(shù)count和start重新截取顯示數(shù)據(jù)傳入顯示模塊并執(zhí)行重繪、內(nèi)置參數(shù)及截取方法如式(10)和式(11)所示。如底層接口傳入了bar數(shù)據(jù),則直接添加到緩存模塊。
(2) 用戶輸入的處理。用戶輸入是指用戶調(diào)用了功能模塊,或改變內(nèi)置參數(shù)count和start以放大、縮小、平移圖形,或移動(dòng)光標(biāo)以獲取光標(biāo)所指處圖形所包含的數(shù)據(jù)信息。如是前者,數(shù)據(jù)引擎將重新截取顯示數(shù)據(jù)傳入顯示模塊并執(zhí)行重繪,如是后者,數(shù)據(jù)引擎將根據(jù)式(10)和式(11)計(jì)算出光標(biāo)所指處對(duì)應(yīng)的顯示數(shù)據(jù)的下標(biāo),然后將數(shù)據(jù)傳入可視化模塊并執(zhí)行重繪。
底層接口是可視化框架的輸入通道,金融時(shí)間序列數(shù)據(jù)由此傳入中層引擎,且自定義指標(biāo)和自定義計(jì)算模型通過配置文件的形式保存,并由數(shù)據(jù)引擎中的計(jì)算模塊調(diào)用。
本框架的跨平臺(tái)性也由底層接口體現(xiàn)。用戶通過量化交易平臺(tái)訂閱數(shù)據(jù),在平臺(tái)的回調(diào)推送端調(diào)用底層接口,即可實(shí)現(xiàn)數(shù)據(jù)的持續(xù)可視化及交互,使用效果將在下一節(jié)與不同平臺(tái)對(duì)接測(cè)試中展示。
本節(jié)以實(shí)際工作為例,選取兩個(gè)代表性的量化交易平臺(tái)進(jìn)行對(duì)接測(cè)試,以說明本框架的主要功能及用途。
現(xiàn)有以下需求:取若干股票,自定義“煤炭”板塊,根據(jù)所取股票數(shù)據(jù)合成新板塊數(shù)據(jù),并對(duì)接國內(nèi)某量化交易平臺(tái),使新板塊數(shù)據(jù)在回測(cè)時(shí)能實(shí)時(shí)更新顯示。板塊的計(jì)算模型如表3所示。
表3 自定義板塊計(jì)算模型
第一步,訂閱這若干只股票的行情數(shù)據(jù),訂閱后量化平臺(tái)將在回調(diào)推送端自動(dòng)傳回行情數(shù)據(jù)。第二步,分析平臺(tái)傳回行情數(shù)據(jù)的結(jié)構(gòu)及字段信息,編寫計(jì)算模型,將平臺(tái)數(shù)據(jù)轉(zhuǎn)換成式(1)的形式。第三步,在平臺(tái)的回調(diào)推送端直接調(diào)用數(shù)據(jù)傳入接口。之后每當(dāng)平臺(tái)推送數(shù)據(jù),就會(huì)觸發(fā)事件引擎,通知數(shù)據(jù)引擎根據(jù)自定義的計(jì)算模型轉(zhuǎn)換數(shù)據(jù)并存入數(shù)據(jù)庫,并根據(jù)顯示模塊的參數(shù),合成相應(yīng)的bar數(shù)據(jù)及其他金融指標(biāo),最后由上層應(yīng)用繪制圖形,實(shí)現(xiàn)新版塊數(shù)據(jù)的持續(xù)可視化與交互。
在測(cè)試中,同時(shí)定義了多個(gè)板塊,涉及不同數(shù)量的股票數(shù)據(jù),添加了鍵盤事件實(shí)現(xiàn)板塊切換,并使用多個(gè)時(shí)間段回測(cè)觀察性能表現(xiàn),如表4所示。測(cè)試環(huán)境:Intel i7-8750H,內(nèi)存16 GB,以下測(cè)試中框架均能正常工作,響應(yīng)時(shí)間小于1秒,能夠滿足日常研究需要。自定義“煤炭”板塊的效果圖如圖7所示。
表4 平臺(tái)對(duì)接測(cè)試
圖7 自定義“煤炭”板塊效果圖
vn.py是基于Python語言的開源的量化交易系統(tǒng),基于vn.py二次開發(fā)說明了可視化框架可以作為同類型軟件UI設(shè)計(jì)的一部分,不局限于電腦端或手機(jī)端。在開發(fā)時(shí),由于可視化框架的中層引擎部分就取自于vn.py,所以框架的上層應(yīng)用可以很好地移植到vn.py中。軟件界面如圖8所示。
圖8 基于vn.py二次開發(fā)的軟件界面
本框架設(shè)計(jì)是為了滿足量化交易研究過程中個(gè)性化定制數(shù)據(jù)的可視化需求,使用戶可以更加注重策略和模型研究本身,直接調(diào)用接口,方便快捷,優(yōu)勢(shì)在于兼容目前市場上絕大多數(shù)的量化交易平臺(tái)。
此次工作的不足之處:(1) 測(cè)試時(shí)板塊數(shù)量與包含股票數(shù)量代入不夠,未能測(cè)試框架所能承受數(shù)據(jù)量的上限。(2) 回測(cè)周期較短,不能說明框架在長時(shí)間運(yùn)行時(shí)的穩(wěn)定性。(3) 沒有具體性能指標(biāo),只通過主觀判斷系統(tǒng)運(yùn)行效果,不具有說服力。針對(duì)以上問題將在后期的研發(fā)工作中加大測(cè)試力度,完善框架的整體性能評(píng)價(jià)。
最后框架本身還有很多值得改進(jìn)與擴(kuò)充的部分,將在今后的工作研究中不斷完善和更新。