2019年7月3日 星期三

群益API 更新至 2.13.17, Login 時錯誤訊息 "SK_WARNING_REGISTER_REPLYLIB_ONREPLYMESSAGE_FIRST"

群益API 更新至 2.13.17,這版本 Login 時會要求要先看過公告的訊息
否則會出現錯誤訊息 "SK_WARNING_REGISTER_REPLYLIB_ONREPLYMESSAGE_FIRST".

API文件寫說:

SKCenterLib初使化檢查是否接收SKReplyLib_OnReplyMessage公告訊息並回傳指定值VARIANT_TRUE,方可登入。

SKReplyLib_OnReplyMessage 文件又寫說,當 sConfirmCode 回傳 VARIANT_TRUE (0xFFFF),表示你看過公告了。官方沒附範例還真難理解要怎麼實做,一陣摸索後,寫了一個目前可以運作的版本。這更新真是擾民啊,可能要設計個介面讓人讀取公告後按確認,才能進行登入吧,我把它寫死了,固定回傳 0xFFFF ,也就是 VARIANT_TRUE



from comtypes.client import GetModule, CreateObject, GetEvents
GetModule(r'C:\SKCOM\CapitalAPI_2.13.17\x64\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
#建立COM物件
if 'skC' not in globals(): skC=CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
if 'skQ' not in globals(): skQ=CreateObject(sk.SKQuoteLib, interface=sk.ISKQuoteLib)
if 'skR' not in globals(): skR=CreateObject(sk.SKReplyLib, interface=sk.ISKReplyLib)
#Configuration
ID=''
PW=''
#建立事件類別
class skQ_events:
    def OnConnection(self, nKind, nCode):
        if nCode == 0 :
            if nKind == 3001 :  print("連線中, nkind= ", nKind)
            elif nKind == 3003: print("連線成功, nkind= ", nKind)
class skR_events:
    def OnReplyMessage(self, bstrUserID, bstrMessage, sConfirmCode=0xFFFF):
        #根據API 手冊,login 前會先檢查這個 callback, 
        #要返回 VARIANT_TRUE 給 server,  表示看過公告了,我預設返回值是 0xFFFF
        print('OnReplyMessage', bstrUserID, bstrMessage)
        return sConfirmCode       
#Event sink, 事件實體  
EventQ=skQ_events()
EventR=skR_events()
#make connection to event sink
ConnQ = GetEvents(skQ, EventQ)
ConnR = GetEvents(skR, EventR)
print("Login,", skC.SKCenterLib_GetReturnCodeMessage(skC.SKCenterLib_Login(ID, PW)))

2019年6月14日 星期五

GetFutureRight example

示範一下 GetFutureRight 最簡版本

import time, pythoncom, sys
import comtypes.client as cc
#import skcom package
import comtypes.gen.SKCOMLib as sk
#Create com objects
skC = cc.CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
skO = cc.CreateObject(sk.SKOrderLib,interface=sk.ISKOrderLib)
#Order event handlers
class skO_events:
    def __init__(self):
        #TXAccount
        self.TXAcc=''
    def OnFutureRights(self, bstrData):
        print(bstrData)        
    def OnAccount(self, LogInID, AccountData):
        if AccountData.split(',')[0]=='TF':
            self.TXAcc= AccountData.split(',')[1]+ AccountData.split(',')[3]
            print('TXAcc', ID, self.TXAcc)

#implant event instances
EventO=skO_events()
#connect event to com object
EventO_conn=cc.GetEvents(skO,EventO)

#輸入身分證與密碼
ID=''
PW=''

#Login
nCode=skC.SKCenterLib_Login(ID,PW)
print('Login', skC.SKCenterLib_GetReturnCodeMessage(nCode))
#初始 Order 物件
nCode=skO.SKOrderLib_Initialize()
print("Initialize ", skC.SKCenterLib_GetReturnCodeMessage(nCode))
#Get User TF Account
nCode=skO.GetUserAccount()
print("GetUserAccount ", skC.SKCenterLib_GetReturnCodeMessage(nCode))
#GetFutureRights, 不能呼叫太頻繁,不然會出現 SK_ERROR_QUERY_IN_PROCESSING
nCode=skO.GetFutureRights(ID, EventO.TXAcc ,1)
print("GetFutureRights ", skC.SKCenterLib_GetReturnCodeMessage(nCode))

#每秒推一次 event, 推5秒
for i in range(5):
    pythoncom.PumpWaitingMessages()
    time.sleep(1)
#exit
sys.exit(0)

2019年1月24日 星期四

matplotlib label 上/下標,設置方法

下標 (subscripts) 用底線 '_' ,上標(superscripts) 用 '^' 符號,前後用 '$' 包起來

例如這樣

#下標效果
plt.xlabel('RR$_{n}$ (ms)', fontsize=20)

#上標效果
plt.ylabel('RR$^{n+1}$ (ms)', fontsize=20)

結果


ref:
http://blog.sina.com.cn/s/blog_4a7b9abb0102x27h.html
其他特殊符號
https://matplotlib.org/users/mathtext.html

2019年1月20日 星期日

matplotlib 2.2.0 以上版本,finance 分離出來了

最近想要使用 matplotlib 的 finance 包,突然發現找不到了,原來是從 matplotlib 2.2.0以上版本,就被分離出來了,需要另外獨自安裝

cmd line 下

pip install mpl_finance

就可以安裝囉


ref: 畫 candlestick chart
https://openwritings.net/pg/python/python-draw-candlestick-chart-using-mplfinance-fetching-data-csv-file


2018年9月19日 星期三

測試 SKOrderLib 的 GetBalanceQuery, GetMarginPurchaseAmountLimit 功能

一點範例測試 GetBalanceQuery, GetMarginPurchaseAmountLimit 功能


from comtypes.client import GetModule, GetEvents, CreateObject
GetModule('C:\\SKCOM\\CapitalAPI_2.13.13\\x64\\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
skC = CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
skO = CreateObject(sk.SKOrderLib, interface=sk.ISKOrderLib)
    
#使用jupyter notebook magic function,這句可以讓 Event Pump 出來
%matplotlib auto

ID=''
PW=''

#建立事件類別
class skO_events:
    def __init__(self):
        #初始化,可以設定一些變數供使用
        self.Acc=''
        self.Balance=[]
    def OnBalanceQuery(self, bstrData):
        #將Balance 回傳資訊存在 event instance 的 Balance 屬性中
        self.Balance.append(bstrData)
        print('OnBalanceQuery', bstrData)
    def OnMarginPurchaseAmountLimit(self, bstrData):
        print('OnMargin', bstrData)
    def OnAccount(self, LogInID, AccountData):
        if AccountData.split(',')[0]=='TS':
            self.Acc=AccountData.split(',')[2] + AccountData.split(',')[3]
        print(LogInID, AccountData)

EventO=skO_events()
EventO_handler=GetEvents(skO, EventO)       

#Login
skC.SKCenterLib_Login(ID,PW)
#Order object initialize
skO.SKORderLib_Initialize()

skO.GetUserAccount()

skO.GetBalanceQuery(ID, EventO.Acc, '')
#查看 Balance
print(EventO.Balance)
skO.GetMarginPurchaseAmountLimit(ID, '', '')

2018年9月18日 星期二

python 接群益api callback / event 沒反應,常見問題

沒有順序之分,想到過去有哪些經驗就寫什麼


1. python 跟 API 的位元版本要一樣,python 是64 bit,API 就裝 x64,網友指出 64位元版好像問題比較多,可以試試 32位元版本

2. 缺少 event loop,  在 IDE 或 GUI 介面下一般都會自帶有 eventloop 功能,比較不用煩惱。  如果用 jupyter notebook 開發,可用 magic function:  %matplotlib auto, 也會幫你準備一個 eventloop。

如果在 terminal 下開發,需要用 pythoncom.PumpWaitingMessages() / PumpMessages() 之類的方法讓 callback出來。如:

    while Ture:
        pythoncom.PumpWaitingMessages()

或是直接用 pythoncom.PumpMessages() 等同上面的 while loop

最近發現,使用 juypter notebook 的  magic function '%matplotlob auto' 來推動 eventloop,可能要注意 '%matplotlob auto' 放置的位置,太早使用,可能 eventloop 沒有反應,可以嘗試調整 '%matplotlob auto' 出現的位置。

3. Event class 的定義有錯誤,像是  class 定義 def 的名稱都要參照 API 文件裡事件的名稱
例如: SKQuotelib 的事件

class skQ_events:
    def OnConnect(self, nKind, nCode):
        print('nKind, nCode=', nKind, nCode)
    def OnNotifyServerTime(self, sHour, sMinute, sSecond, nTotal):
        print(sHour, sMinute, sSecond)

記得  def  裡第一個參數是 self,這個一開始寫常忘記

4. 如果是更新API 後有問題,可以考慮清空 comtypes.gen下的資料
   請參考 https://easontseng.blogspot.com/2018/05/api-python-comtypes.html

我常用 OnNotifyServerTime 這個 callback 來看 eventloop 正不正常,連上群益報價主機後,每隔5秒主機會發送一個時間,可以藉此觀察 eventloop 有沒有問題。


以上是我的經驗,如果你有遇到其它情況,也歡迎在下面留言分享