2017年8月2日 星期三

群益api in python 取得歷史kline報價

今天來用群益API取得歷史報價,群益API可以取得從上市櫃開始到今日的所有日K歷史報價,有了歷史報價就可以做很多樣回測。一分K歷史報價目前可以取得約 60000 根的資料,且幾秒鐘內就可以取回來,相當便利喔!

到目前2021年,kline 改變了不少,目前定位為 "歷史kline",只能取得當日以前的kline,若要取得當日kline,需要自己收集 tick 資料,自己組成 kline
可以參考:
  1. 群益api 使用python 取得 tick 報價
  2. tick data 轉換成 k Bar

################SKCOMAPI 2.13.17 以上版本適用##################
# 本範例要用 jupyter 來跑, 如果要在console 下跑,要加pythoncom來處理eventloop
# Eventloop 參考這幾篇的用法,或是像群益官方範例建立GUI方式產生

# skcomapi 2.13.23 以上適用
from comtypes.client import GetModule, CreateObject, GetEvents
# 將sckcom轉成python package
# GetModule 只要執行一次就好,除非有更新API,再參考官網範例,清除comtypes.gen 
# 下的檔案,再重新呼叫 GetModule 包裝
GetModule('C:\\skcom\\CapitalAPI_2.13.23\\x64\\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
import pythoncom
#config #ID and Password ID = "" PW = "" #request stock stockName='TSEA' #建立物件,避免重複 createObject #登錄物件 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) #建立事件類別 class skR_events: def OnReplyMessage(self, bstrUserID, bstrMessage, sConfirmCode=0xFFFF): print('OnReplyMessage', bstrMessage) return sConfirmCode class skQ_events: def __init__(self): self.KlineData = [] def OnConnection(self, nKind, nCode): if nKind == 3003: print("skQ連線成功, nkind= ", nKind) nCode=skQ.SKQuoteLib_RequestKLine(stockName, sKLineType=4, sOutType=1) else: print('please check, nCode, nKind=', nCode, nKind) def OnNotifyKLineData(self, bstrStockNo, bstrData): self.KlineData.append([bstrStockNo] + bstrData.split(',')) #Event sink, 事件實體 EventR=skR_events() EventQ=skQ_events() #make connection to event sink ConnR = GetEvents(skR, EventR) ConnQ = GetEvents(skQ, EventQ) print('load module and event handler') #########在新 cell 執行 ############ # magic function to get event loop, 只有jupyter 可以用,
# console 介面要用 pythoncom.PumpWaitingMessages(1)
%matplotlib auto
 
#登入,連線報價主機
nCode=skC.SKCenterLib_Login(ID, PW)
print("Login,", skC.SKCenterLib_GetReturnCodeMessage(nCode))
 
#Enter quote server
nCode=skQ.SKQuoteLib_EnterMonitor()
print('SKQuoteLib_EnterMonitor()', skC.SKCenterLib_GetReturnCodeMessage(nCode))


######以下為 2.13.17以下版本 年久失修僅供參考#################################
#群益api in python 取得歷史報價
import pythoncom, time, os
import comtypes.client as cc
cc.GetModule(r'C:\SKCOM\x86\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
#建立COM物件
skC=cc.CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
skQ=cc.CreateObject(sk.SKQuoteLib, interface=sk.ISKQuoteLib)

#Some Configuration
ID='身分證'
PW='密碼'

#顯示 event 事件, t 秒內,每隔一秒,檢查有沒有 event 發生
def pumpwait(t=1):
    for i in range(t):
        time.sleep(1)
        pythoncom.PumpWaitingMessages()

#建立事件類別
class skQ_events:
    def __init__(self):
        self.KlineData=[]
    def OnConnection(self, nKind, nCode):
        if nCode == 0 :
            if nKind == 3001 :
                print("連線中, nkind= ", nKind)
            elif nKind == 3003:
                print("連線成功, nkind= ", nKind)
    def OnNotifyKLineData(self, bstrStockNo, bstrData):
        self.KlineData.append(bstrData.split(','))
                    
#Event sink, 事件實體  
EventQ=skQ_events()
#make connection to event sink
ConnectionQ = cc.GetEvents(skQ, EventQ)        

#登入,連線報價主機
nCode=skC.SKCenterLib_Login(ID, PW)
print("Login,", skC.SKCenterLib_GetReturnCodeMessage(nCode))
nCode=skQ.SKQuoteLib_EnterMonitor()
print("EnterMonitor,", skC.SKCenterLib_GetReturnCodeMessage(nCode))

#讀取加權日k歷史報價
#bstrStockNo 放股票代碼
#sKLineType,0 = 1分鐘線, 3 =日線288天, 4 =完整日線, 5 =週線, 6 =月線。
#sOutType, 0=舊版輸出格式, 1=新版輸出格式。新版格式一分日期與分時資料是各自一個欄位
#將data 佔存至  EventQ.KlineData
EventQ.KlineData=[]
#請求歷史報價,參數可能有出入,請自行參考最新官方 API 文件
nCode=skQ.SKQuoteLib_RequestKLine('TSEA',, sKLineType=4, sOutType=1)
#data 輸出
EventQ.KlineData[0:2]
#取1分k歷史報價
EventQ.KlineData=[]
tic=time.time()
nCode=skQ.SKQuoteLib_RequestKLine('TSEA', sKLineType=0, sOutType=1)
toc=time.time()
print('取得', len(EventQ.KlineData),  '筆1分k報價, 花費', round(toc-tic,2), '秒')


2017年8月1日 星期二

comtypes error 'tuple' object has no attribute '__ctypes_from_outparam__'

最近使用comtypes 需要使用到pythoncom功能,可以用
pip install pypiwin32

這樣就會附帶安裝pythoncom了

#2018年更新,這個問題在 comtypes 1.1.4 版中已經被修正了
使用comtypes 有時候會出現

comtypes 裡的 __init__.py  第 658 行程式碼做些修改可以修正這個bug
路徑大概類似這樣
~python\Lib\site-packages\comtypes\__init__.py
    657             # be iterable.
    658             if len(outargs) == 1:  # rescode is not iterable
--> 659                 return rescode.__ctypes_from_outparam__()
    660 
    661             rescode = list(rescode)
改成
            # be iterable.
            if len(outargs) == 1:  # rescode is not iterable
                try:
                    return rescode.__ctypes_from_outparam__()
                except: #somtimes rescode is tuple
                    return rescode

            rescode = list(rescode)

即可修正


Ref:



2017年7月31日 星期一

用 pywin32 COM makpy utiltiy 找群益api com 元件 GUID 碼

安裝pywin32
裝好後會在 python目錄/lib/site-pacjages/pythonwin 下看到一個 pythonwin IDE,執行後如下
選擇 Tools => COM makpy Uitility => Select library 選SKCOMlib後,會在 ~/lib\site-packages\win32com\gen_py\ 產生長串檔名的.py
打開後找 class ISKCenterLib, ISKOSQuoteLib 等的 coclass_clsid像是SKCenterLibclass_clsid 
{AC30BAB5-194A-4515-A8D3-6260749F8577}
之後就可以用這些class_clsid comtypes.client.CreatObject COM元件,請參考


群益 API in pyhton 報價範例

群益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()

2017年7月7日 星期五

python, COM, 群益 api

我剛開始自學python想做一些訊號分析的工作,想要用來分析金融商品,做自動化交易的工作。網路上很多人推薦群益的api,可以查詢報價,且伺服器相對穩定,取得速度又快,還不用費用。群益api是使用com元件的架構,我第一次使用的comtypes 這個module,但常常會莫名死機,不是很穩定。後來再google了許久後,發現可以使用win32com這個module,情況似乎好了點。以下是一些使用過程中的知識,有些用語其實我不知道正確的用法,就以我的理解寫下來了,拉拉雜雜,當作是一個筆記,先記上了,有空再來整理。希望可以有同好一起討論,我沒什麼程式經驗就是了,純粹自己興趣。


1. 什麼是 COM,先稍微了解一下com的架構
https://zh.wikipedia.org/wiki/%E7%BB%84%E4%BB%B6%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8B

2.安裝pywin32, 使用 makepy
參考網址HL的做法
http://hlfutures.blogspot.tw/2016/08/api-in-python_8.html

HL大用元大api的例子中可以找到# This CoClass is known by the name 'Yuanta.YuantaOrdCtrl.1'
from win32com.client import CoClassBaseClass
# This CoClass is known by the name 'Yuanta.YuantaOrdCtrl.1'
class YuantaOrd(CoClassBaseClass): # A CoClass

再把 Yuanta.YuantaOrdCtrl.1給win32com.client.Disptch('Yuanta.YuantaOrdCtrl.1') ,來使用
但群益的api不像元大api ,找不到name的訊息,後來我發現

class ISKCenterLib(DispatchBaseClass):
 CLSID = IID('{D61780D3-2239-4FD8-9C64-0E47B2E75464}')
 coclass_clsid = IID('{AC30BAB5-194A-4515-A8D3-6260749F8577}')
把coclass_clsid這串當作progid用也是可行的
所以輸入:
    
skC=win32com.client.Dispatch('{AC30BAB5-194A-4515-A8D3-6260749F8577}')

就可以用skC呼叫SKCenterLib底下的方法了

skC.SKCenterLib_GetReturnCodeMessage(skC.SKCenterLib_Login(ID,PW))
Out[5]: 'SK_SUCCESS'

這樣就可以登入群益伺服器主機了


3.取得報價,我不會!!  有人可以教我嗎?  要使用event 嗎? 不知道該怎麼處理event
我研究出來可以獲取報價的方式了,請參考
https://easontseng.blogspot.tw/2017/07/api-in-pyhton.html

2016年10月18日 星期二

How can I reverse a list in python?

This syntax works for any interable, not just lists. It just returns a new reversed list, but it doesn't modify the original one.
L=[01020, 40]
L[::-1]
[40, 20, 10, 0]
The syntax represanted as [start:stop:step], so step is -1. You're only returning the values in reverse 

To actually reverse the list,






2016年5月23日 星期一

論文中的英文姓名,姓與名該如何區分

論文中的英文姓名,常常搞不清楚該如何區分姓與名,問了google大神,在此做個備份

英文以名(first name)在前、姓(last name 或 surname)在後為原則。因此Mihaela Cardei 即是名為 Mihaela 且姓為 Cardei 的學者。有時候基於編排或索引的需要,會將姓調到名的前面,此時姓與名之間需用逗號隔開,如 Cardei, Mihaela。逗號表示此寫法的姓與名是調過來寫的。 

在論文中稱呼相關學者時,只要指出其姓即可,不用將其全名寫出,所以有些論文作者名稱常用一個英文字母來縮寫其名,如 M. Cardei 或 Cardei, M.。

有些外國人會有 middle name,但 middle name 可用可不用,通常不見得要寫出來,寫出來時也常用一個字母縮寫代替,如 Wendi B. Heinzelman 表示其 middle name 是 B 開頭的某個名字。如果 first name 和 middle name 皆縮寫,就會成為 W. B. Heinzelman 或 Heinzelman, W. B.。 

有些外國人的姓本身是由兩個或更多的字 (word) 構成的,如 Laurent El Ghaoui。此時要注意分辨中間的 word 是 middle name 或是 last name 的一部分,才不會鬧笑話。幸好 middle name 在大部份的文獻中都是用一個英文字母縮寫的,而姓的部分是不能縮寫的。所以一個簡單的判斷原則是,沒有縮寫而完整寫出的中間的 word,應該就是姓的一部分。

例如資訊科學的奠基者之一 John von Neumann,他是個匈牙利人,他的姓是 von Neumann。我們在論文中提到他時,可以寫成 von Neumann,但決不能寫成 Neumann。 有些作者體貼我們,會將屬於姓的兩個 word 用連字號 (hyphen)連起來,如 Hesham El-Rewini,表示他的姓是 El Rewini,而 Albert-László Barabási 是姓為 Barabási 的學者,前兩個word是他的名。

外國人的姓名有時有奇怪的寫法,我們最好原封不動的照寫,不要自作聰明改掉。如前述的 von Neumann 的 von 是小寫的,除非出現在句首,我們不能隨便改成大寫版本的 Von Neumann。英文中有不少這樣的例子。如O'Rourke。速食業龍頭 McDonald 中的 d 也一定要大寫。

Reference:
http://celaviasnote.blogspot.tw/2012/01/blog-post_26.html