像股票這樣的金融商品百百種,加上市場的變化性與多樣的市場規則,使得這類的分析總是相當困難。但相關數據取得與蒐集的管道也相當稀少,甚至難以整合與上手。國內幾家券商提供之API服務便顯得相當地重要。
前言
金融有趣的地方就是似乎每一刻過後,我們所認知事物以及對其的感覺就不太一樣了。當然,這些都是在我們去親自去感受它的時候,比較可能會體會到的。我們面對的都是未知的未來。
隨著時代的演進,金融在取得數據這塊,有越來越多且更加完善的API服務。並且也因應交易制度的改變與開放,API也會進一步開通新的功能。
話說回來,這個系列,我們將環境設定、相關變數與模組到登入功能做了介紹,而上一篇也提到了事件的註冊、如何接收事件回傳回來的訊息以及相關的報價操作。
本次要來提一下,當日歷史回補資料的獲取,並提及一些要注意的事項。
程式環境
程式語言: Python 3.6.8
作業系統: Windows 10 64位元
API版本: 2.13.16 x86版本
觀察
先前提到,群益API功能相對完整,但也複雜。相關功能的使用與數據的產生,也要與台灣集中市場的交易制度相對應。因此,如果我們希望獲取某一檔股票的當日Tick回補資料,必須去檢查在API中,是不是只需要註冊一個事件就能實現,否則若缺少註冊某些必要事件,我們很可能會缺損一部份資料。
為了試驗事件的功能,除了查看官方說明文件之外,就是去看範例程式碼。
但這也有點...就是說麻煩,我們其實還可以直接運行它的範例,觀察看看有沒有出現甚麼提示訊息。
如下圖所示:
我們可以發現,在Tick的子頁面中,輸入某一檔商品代碼,並進行完整的查詢後,其回傳的訊息開頭會有提示是觸發哪個事件而回傳的訊息。
基本上,就實際的觀察結果,13點30分(這邊推測是一般交易的最後一筆,如下圖所示)的盤後集合競價成交明細是由OnNotifyTicks事件所回傳。同理,14點30分的盤後定價交易成交明細也是。
所以如果我們希望獲取的成交明細是一個相較完整的成交內容,我們需要將OnNotifyTicks、OnNotifyHistoryTicks兩個事件做一個實現。
這邊眼尖的朋友可以注意到,這張圖其實是在盤中全面逐筆交易開放前截圖的,但這並不影響我們的做法。
實現當日Tick回補功能
首先在先前所定義的SKQuoteLibEvents Class中,宣告一個OnNotifyHistoryTicks()函式,在一般觸發事件的情況下,資料回傳的功能是正常的,所以我們將<self.__is_data_get>設置為True。接著,就不需要做過多的處理,只要單純把接收到的資料進行儲存就行,這邊是存在原先宣告好的字典中。並且,<self.__is_ready>也設置為True,代表資料的回傳與接收是完畢的。(這邊是比較特殊的地方,在回傳某檔商品的當日歷史Tick,當事件觸發時,由於訊息的取出是透過pywin32套件裡pythoncom模組包含的PumpWaitingMessages()函式,因此,會在訊息傳遞完畢之前都會持續讀取,在讀取結束後才會結束這次PumpWaitingMessages()函式的運行)。我們要注意到,而<self.__is_ready>正是我們用來決定是否跳出While迴圈的依據(回顧先前我們所定義的run_callback_sync()函式)。
class SKQuoteLibEvents:
...
def OnNotifyHistoryTicks(self, sMarketNo: int, sStockIdx: int, nPtr: int, lDate: int, lTimehms: int, lTimemillismicros: int, nBid: int, nAsk: int, nClose: int, nQty: int, nSimulate: int):
self.__is_ready = True
self.__is_data_get = True
if self.__Stock_id not in self.__Stock_dict:
self.__Stock_dict[self.__Stock_id] = []
self.__Stock_dict[self.__Stock_id].append(" ".join(['[OnNotifyHistoryTicks]', str(nPtr), str(lDate), str(lTimehms), str(lTimemillismicros),str(nBid), str(nAsk), str(nClose), str(nQty), str(nSimulate)]))
理所當然,OnNotifyTicks事件的部分,大致上的作法也會是類似的。
class SKQuoteLibEvents:
...
def OnNotifyTicks(self, sMarketNo: int, sStockIdx: int, nPtr: int, lDate: int, lTimehms: int, lTimemillismicros: int, nBid: int, nAsk: int, nClose: int, nQty: int, nSimulate: int):
self.__is_ready = True
self.__is_data_get = True
if self.__Stock_id not in self.__Stock_dict:
self.__Stock_dict[self.__Stock_id] = []
self.__Stock_dict[self.__Stock_id].append(
" ".join(['[OnNotifyTicks]', str(nPtr), str(lDate), str(lTimehms), str(lTimemillismicros), str(nBid), str(nAsk), str(nClose), str(nQty), str(nSimulate)]))
實際呼叫的程式碼如下:
if __name__ == '__main__':
...
for index in market_number_dict.keys():
for row in SKQuoteEvent.get_Stock_list_dict(index):
print(row)
for item in row[1:]:
...
SKQuoteEvent.set_Stock_id(stock_info[0])
skQ.SKQuoteLib_RequestTicks(page_index, stock_info[0])
run_callback_sync(SKQuoteEvent)
print("RequestTicks: {}\t{}\t{}".format(stock_info[0], market_number_dict[index], page_index))
if page_size_index >= 80:
page_size_index = 0
page_index += 1
else:
page_size_index += 1
由於我們是把用來儲存資料用的字典(<self.__Stock_dict>),綁定一個商品編號(<self.__Stock_id>),所以每次訂閱成交明細時,需要重新設置一次<self.__Stock_id>,這個部分,根據不同需求,可以另外修改。
實際結果圖如下:
這邊是另外加上輸出訊息,如果確認沒問題,其實就可以把輸出拿掉了。
到這邊,我們成功接收並儲存當日歷史Tick回補的資料,要另外儲存為檔案的部分就不另外提了,一般是直接存為txt文字檔或csv逗點分隔檔就行,之後要用來載入也比較輕便、好處理。
結論
本篇將當日Tick回補的功能做一個段落,並提及了一些注意事項,在足夠了解API各函式或事件的運作之前,我們都得先做一番確認,避免整理過後的資料有缺失。
追加事項
由於群益官網已明確公告在2021年4月1日會終止V2.13.27之前的版本服務,所以基本上這個系列也會繼續往下追加API換版的文章。
沒有留言:
張貼留言