祁 長(zhǎng) 興
(沈陽(yáng)師范大學(xué) 軟件學(xué)院, 沈陽(yáng) 110034)
分時(shí)數(shù)據(jù),是股票期貨等金融領(lǐng)域以及生產(chǎn)生活中的面向過程控制等領(lǐng)域的實(shí)時(shí)數(shù)據(jù),通過對(duì)大量分時(shí)數(shù)據(jù)做動(dòng)態(tài)統(tǒng)計(jì)分析,可以掌握其分時(shí)波動(dòng)規(guī)律,從而對(duì)產(chǎn)品的性質(zhì)好壞做出判斷,對(duì)數(shù)據(jù)發(fā)展趨勢(shì)做出輔助預(yù)測(cè)。但是分時(shí)數(shù)據(jù)的數(shù)據(jù)量較大,產(chǎn)品種類繁多,通過畫圖可以直觀反映指定時(shí)間段內(nèi)數(shù)據(jù)的發(fā)展變化情況,更利于量化分析。
GDI(Graphics Device Interface Plus)是Windows系統(tǒng)下負(fù)責(zé)系統(tǒng)與繪圖程序之間的信息交換的接口之一。本文采用了C#語(yǔ)言中的GDI以及GDI+技術(shù),設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)可以靈活拖拽在桌面窗口上的控件,以網(wǎng)絡(luò)上開源的A股實(shí)時(shí)數(shù)據(jù)為實(shí)驗(yàn)測(cè)試數(shù)據(jù),通過設(shè)置數(shù)據(jù)接口和顯示圖形屬性設(shè)定來完成對(duì)分時(shí)數(shù)據(jù)的即時(shí)顯示[1]。
根據(jù)控件的實(shí)現(xiàn)功能要求,控件在架構(gòu)上分為數(shù)據(jù)的采集,數(shù)據(jù)的管理和處理,數(shù)據(jù)的圖形加工處理3個(gè)模塊。外部分時(shí)數(shù)據(jù)通過數(shù)據(jù)采集模塊進(jìn)入控件數(shù)據(jù)按時(shí)間點(diǎn)分布,包括商品代碼,名稱,時(shí)間點(diǎn)信息和時(shí)間點(diǎn)數(shù)據(jù)等,在模塊內(nèi)拆分為K線數(shù)據(jù)(4種)和普通商品線性數(shù)據(jù)(1個(gè))。拆分后的數(shù)據(jù)進(jìn)入數(shù)據(jù)管理模塊,數(shù)據(jù)管理模塊首先是管理所有的對(duì)象,包括商品對(duì)象、行情列表列對(duì)象以及畫面對(duì)象,并提供相關(guān)數(shù)據(jù)的所有操作接口供程序內(nèi)部管理數(shù)據(jù)使用,將相關(guān)分時(shí)數(shù)據(jù)保存在本地臨時(shí)數(shù)據(jù)表中。數(shù)據(jù)圖形加工模塊對(duì)已經(jīng)加工處理過的數(shù)據(jù)進(jìn)行圖形化顯示[2-6]。
圖1 控件的架構(gòu)模型圖Fig.1 Structure model of control
控件在設(shè)計(jì)上分為2大功能模塊,圖形繪制和數(shù)據(jù)管理(將數(shù)據(jù)采集和數(shù)據(jù)的管理設(shè)計(jì)在一起)。圖形繪制的主要作用是按照控件初始化時(shí)給定的相關(guān)參數(shù)以及分時(shí)數(shù)據(jù)精確的繪制出圖形,并且負(fù)責(zé)響應(yīng)用戶鍵盤和鼠標(biāo)的輸入操作。數(shù)據(jù)管理的主要作用是提供不同的數(shù)據(jù)類型并管理這些數(shù)據(jù)[7]。
數(shù)據(jù)管理類的主要作用是用于采集信息、存儲(chǔ)信息和進(jìn)行必要的信息處理,為圖形繪制類提供必需的數(shù)據(jù)接口。
1) 數(shù)據(jù)管理類DataManager:該類中包含了3組對(duì)象:商品對(duì)象、行情列表列對(duì)象以及畫面對(duì)象。該類提供的是這些類的添加、獲取和更新接口,用于控件的所有對(duì)象的管理操作[11]。
2) 商品信息類Commodity:該類存儲(chǔ)了關(guān)于該商品的所有數(shù)據(jù),其中除了包括商品名稱、商品代碼、商品序號(hào)(記錄添加的順序,行情列表的默認(rèn)排序字段)和昨日收盤價(jià)以外,還包括商品的行情列表數(shù)據(jù),以及對(duì)應(yīng)的線數(shù)據(jù)[12]。
3) 行情列表數(shù)據(jù)類ListSubItems:該類除了存儲(chǔ)具體的數(shù)據(jù)值之外,還存儲(chǔ)了繪制時(shí)的相關(guān)字段字體顏色和背景顏色。
4) 線數(shù)據(jù)管理對(duì)象LineDataManager:該類主要提供的就是所有線數(shù)據(jù)對(duì)象的數(shù)據(jù)添加接口,由于線數(shù)據(jù)根據(jù)不同的線類型對(duì)應(yīng)的是不同的類,因此在添加數(shù)據(jù)時(shí)負(fù)責(zé)判斷所屬的線類型并添加對(duì)應(yīng)的線數(shù)據(jù)對(duì)象。
5) 線數(shù)據(jù)抽象類LineData:該類是線數(shù)據(jù)的抽象類,所有類型的線數(shù)據(jù)均繼承自該類。該類除了存儲(chǔ)線數(shù)據(jù)基本單位對(duì)象以外,還提供了獲取該線的最大值和最小值。其作用是在圖形繪制時(shí)判斷繪制區(qū)間的數(shù)據(jù)最大最小值范圍。
6) 線數(shù)據(jù)基本單位類LineDataUnit:該類是線數(shù)據(jù)的基本單位抽象類,所有類型的線數(shù)據(jù)基本單位均繼承自該類。其存儲(chǔ)了2個(gè)基礎(chǔ)數(shù)據(jù)即顯示數(shù)據(jù)值以及日期時(shí)間。
7) 時(shí)間段類TimePeriod:該類提供了一個(gè)簡(jiǎn)單的接口來實(shí)現(xiàn)添加一個(gè)時(shí)間段的所有時(shí)間標(biāo)簽。
8) 控件對(duì)象StockChart:該類的作用是打包管理所有的管理對(duì)象和繪制對(duì)象,并對(duì)開發(fā)者提供統(tǒng)一的使用接口。
圖形繪制結(jié)構(gòu)的概念一共有2個(gè):畫面和區(qū)域。畫面是構(gòu)成基礎(chǔ)界面的單位元素,從界面上看到的一個(gè)完整圖像則是一個(gè)畫面,區(qū)域是指每個(gè)畫面中繪制不同類型的數(shù)據(jù)而劃分的不同區(qū)間,其位置構(gòu)成為從上到下,每個(gè)畫面包含若干個(gè)區(qū)域。
1) 畫面類ChartImage:指定了邊框的寬度以及添加區(qū)域的方法和繪制畫面時(shí)確定該畫面中是否包含有柱線。
2) 區(qū)域類AreaClass:提供屬性和方法,實(shí)例化一個(gè)具體的區(qū)域設(shè)置。
3) 線信息類LineInfoClass:定義一組相關(guān)的數(shù)據(jù)集合為一條線,如K線數(shù)據(jù),該對(duì)象保存的是每一條線的相關(guān)參數(shù),供數(shù)據(jù)管理對(duì)象實(shí)例化具體的線數(shù)據(jù)類,并提供對(duì)應(yīng)的數(shù)據(jù)添加和更新方法。
4) 行情列表列對(duì)象類ListColumn:行情列表中每一列都有一個(gè)對(duì)應(yīng)的對(duì)象來存儲(chǔ)其相關(guān)的繪制屬性,其中包括列名稱、最小列寬度、列名稱對(duì)齊方式、數(shù)據(jù)對(duì)齊方式、數(shù)據(jù)比較類型、是否可見、數(shù)據(jù)項(xiàng)字體顏色、是否在數(shù)據(jù)更新時(shí)改變背景色以及數(shù)據(jù)是否根據(jù)比較值顯示漲跌符號(hào)等。
5) 行情列表繪制對(duì)象類ListClass:該類包含了所有行情列表的繪制方法及相關(guān)事件,是實(shí)際調(diào)用GDI接口及Graphics繪制對(duì)象繪制行情列表的類。
6) 分時(shí)走勢(shì)圖繪制對(duì)象類ChartClass:該類包含了所有走勢(shì)圖的繪制方法及相關(guān)事件,是實(shí)際調(diào)用GDI接口及Graphics繪制對(duì)象繪制走勢(shì)圖的類。
根據(jù)采集并處理過的數(shù)據(jù)信息分類,相應(yīng)的圖形的繪制包括行情列表的繪制和分時(shí)走勢(shì)圖的繪制[8-10]。
1) 基本功能
實(shí)現(xiàn)的功能主要是以列表的形式顯示每一個(gè)股票的基礎(chǔ)數(shù)據(jù),控件提供了統(tǒng)一的配置接口,通過addColumn方法即可在行情列表添加一個(gè)列,同時(shí)也提供了ShowColumn和HideColumn方法以便在運(yùn)行時(shí)動(dòng)態(tài)的隱藏或顯示某一列。圖2為A股的行情列表圖實(shí)例[12-15]。
圖2 行情列表圖Fig.2 Market list chart
2) 繪制算法
在行情列表中圖形的繪制包括:全局重新繪制、繪制行選擇線、繪制列調(diào)整線、列寬度調(diào)整、清空鼠標(biāo)操作繪制層以及更新數(shù)據(jù)時(shí)背景變化[4]。
3) 繪制過程
該繪制過程主要分為2步:初始化畫布及繪制數(shù)據(jù)。
初始化畫布時(shí),整個(gè)行情列表主要分為3個(gè)圖層:數(shù)據(jù)層、鼠標(biāo)操作標(biāo)識(shí)層以及操作標(biāo)志層。根據(jù)PictureBox容器大小初始化對(duì)應(yīng)的Graphics對(duì)象及Bitmap對(duì)象。隨后計(jì)算滾動(dòng)條寬度,并根據(jù)畫面高度和起始數(shù)據(jù)編號(hào)計(jì)算繪制的數(shù)據(jù)范圍。
繪制數(shù)據(jù)時(shí)首先繪制行情列表列對(duì)象,從dataManager對(duì)象取到所有的列,逐個(gè)繪制。如果該列被設(shè)置為隱藏則不繪制跳過。其次判斷如果該列在排序狀態(tài),則在列名稱前繪制出排序方式,用箭頭表示,整個(gè)一列都繪制藍(lán)色的背景色。其中繪制行選擇線的計(jì)算公式為
鼠標(biāo)選擇行index=鼠標(biāo)點(diǎn)擊Y坐標(biāo)/單位行高度-1+rowStartIndex
(1)
3.2.1 基本功能
分時(shí)走勢(shì)圖功能的實(shí)現(xiàn)主要是依賴控件聲明時(shí)對(duì)布局的定義。 在本設(shè)計(jì)的演示實(shí)例中, 分為2個(gè)畫面, 一個(gè)是分時(shí)走勢(shì), 另一個(gè)是K線技術(shù)指標(biāo)。 分時(shí)走勢(shì)畫面包含2個(gè)區(qū)域, 一個(gè)是實(shí)時(shí)走勢(shì), 另一個(gè)是對(duì)應(yīng)時(shí)刻的成交量。K線技術(shù)指標(biāo)也包含2個(gè)區(qū)域, 一個(gè)是K線數(shù)據(jù), 另一個(gè)是對(duì)應(yīng)的成交量。
3.2.2 繪制算法[16]
1) 坐標(biāo)軸的繪制:對(duì)于縱坐標(biāo)軸,系統(tǒng)定義了最小繪制行間隔。在繪制時(shí)首先根據(jù)控件尺寸高度計(jì)算出需要繪制的行數(shù),橫坐標(biāo)軸單位是固定的,隨著控件尺寸的變化決定的就是2個(gè)數(shù)據(jù)點(diǎn)的橫向間隔。
2) 數(shù)據(jù)值的繪制:數(shù)據(jù)值繪制的重點(diǎn)是需要計(jì)算出該數(shù)據(jù)值在區(qū)域繪制的坐標(biāo)中對(duì)應(yīng)的坐標(biāo)(X,Y)。其中橫坐標(biāo)的確定是由區(qū)間繪制的數(shù)據(jù)個(gè)數(shù)和繪制形態(tài)決定的,縱坐標(biāo)是由區(qū)域最高值和最低值的相對(duì)比例決定的。
假設(shè)一個(gè)區(qū)域的寬度為Width,共n個(gè)數(shù)據(jù),假設(shè)繪制的是第x個(gè)數(shù)據(jù)(1≤x≤n)的K線,橫坐標(biāo)區(qū)間為
[x×width/(n-1),x×width/n]
(2)
對(duì)于折線,其繪制橫坐標(biāo)為一個(gè)點(diǎn),橫坐標(biāo)點(diǎn)為
(x×width/(n-1))
(3)
縱坐標(biāo)的計(jì)算方式,假設(shè)繪制區(qū)域高度為Height,區(qū)域最大值為Max,最小值為Min,要繪制的數(shù)據(jù)Value的縱坐標(biāo)Y計(jì)算公式
(4)
3) 柱形線的繪制
圖3 K線圖的結(jié)構(gòu)Fig.3 Structure of K-line diagram
以K線為例,一個(gè)數(shù)據(jù)單元包含4個(gè)數(shù)據(jù):開盤價(jià)、收盤價(jià)、最高價(jià)和最低價(jià)。一個(gè)K線的結(jié)構(gòu)如圖3。
假設(shè)收盤價(jià)高于開盤價(jià),則3部分的縱坐標(biāo)分別是:上影線:(最高價(jià),收盤價(jià)),實(shí)體矩形:(收盤價(jià),開盤價(jià)),下影線:(開盤價(jià),最低價(jià))。如果收盤價(jià)低于開盤價(jià),則3部分的縱坐標(biāo)分別是:上影線:(最高價(jià),開盤價(jià)),實(shí)體矩形:(開盤價(jià),收盤價(jià)),下影線:(收盤價(jià),最低價(jià))。
橫坐標(biāo)由定義的寬度決定,假設(shè)繪制區(qū)間寬度是spacing,定義的矩形寬度占中間的70%,兩邊各15%的間隔。因此橫坐標(biāo)計(jì)算如下:上影線和下影線:spacing÷2,實(shí)體矩形:spacing×0.15。據(jù)此加上該數(shù)據(jù)由公式(3)得出的全局橫坐標(biāo)即可。如圖4,是商品“白云機(jī)場(chǎng)”的全局K線圖[6-8]。
圖4 全局K線圖Fig.4 Global K-line diagram
本文主要論述了一個(gè)分時(shí)走勢(shì)繪制控件的設(shè)計(jì)模型以及實(shí)現(xiàn)的算法和實(shí)現(xiàn)過程,實(shí)現(xiàn)的功能點(diǎn)主要參考了國(guó)內(nèi)外主流的各大A股交易公司推出的行情軟件。最終得到了一個(gè)能夠在.NET平臺(tái)上各種項(xiàng)目中快速嵌入的一個(gè)控件。該控件的接口設(shè)計(jì)合理,圖形繪制準(zhǔn)確,基本能滿足用戶讀取數(shù)據(jù)和指標(biāo)分析的要求。該代碼生成的最終動(dòng)態(tài)鏈接庫(kù)只有80 KB左右,十分適合開發(fā)者進(jìn)行二次開發(fā)。實(shí)現(xiàn)過程中,代碼架構(gòu)重構(gòu)了多次,目的是為了盡可能的提高該控件的性能和美觀度。由于GDI+本身的性能缺陷,在頻繁的重繪操作下仍然可能出現(xiàn)CPU占用高的情況。亮點(diǎn)和創(chuàng)新點(diǎn)是對(duì)控件的適應(yīng)能力,不論呈現(xiàn)設(shè)備尺寸大小如何,都能以準(zhǔn)確美觀的界面呈現(xiàn)用戶想要的數(shù)據(jù)。另外接口定義十分靈活,不論用戶的數(shù)據(jù)取自何處,都不會(huì)受控件接口的限制無(wú)法顯示。不論是何種指標(biāo)數(shù)據(jù),都可以用統(tǒng)一的接口調(diào)用傳入并繪制呈現(xiàn)。
沈陽(yáng)師范大學(xué)學(xué)報(bào)(自然科學(xué)版)2020年4期