群益api更新至2.13.8後,改一下順序,先呼叫 SKReplyLib_ConnectByID,再 EnterMonitor,才會可以收到 OnConnection 3003 的回報,然後就可以求報價了。本範例示範如何用python 接群益api的報價,希望能拋磚引玉, 讓更多能手參與。小弟python自學,COM 元件的運作也是一知半解,東拼西湊下還算可用,程式碼很醜請見諒。過程遇到一些錯誤,很多我無法解決,以下是我試誤各種組合後, 可以運作的一組方法,,若有更好的解法,請各位大大多加分享。
另外是事件處理,我用comtypes 中的 showevents 也有錯誤產生,於是用 pyhoncom.PumpWaitingMessages() 來代替
使用comtpyes 若出現
"comtypes com object's method returns: 'tuple' object has no attribute 'ctypes_from_outparam'",需要做一些修正 ,請參考
https://easontseng.blogspot.com/2017/07/install-pythoncom-tuple-object-has-no.html
#這個bug好像在最新版的comtypes中被修正了
弄個FB社團,大家來討論好了。
https://www.facebook.com/groups/1805224676441902/
運行環境:
winXP, Anaconda python3.4 32 bit, CapitalAPI 2.13.8, pywin32 build221, comtypes 1.1.3
參考文獻:
#pythoncom 是安裝 pywin32 附帶的
https://sourceforge.net/projects/pywin32/
#用pywin makepy utility 找 GUID
https://easontseng.blogspot.tw/2017/07/pywin32-com-makpy-utiltiy-api-com.html
#python 元大期貨 api,
http://hlfutures.blogspot.tw/2016/08/api-in-python_8.html
#comtpyes:
https://pythonhosted.org/comtypes/
http://starship.python.net/crew/theller/comtypes/
https://easontseng.blogspot.tw/2017_07_07_archive.html
###########################################################
# pythoncom 是安裝 pywin32 附的,如果 event 沒反應才需要用到
# 第一次使用cc.GetModule, 會在 comtypes\gen\ 下產生幾個.py檔,像是
# _75AAD71C_8F4F_4F1F_9AEE_3D41A8C9BA5E_0_1_0.py
# 如果有 dll 錯誤產生,請檢查 SKCOM.dll 路徑有沒有錯誤
# 如果發生 gen 下沒有 SKCOMLib 錯誤訊息,請將python關閉
# AttributeError: module 'comtypes.gen.SKCOMLib' has no attribute 'SKCenterLib'
# 重新啟動python後,應該就可以找到了
# 如果還是不行,請重新安裝 capital API 元件,注意 API 與python 版本要一致,
# API安裝要以管理員權限執行
# 20190506,程式碼簡化
import pythoncom, time
import comtypes.client as cc
cc.GetModule('C:\\SKCOM\\x86\\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
ts=sk.SKSTOCK()
skC=cc.CreateObject(sk.SKCenterLib,interface=sk.ISKCenterLib)
skQ=cc.CreateObject(sk.SKQuoteLib,interface=sk.ISKQuoteLib)
#Some Configure
ID='身分證'
PW='密碼'
#想取得報價的股票代碼
strStocks='TSEA'
#define functions
def getStock(nMarket, nIndex, ts):
skQ.SKQuoteLib_GetStockByIndex(nMarket, nIndex, ts)
print(ts.bstrStockName, ts.bstrStockNo, ts.nClose/10**ts.sDecimal)
#建立事件類別
class skQ_events:
def OnConnection(self, nKind, nCode):
if nCode == 0 :
if nKind == 3001 :
print("skQ OnConnection, nkind= ", nKind)
elif (nKind == 3003):
#等到回報3003 確定連線報價伺服器成功後,才登陸要報價的股票
skQ.SKQuoteLib_RequestStocks(1, strStocks)
print("skQ OnConnection, request stocks, nkind= ", nKind)
def OnNotifyQuote(self, sMarketNo, sStockIdx):
getStock(sMarketNo, sStockIdx, ts)
#Event sink
EventQ=skQ_events()
#make connection to event sink
ConnectionQ = cc.GetEvents(skQ, EventQ)
#Login
print("Login,", skC.SKCenterLib_GetReturnCodeMessage(skC.SKCenterLib_Login(ID,PW)))
time.sleep(1)
#登錄報價伺服器
print("EnterMonitor,", skC.SKCenterLib_GetReturnCodeMessage(skQ.SKQuoteLib_EnterMonitor()))
#每秒 pump event 一次,這裡示範15秒
for i in range(15):
time.sleep(1)
pythoncom.PumpWaitingMessages()