多年前曾用想要用pythonnet,來載入群益的api ,但最後失敗了。這篇純粹是出自個人好奇,還是想了解是否能用 pythonnet 來載入 dll,最近找到可以使用的步驟了,在windows下 python 可以呼叫群益api,讓熟悉 C# 的開發者,又想用 python 的人多一種選擇。
目前使用這個方法的好處:
- 在 juypterlab 下,可以顯示各個 function 參數有哪些,減少一直翻手冊的時間。
- callback 部屬比較直覺快速,但也因此比較冗長。
- 熟悉 C# 的人,可以加入 C# 相關的 reference, namespace 當作 python 的模組來使用。
- 其他券商的 dll 檔,也有機會用這套方法來呼叫?
壞處:
- 目前遇到狀況是 callback 出現錯誤時,python沒有任何錯誤通知,除錯比較麻煩。
我的安裝環境:
- windows 10,
- 我使用的是python 3.10.5
- visual studio 2022 (只是為了使用它的 tlbimp.exe)
前置工作
1. 用 tlbimp.exe 將 SKCOM.dll 轉成 Type library
要先將群益的SKCOM.dll 轉成 Type library,我有安裝 visual studio 2022,利用它附帶的 comandline prompt terminal ,下指令 tlbimp.exe 將 SKCOM.dll 轉成 typelib 形式,最終產生 SKCOMLib.dll 的檔案。之後就可以輕鬆用 pythonnet 的 clr 模組取用。
2. 安裝 pythonnet
Python.NET 模組可以讓 python 使用者無縫整合 .NET Common Language
Runtime (CLR)。它讓 Python 可以跟 CLR 互動, 甚至也可以反過來將 Python 包進
.NET 裡.
在你的 python 環境下用 pip 安裝 pythonnet 即可。詳細操作請看
pythonnet 官網
pip install pythonnet
使用 pythonnet 的 clr 模組呼叫 SKCOMAPI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 使用 pythonnet 呼叫群益api | |
import clr | |
# AddReference,不用加副檔名 .dll | |
clr.AddReference(r"C:\skcom\CapitalAPI_2.13.41\x64\SKCOMLib") # 使用絕對路徑我個人偏好這個 | |
# 加入參考後,利用 improt SKCOMLib 可以使用群益整個 skcomapi 的功能, | |
import SKCOMLib | |
# 也可以 from SKCOMlib import 部分功能 | |
from SKCOMLib import SKCenterLib, SKReplyLib, SKQuoteLib, SKSTOCKLONG | |
# 推動eventloop用 | |
import time | |
import pythoncom | |
# 使用 skcom 元件 | |
skC = SKCenterLib() | |
skR = SKReplyLib() | |
skQ = SKQuoteLib() | |
##################################################### | |
# Configuration | |
ID = "" | |
PW = "" | |
# 欲報價的商品代號 | |
StockNo = "1101,2330" | |
# working function | |
# resqest stock | |
def request_stock(page, stocks): | |
ncode, _ = skQ.SKQuoteLib_RequestStocks(page, stocks) | |
print(f"Request stock: {stocks}", skC.SKCenterLib_GetReturnCodeMessage(ncode)) | |
##################################################### | |
# Event callback | |
# SKReplyLib 相關 callback | |
def OnReplyMessage(bstrUserID , bstrMessage, sConfirmCode): | |
# 這個一定要,Login 時會檢查 sConfirmCode 是否 == -1 | |
sConfirmCode = -1 | |
print("OnReplyMessage", bstrMessage) | |
return sConfirmCode | |
# SKQuoteLib 相關 | |
def OnConnection(nKind, nCode): | |
"""回報連線報價伺服器狀態 | |
nKind: 3001 連線報價伺服器 | |
3002 離線報價伺服器 | |
3003 連線成功,收到3003後,始可登錄報價商品 | |
""" | |
print(f'skQ_OnConnection nKind= {nKind}', skC.SKCenterLib_GetReturnCodeMessage(nKind)) | |
if nKind == 3003: | |
request_stock(1, StockNo) | |
def OnNotifyQuoteLONG(sMarketNo, nIndex): | |
"""報價""" | |
ts = SKSTOCKLONG() | |
ncode, ts = skQ.SKQuoteLib_GetStockByIndexLONG(sMarketNo, nIndex, ts) | |
print(ts.bstrStockName, "市價", ts.nClose/ 10**ts.sDecimal, "單量", ts.nTickQty) | |
##################################################### | |
# 綁定 event callback,需一個一個綁定,如果有比較快的方法請跟我分享 :) | |
# 請查閱SKCOMapi手冊有哪些 Callback,及相關參數 | |
skR.OnReplyMessage += OnReplyMessage | |
skQ.OnConnection += OnConnection | |
skQ.OnNotifyQuoteLONG += OnNotifyQuoteLONG | |
print("綁定各元件的event callback") | |
#################################################### | |
# Login | |
ncode = skC.SKCenterLib_Login(ID, PW) | |
print("Login", skC.SKCenterLib_GetReturnCodeMessage(ncode)) | |
# EnterMonitor | |
ncode = skQ.SKQuoteLib_LeaveMonitor() | |
ncode = skQ.SKQuoteLib_EnterMonitorLONG() | |
print("EnterMonitor", skC.SKCenterLib_GetReturnCodeMessage(ncode)) | |
# pump events for 30 seconds | |
print("Pumping events for 30s") | |
for i in range(30): | |
pythoncom.PumpWaitingMessages() | |
time.sleep(1) |