群益API行情串接(三)

像股票這樣的金融商品百百種,加上市場的變化性與多樣的市場規則,使得這類的分析總是相當困難。但相關數據取得與蒐集的管道也相當稀少,甚至難以整合與上手。國內幾家券商提供之API服務便顯得相當地重要。

Jerome Lin
Coding Learning Sharing
8 min readFeb 6, 2021

--

前言

金融有趣的地方就是似乎每一刻過後,我們所認知事物以及對其的感覺就不太一樣了。當然,這些都是在我們去親自去感受它的時候,比較可能會體會到的。我們面對的都是未知的未來。

隨著時代的演進,金融在取得數據這塊,有越來越多且更加完善的API服務。並且也因應交易制度的改變與開放,API也會進一步開通新的功能。

話說回來,這個系列,我們將環境設定相關變數與模組登入功能做了介紹,而上一篇也提到了事件的註冊如何接收事件回傳回來的訊息以及相關的報價操作

本次要來提一下,當日歷史回補資料的獲取,並提及一些要注意的事項。

程式環境

程式語言: Python 3.6.8

作業系統: Windows 10 64位元

API版本: 2.13.16 x86版本

觀察

先前提到,群益API功能相對完整,但也複雜。相關功能的使用與數據的產生,也要與台灣集中市場的交易制度相對應。因此,如果我們希望獲取某一檔股票的當日Tick回補資料,必須去檢查在API中,是不是只需要註冊一個事件就能實現,否則若缺少註冊某些必要事件,我們很可能會缺損一部份資料。

為了試驗事件的功能,除了查看官方說明文件之外,就是去看範例程式碼。

但這也有點...就是說麻煩,我們其實還可以直接運行它的範例,觀察看看有沒有出現甚麼提示訊息。

如下圖所示:

我們可以發現,在Tick的子頁面中,輸入某一檔商品代碼,並進行完整的查詢後,其回傳的訊息開頭會有提示是觸發哪個事件而回傳的訊息。

基本上,就實際的觀察結果,13點30分(這邊推測是一般交易的最後一筆,如下圖所示)的盤後集合競價成交明細是由OnNotifyTicks事件所回傳。同理,14點30分的盤後定價交易成交明細也是。

所以如果我們希望獲取的成交明細是一個相較完整的成交內容,我們需要將OnNotifyTicksOnNotifyHistoryTicks兩個事件做一個實現。

這邊眼尖的朋友可以注意到,這張圖其實是在盤中全面逐筆交易開放前截圖的,但這並不影響我們的做法。

實現當日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換版的文章。

--

--

Jerome Lin
Coding Learning Sharing

覺得平凡就好,但還是多少充實一下人生。It feels good to be ordinary, but you still need to enrich your life a little bit. Buy Me A Coffee: https://www.buymeacoffee.com/jeromelinil