群益api 版本: 2.13.6
python 版本: 2 or 3 64bit
用pythonnet, 一開始串SKCOM, 結果一直沒有成功, 想說要不要換 ironpython 試試
後來想說改串 Interop.SKCOMLib 沒想到卻成功了
目前遇到的問題是 Event Callback 時候沒辦法下中斷點,
另外在 Event 裡面再去呼叫 Com 的程式,好像會遇到不明的錯誤
所以全部改為使用 queue 在外部實作功能
特別一提的是 呼叫 SKQuoteLib_GetStockByIndex 輸入的的 STOCK 變數,輸出卻是不同一個(?)
所以我就在 SKCOMWapper 裡面也宣告了一個 STOCK, 每次都使用同一個就好了
在測試本程式的時候需要 更改 帳號/密碼, dll位置我是放在同一個目錄下的 dll/x64/
宣告 StockBot 時候,初始要查詢的 股票編號
switch.py 就不另外給了,網路上也是方便可以查詢的到原始碼
本身我 python 也是初學,目前先寫到可以登入、查詢股票
有些人問了 switch.py, 這裡有一個範例可以使用
https://github.com/soarpenguin/python-scripts/blob/master/switch.py
另外 pythonnet 使用群益的新版目前會遇到問題, 請參考網址, 改用 comtypes
http://easontseng.blogspot.tw/2017/08/api-in-python.html
python 版本: 2 or 3 64bit
用pythonnet, 一開始串SKCOM, 結果一直沒有成功, 想說要不要換 ironpython 試試
後來想說改串 Interop.SKCOMLib 沒想到卻成功了
目前遇到的問題是 Event Callback 時候沒辦法下中斷點,
另外在 Event 裡面再去呼叫 Com 的程式,好像會遇到不明的錯誤
所以全部改為使用 queue 在外部實作功能
特別一提的是 呼叫 SKQuoteLib_GetStockByIndex 輸入的的 STOCK 變數,輸出卻是不同一個(?)
所以我就在 SKCOMWapper 裡面也宣告了一個 STOCK, 每次都使用同一個就好了
在測試本程式的時候需要 更改 帳號/密碼, dll位置我是放在同一個目錄下的 dll/x64/
宣告 StockBot 時候,初始要查詢的 股票編號
switch.py 就不另外給了,網路上也是方便可以查詢的到原始碼
本身我 python 也是初學,目前先寫到可以登入、查詢股票
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
# -*- coding: utf-8 -*- | |
import sys, os, clr, time | |
is_py2 = sys.version[0] == '2' | |
if is_py2: | |
import Queue as queue | |
else: | |
import queue as queue | |
from switch import * | |
import logging | |
logging.basicConfig(level=logging.DEBUG) | |
q = queue.Queue () | |
class Job: | |
GetTimer = 0 | |
Quote_EnterMonitor = 1 | |
GetStockByIndex = 2 | |
GetStockByIndexResult = 3 | |
OnNotifyQuote = 4 | |
def __init__ (self, do_type): | |
self.do_type = do_type | |
class SKCenterLibEvent: | |
def __init__(self, parent, bot): | |
self.parent = parent | |
self.bot = bot | |
def Bind(self, obj): | |
obj.OnTimer += self.OnTimer | |
def OnTimer(self, nTime): | |
j = Job (Job.GetTimer) | |
j.Time = str(nTime) | |
q.put (j) | |
print ("OnTimer: " + str(nTime)) | |
def OnShowAgreement(self, bstrData): | |
print ("OnShowAgreement: " + str(bstrData)) | |
class SKReplyLibEvent: | |
def __init__(self): | |
self.parent = None | |
self.bot = None | |
def OnConnect(bstrUserID, nErrorCode ): | |
print ("OnConnect: user:" + bstrUserID + " error:" + str(nErrorCode)) | |
class SKQuoteLibEvent: | |
def __init__(self, parent, bot): | |
self.parent = parent | |
self.bot = bot | |
def Bind(self, obj): | |
obj.OnConnection += self.OnConnection | |
obj.OnNotifyQuote += self.OnNotifyQuote | |
def OnConnection(self, nKind, nCode): | |
print ("OnConnection: kind:" + str(nKind) + " error:" + str(nCode)) | |
self.bot.SKQuoteLibOnOnConnection (nKind, nCode) | |
def OnNotifyQuote(self, sMarketNo, sIndex): | |
j = Job (Job.GetStockByIndexResult) | |
j.sMarketNo = sMarketNo | |
j.sIndex = sIndex | |
q.put (j) | |
class SKCOMWapper: | |
def __init__(self, uid, bot): | |
self.uid = uid | |
self.bot = bot | |
sys.path.append(os.path.join(os.getcwd(), "dll", "x64")) | |
clr.AddReference("Interop.SKCOMLib") | |
import SKCOMLib as SKCOMLib | |
self.Template = SKCOMLib | |
self.SKCenterLib = SKCOMLib.SKCenterLib () | |
self.SKCenterLibEvent = SKCenterLibEvent(self, bot) | |
self.SKCenterLibEvent.Bind (self.SKCenterLib) | |
self.SKReplyLib = SKCOMLib.SKReplyLib () | |
#國內報價物件。 | |
self.SKQuoteLib = SKCOMLib.SKQuoteLib () | |
self.SKQuoteLibEvent = SKQuoteLibEvent(self, bot) | |
self.SKQuoteLibEvent.Bind (self.SKQuoteLib) | |
self.SKSTOCK = SKCOMLib.SKSTOCK () | |
class StockBot: | |
def __init__(self, stockno): | |
self.SKCOM = SKCOMWapper (0, self) | |
self.Stock = {} | |
self.StockNo = stockno | |
def DoLogin (self, account, pwd): | |
ret = self.SKCOM.SKCenterLib.SKCenterLib_Login (account, pwd) | |
print ("CeterLib Login: " + str (ret)) | |
q.put (Job (Job.Quote_EnterMonitor)) | |
def SKQuoteLibOnOnConnection (self, nKind, nCode): | |
if nKind == 3003 and nCode == 0: | |
q.put (Job (Job.GetStockByIndex)) | |
def DoOnNotifyQuote (self, sMarketNo, sIndex): | |
ret, Stock = self.SKCOM.SKQuoteLib.SKQuoteLib_GetStockByIndex(sMarketNo, sIndex, self.SKCOM.SKSTOCK) | |
j = Job(Job.OnNotifyQuote) | |
j.Stock = Stock | |
q.put (j) | |
def DoGetStockByIndex (self): | |
self.SKCOM.SKQuoteLib.SKQuoteLib_RequestStocks (-1, self.StockNo) | |
def DoEnterMonitor (self): | |
ret = self.SKCOM.SKQuoteLib.SKQuoteLib_EnterMonitor () | |
def DoJob(Bot, x): | |
for case in switch(x.do_type): | |
print ("DoJob: " + str (x.do_type)) | |
if case(Job.GetTimer): | |
print ("GetTimer: " + x.Time) | |
break | |
if case(Job.Quote_EnterMonitor): | |
Bot.DoEnterMonitor () | |
break | |
if case(Job.GetStockByIndex): | |
Bot.DoGetStockByIndex () | |
break | |
if case(Job.GetStockByIndexResult): | |
Bot.DoOnNotifyQuote (x.sMarketNo, x.sIndex) | |
break | |
if case(Job.OnNotifyQuote): | |
print ("OnNotifyQuote: " + x.Stock.bstrStockName + " Close: " + str (x.Stock.nClose)) | |
Bot.Stock[x.Stock.bstrStockNo] = x.Stock | |
break; | |
if __name__ == "__main__": | |
Bot = StockBot("TSEA") | |
Bot.DoLogin('帳號', '密碼') | |
while 1: | |
while not q.empty(): | |
next_job = q.get() | |
DoJob (Bot, next_job) | |
time.sleep(1) | |
https://github.com/soarpenguin/python-scripts/blob/master/switch.py
另外 pythonnet 使用群益的新版目前會遇到問題, 請參考網址, 改用 comtypes
http://easontseng.blogspot.tw/2017/08/api-in-python.html
17 則留言:
山豆兒你好
對於用python串接群益API有興趣了解
剛好最近也在學習如何使用python做程式交易
可否跟你請教呢?
方便用email交流嗎?
我的epson0209@gmail.com
謝謝
你好,我對程式交易 可能連一知半解還不到
但還是歡迎交流,可以寄信到這個信箱
把 _ 換 成 @ 就行了
xblueman_gmail.com
謝謝
您好....山豆兒....我一直在找人教我群益api. 的連結......可以請教您們嗎....
不過我很笨......
我的目的...用群益api回補tick .1分.5分資料.....
可以聊嗎?
yuntsan0323@gmail.com
我叫eric
謝謝.
您好,我使用上面的範例來取得報價,
在win 10上測試,
經過數分或是十數分鐘後,
報價就會停止,
請問可能是哪邊的問題呢?
你好
我使用目前的程式,報價並沒有停止的問題(我的環境是win7)
不過有想到一個問題,
依群益的使用watch的回報方式,是要報價內容有變動,
才會通知更新,所以會不會是這期間沒有資料變動,
所以就不會更新了,建議
Bot = StockBot("6111")
可以改為
Bot = StockBot("TSEA")
使用台灣加權指數來測試報價會不會中斷
以上
您好
我是使用TX_05來測試
資料應該是很常變動
因為我是在公司測試
若您測試沒有停止問題的話
那我猜測也許是公司網路不穩定的關係?
若是網路不穩的話
是否有建議的方法來偵測?
再次感謝
你好
我有更新一下程式
onTimer 是會定時回報 伺服器上目前的時間
你可以試試看會不會卡住
這個應該也是從群益的伺服器回傳的
但如果卡住是不是網路有問題其實也很難確定
建議你可能還是要換個環境
測試一下是平台的問題還是網路的問題
您好
我今天測試的結果
如果只用一檔2330的話
目前測了一個半小時都正常
但是我將
Bot = StockBot("2330")
改成一次要多檔資料(目前要30檔)
跑沒幾分鐘就會卡住
我有將所有queue.put和get都加上false讓它不要被block
也有在while裡面放try except看有沒有辦法抓到exception
但它就是卡住了什麼訊息都沒有
你好
不知道你是否方便將你修改後的程式碼給我測試
我目前是已經沒有使用 pythonnet 而是改用 comtypes
您好
目前最新的狀況如下
我把 Bot裡,case(Job.OnNotifyQuote) 裡面的 job
往前拉到 SKQuoteLibEvent 裡的 OnNotifyQuote() 做
就是從OnNotifyQuote之後的所有動作都不要進 queue
目前在兩個環境各測試不同的情境
一個是只抓TX05
一個是抓40檔的個股
目前測了15分鐘都還沒卡住
看起來朝這方向解應該是正確的
在此跟您分享一下我目前的狀況
也再次感謝您這篇的分享
謝謝您
您好
改成這樣的做法之後
剛剛跑到收盤都沒過問題
跟您報告一下
你好,
謝謝你的分享~
您好,
請問一下您有使用過 SKOrderLib.SendFutureOrder 來下單嗎?
因為我試了好久無法成功。
我從您的範例去改,
先宣告一個:
class FUTUREORDER(Structure):
_fields_ = [("bstrFullAccount", c_char_p),
("bstrStockNo" , c_char_p),
("sTradeType", c_int),
("sBuySell", c_int),
("sDayTrade", c_int),
("sNewClose", c_int),
("bstrPrice", c_char_p),
("nQty", c_int),
("bstrTrigger", c_char_p),
("bstrMovingPoint", c_char_p),
("sReserved", c_int),
("bstrDealPrice", c_char_p)
]
然後試著呼叫
def DoSendFutureOrder(self, data_dict):
FUTUREORDER.bstrFullAccount = ""
FUTUREORDER.bstrStockNo= "TX06"
FUTUREORDER.sTradeType=0
FUTUREORDER.sBuySell=0
FUTUREORDER.sDayTrade=0
FUTUREORDER.sNewClose=0
FUTUREORDER.bstrPrice="10000"
FUTUREORDER.nQty=1
strMessage = ""
self.SKCOM.SKOrderLib.SendFutureOrder("", 1, FUTUREORDER, strMessage);
會出現 No method matches given arguments
補充一下,
我已成功的初始化以下兩個function
SKCenterLib_Login: 0
SKOrderLib_Initialize: 0
您好,
因為一直試不出來
我剛剛改用下面這個連結的範例
就可以成功送出了
https://easontseng.blogspot.tw/2017/07/api-in-pyhton.html
跟您報告一下以免您花費時間測試
謝謝您的分享
你好
使用 pythonnet 由於是使用 Interop.SKCOMLib.dll 來呼叫 COM 元件
但是群益已經很久沒有更新這個DLL了,所以有些函式可能格式不符或是新增卻不能呼叫
之前有網友有說可以自已產出來
不過我後來改用 comtypes 也是使用 eason 大大的方式,
就沒再使用 pythonnet 了
目前 comtypes 都可以正常使用
您好!
有一個問題想請教一下,最近參考https://easontseng.blogspot.com/2017/07/api-in-pyhton.html
的方法來抓歷史報價。
但是只要建立class skQ_events:
運行後就會出現Error in sys.excepthook: Original exception was:
想請問一下有可能是哪方面出問題?
謝謝!
張貼留言