把手邊的工具都了解一遍,像是合約、訂閱等等。尤其是昨天的訂閱,讓我們更前一步,但是實際上這樣的行情資料,並不適合在Jupyter notebook上,應該是要寫在一般的py
檔中,所以這篇嘗試移植過去。
本日程式碼使用:d15_subscribe_change_order.py
由於行情資料會一直進來,Jupyter notebook很適合觀察圖表,但是程式運作比較難進行,因此製作出一個trader
模組來進行資料處理吧~
首先把一些預設資料設定好,這邊設定的是登入資訊,在預設中,先預設登入測試環境的資訊。
class trader:
"""The Shioaji Object"""
def __init__(self) -> None:
self.simulation = True # 是否為測試環境
self.id = "PAPIUSER07"
self.pwd = "2222"
self.api = None
接著最核心的就是登入功能,登入功能會有三個參數:id
、pwd
、simulation
,分別代表登入的帳號、密碼、登入的環境,如果沒有輸入就是使用測試環境。
def login(self, id=None, pwd=None, simulation=True):
"""Login to Shioaji.
Args:
id(str): user ID
pwd(str): the login password
Returns:
bool: True is login successfully, False is not.
"""
print(f"=start login-{datetime.now().strftime('%Y%m%d')}")
if id and pwd:
self.id = id
self.pwd = pwd
try:
# 登入 shioaji
self.api = sj.Shioaji(simulation=simulation)
self.api.login(person_id=self.id, passwd=self.pwd)
except Exception as exc:
print(f"id={self.id}, pwd={self.pwd}...{exc}")
return False
return True
訂閱功能,其實就是原本的API簡化版,只有一個function名和一個合約參數而已。
def subscribe(self, contract):
print("訂閱中")
self.api.quote.subscribe(contract, quote_type=sj.constant.QuoteType.Tick)
解除訂閱也是如此,簡化原本的呼叫路徑。
def unsubscribe(self, contract):
self.api.quote.unsubscribe(contract, quote_type=sj.constant.QuoteType.Tick)
print("取消訂閱")
當設定完後,就是要實作囉!
首先製作一個thread
(scraper
),是用來停頓程式,這邊設定十秒,在這十秒鐘,來收集台指期貨的交易Tick,避免太快沒有收到資料就結束程式。
有了之後,我們就先登入shioaji,之後再訂閱資料,當十秒後關閉訂閱。其中當收到的訂閱回報時,會有一個回呼(callback)quote_callback
,將由這個功能顯示我們的API回復,進行後續的處理。這樣的用途是我們收到行情並不是只有一兩次而已,而是有長時間收資料的需求,像是我們要收到加權指數即時價格,就要推出台積電現在應該的價格,諸如此類的計算都是需要當下的交易狀況,因此需要一個thread和callback搭配,才能持續地收回報與計算作業。
def scraper():
print("start sleeping...")
time.sleep(30)
print("Wake up!!")
timer = threading.Thread(target=scraper) # 建立執行緒
t = trader()
t.login()
@t.api.quote.on_quote
def quote_callback(topic: str, quote: dict):
"""Print quote info.
此版本沒有 from shioaji import TickSTKv1了,
所以不能用範例QuoteVersion.v1,
只能用QuoteVersion.v0
"""
print(f"Topic: {topic}, Quote: {quote}")
t._get_subscribe()
t.subscribe(t.api.Contracts.Futures.TXF["TXF202110"])
timer.start() # 執行
timer.join() # 等待結束
t.quote.unsubscribe(t.Contracts.Futures.TXF["TXF202110"])
如此改寫,我們就可以重複使用這個class了,不過更好的方式應該是把登入拉出來,變成登入模組和訂閱模組。但我們這個範例就先不處理這塊,把它全部放在一起,之後需要在切開。