2024年9月13日 星期五

範例 期貨權益

取得期貨權益並存入excel中

使用 jupyterlab 範例

使用 python script 範例

### GetFutureRight 範例
from comtypes.client import GetModule, GetEvents, CreateObject
### GetModule 將 API 打包成 python 可以呼叫的 package
# 第一次執行時會在 comtypes.gen 建立 SKCOMLib wrap package, 之後可以不用再執行,若 API 元件升級時需要至comtypes.gen資料夾刪除 skcom 相關檔案,再重新執行 GetModule
GetModule(r"C:\skcom\CapitalAPI_2.13.43\x64\SKCOM.dll")
from comtypes.gen import SKCOMLib as sk
import pythoncom
import asyncio
import pandas as pd
### 建立 COM 元件
if 'skC' not in globals(): skC = CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
if 'skR' not in globals(): skR = CreateObject(sk.SKReplyLib, interface=sk.ISKReplyLib)
if 'skO' not in globals(): skO = CreateObject(sk.SKOrderLib, interface=sk.ISKOrderLib)
### 輸入身分證與密碼
ID = '你的身分證號'
PW = '你的帳戶密碼'
### 建立 skcom 事件類別
# ReplyLib事件類別
class skR_events:
def OnReplyMessage(self, bstrUserID, bstrMessage):
'''API 2.13.17 以上一定要返回 sConfirmCode=-1'''
sConfirmCode=-1
print('skR_OnReplyMessage', bstrMessage)
return sConfirmCode
# OrderLib 事件類別
class skO_events:
def __init__(self):
self.future_right = []
# 現貨帳號
self.accTS = ''
# 期貨帳號
self.accTF = ''
def OnAccount(self, bstrLogInID, bstrAccountData):
'''取得使用者帳號資訊'''
strI = bstrAccountData.split(',')
# bstrAccountData: 0市場,1分公司,2分公司代號,3帳號,4身份證字號,5姓名
if strI[0] == 'TS': # 現貨帳號
self.accTS = strI[1]+strI[3]
elif strI[0] == 'TF': # 期貨帳號
self.accTF = strI[1]+strI[3]
# print('skO_OnAccount', bstrLogInID, bstrAccountData)
def OnFutureRights(self, bstrData):
if '##' not in bstrData:
self.future_right.append(bstrData)
# print('skO_OnFutureRights', bstrData)
# Event sink, 事件實體
EventR = skR_events()
EventO = skO_events()
# 連結 com 元件與事件callback
ConnR = GetEvents(skR, EventR)
ConnO = GetEvents(skO, EventO)
print('Setting event handeller done!!')
### 適用於 Jupyter lab 的 event loop, 持續監測 skcom api 的事件函數
# working functions, async coruntime to pump events
async def pump_task():
while True:
pythoncom.PumpWaitingMessages()
await asyncio.sleep(0.1)
# get an event loop
loop = asyncio.get_event_loop()
pumping_loop = loop.create_task(pump_task())
print('Event pumping ready!')
### 登入 與 OrderLib 初始化
# login
nCode=skC.SKCenterLib_Login(ID,PW)
print('Login', skC.SKCenterLib_GetReturnCodeMessage(nCode))
# SKOrderLib 初始化
ncode = skO.SKOrderLib_Initialize()
print('SKOrderLib 初始化', skC.SKCenterLib_GetReturnCodeMessage(nCode))
# 取得帳號
ncode = skO.GetUserAccount()
print('取得帳號', skC.SKCenterLib_GetReturnCodeMessage(nCode))
### 取得期貨權益
ncode = skO.GetFutureRights(ID, EventO.accTF, 1)
print('取得期貨權益', skC.SKCenterLib_GetReturnCodeMessage(nCode))
# OnFutureRight 回傳欄位
futurRight_columns = [
'帳戶餘額', '浮動損益', '已實現費用','交易稅','預扣權利金','權利金收付',
'權益數','超額保證金','存提款','買方市值','賣方市值','期貨平倉損益',
'盤中未實現','原始保證金','維持保證金','部位原始保證金','部位維持保證金',
'委託保證金','超額最佳保證金','權利總值','預扣費用','原始保證金2',
'昨日餘額','選擇權組合單加不加收保證金','維持率','幣別','足額原始保證金',
'足額維持保證金', '足額可用','抵繳金額','有價可用','可用餘額',
'足額現金可用','有價價值','風險指標','選擇權到期差異','選擇權到期差損',
'期貨到期損益','加收保證金','LOGIN_ID','ACCOUNT_NO']
### 存入 dataframe 再轉存 excel 格式
# 存入 pandas dataframe
df = pd.DataFrame([EventO.future_right[0].split(',')], columns=futurRight_columns)
# 存成 excel
df.to_excel('futureRight.xlsx')

2023年3月23日 星期四

修改 jupyterlab notebooks 起始位置

久久用一次,但常忘記,所以紀錄一下 

  1. 打開 cmd prompt,並執行 jupyter notebook --generate-config
     

  2. 會產生一個  jupyter_notebook_config.py 檔案。 也會告知你存放的路徑,類似                       D:\python\WPy64-31090\python-3.10.9.amd64\etc\jupyter\jupyter_notebook_config.py

  3. 用文字編輯器開啟它
     
  4. 尋找檔案內這行 #c.NotebookApp.notebook_dir = '' 
    移除井字號, 將單引號內輸入你想要的目錄位置,
    例如: c.NotebookApp.notebook_dir = "D:/python/notebooks/"


  5. 重新啟動 jupyter lab 後,起始位置就會改成您指定的目錄 

2023年2月20日 星期一

使用 pythonnet 呼叫群益api

 多年前曾用想要用pythonnet,來載入群益的api ,但最後失敗了。這篇純粹是出自個人好奇,還是想了解是否能用 pythonnet 來載入 dll,最近找到可以使用的步驟了,在windows下 python 可以呼叫群益api,讓熟悉 C# 的開發者,又想用 python 的人多一種選擇。

    目前使用這個方法的好處:

  1. 在 juypterlab 下,可以顯示各個 function 參數有哪些,減少一直翻手冊的時間。
  2. callback 部屬比較直覺快速,但也因此比較冗長。
  3. 熟悉 C# 的人,可以加入 C# 相關的 reference, namespace 當作 python 的模組來使用。
  4. 其他券商的 dll 檔,也有機會用這套方法來呼叫? 

    壞處:

  1. 目前遇到狀況是 callback 出現錯誤時,python沒有任何錯誤通知,除錯比較麻煩。


我的安裝環境:

  • windows 10, 
  • 我使用的是python 3.10.5 
  • visual studio 2022 (只是為了使用它的 tlbimp.exe)

前置工作

1. 用 tlbimp.exe 將 SKCOM.dll 轉成  Type library

    要先將群益的SKCOM.dll 轉成  Type library,我有安裝 visual studio 2022,利用它附帶的 comandline prompt terminal ,下指令 tlbimp.exe 將 SKCOM.dll 轉成 typelib 形式,最終產生 SKCOMLib.dll 的檔案。之後就可以輕鬆用 pythonnet 的 clr 模組取用。




2. 安裝 pythonnet

    Python.NET 模組可以讓 python 使用者無縫整合 .NET Common Language Runtime (CLR)。它讓 Python 可以跟 CLR 互動, 甚至也可以反過來將 Python 包進 .NET 裡.
    在你的 python 環境下用 pip 安裝 pythonnet 即可。詳細操作請看 pythonnet 官網


    pip install pythonnet


使用 pythonnet 的 clr 模組呼叫 SKCOMAPI


# 使用 pythonnet 呼叫群益api
import clr
# AddReference,不用加副檔名 .dll
clr.AddReference(r"C:\skcom\CapitalAPI_2.13.41\x64\SKCOMLib") # 使用絕對路徑我個人偏好這個
# 加入參考後,利用 improt SKCOMLib 可以使用群益整個 skcomapi 的功能,
import SKCOMLib
# 也可以 from SKCOMlib import 部分功能
from SKCOMLib import SKCenterLib, SKReplyLib, SKQuoteLib, SKSTOCKLONG
# 推動eventloop用
import time
import pythoncom
# 使用 skcom 元件
skC = SKCenterLib()
skR = SKReplyLib()
skQ = SKQuoteLib()
#####################################################
# Configuration
ID = ""
PW = ""
# 欲報價的商品代號
StockNo = "1101,2330"
# working function
# resqest stock
def request_stock(page, stocks):
ncode, _ = skQ.SKQuoteLib_RequestStocks(page, stocks)
print(f"Request stock: {stocks}", skC.SKCenterLib_GetReturnCodeMessage(ncode))
#####################################################
# Event callback
# SKReplyLib 相關 callback
def OnReplyMessage(bstrUserID , bstrMessage, sConfirmCode):
# 這個一定要,Login 時會檢查 sConfirmCode 是否 == -1
sConfirmCode = -1
print("OnReplyMessage", bstrMessage)
return sConfirmCode
# SKQuoteLib 相關
def OnConnection(nKind, nCode):
"""回報連線報價伺服器狀態
nKind: 3001 連線報價伺服器
3002 離線報價伺服器
3003 連線成功,收到3003後,始可登錄報價商品
"""
print(f'skQ_OnConnection nKind= {nKind}', skC.SKCenterLib_GetReturnCodeMessage(nKind))
if nKind == 3003:
request_stock(1, StockNo)
def OnNotifyQuoteLONG(sMarketNo, nIndex):
"""報價"""
ts = SKSTOCKLONG()
ncode, ts = skQ.SKQuoteLib_GetStockByIndexLONG(sMarketNo, nIndex, ts)
print(ts.bstrStockName, "市價", ts.nClose/ 10**ts.sDecimal, "單量", ts.nTickQty)
#####################################################
# 綁定 event callback,需一個一個綁定,如果有比較快的方法請跟我分享 :)
# 請查閱SKCOMapi手冊有哪些 Callback,及相關參數
skR.OnReplyMessage += OnReplyMessage
skQ.OnConnection += OnConnection
skQ.OnNotifyQuoteLONG += OnNotifyQuoteLONG
print("綁定各元件的event callback")
####################################################
# Login
ncode = skC.SKCenterLib_Login(ID, PW)
print("Login", skC.SKCenterLib_GetReturnCodeMessage(ncode))
# EnterMonitor
ncode = skQ.SKQuoteLib_LeaveMonitor()
ncode = skQ.SKQuoteLib_EnterMonitorLONG()
print("EnterMonitor", skC.SKCenterLib_GetReturnCodeMessage(ncode))
# pump events for 30 seconds
print("Pumping events for 30s")
for i in range(30):
pythoncom.PumpWaitingMessages()
time.sleep(1)









2022年11月14日 星期一

群益海期 tick 報價範例

 群益海期 ticks 報價範例,本範例直接在 OnNotifyTicksNineDigitLONG, OnNotifyHistoryTicksNineDigitLONG 裡做一些資料處理,當海期報價資料量很大的時候,處理速度變很慢,kline 轉換也有點慢,日後都還需要改進,朋友呀,如果有什麼更快的方法請教教我。



Notebook 範例版 jupyter notebook 

範例.py

# # 強烈建議用 jupyterlab or ipython 來測試
# # 海期 tick 報價範例
import pythoncom
import asyncio
import datetime
import pandas as pd
import comtypes.client as cc
import plotly.graph_objects
# 只有第一次使用 api ,或是更新 api 版本時,才需要呼叫 GetModule
# 會將 SKCOM api 包裝成 python 可用的 package ,並存放在 comtypes.gen 資料夾下
# 更新 api 版本時,記得將 comtypes.gen 資料夾 SKCOMLib 相關檔案刪除,再重新呼叫 GetModule
cc.GetModule('C:\\skcom\\CapitalAPI_2.13.39\\x64\\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
# login ID and PW
# 身份證
ID = ''
# 密碼
PW = ''
print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S,"), 'Set ID and PW')
# # 建立 event pump and event loop
# 新版的jupyterlab event pump 機制好像有改變,因此自行打造一個 event pump機制,
# 目前在 jupyterlab 環境下使用,也有在 spyder IDE 下測試過,都可以正常運行
# working functions, async coruntime to pump events
async def pump_task():
'''在背景裡定時 pump windows messages'''
while True:
pythoncom.PumpWaitingMessages()
# 想要反應更快 可以將 0.1 取更小值
await asyncio.sleep(0.1)
# 將ticks 轉為Kline
def convert_to_kline(query_stock, freq):
'''將ticks 轉為Kline
query_stock: 欲查詢的商品代號 ex. "YM2212"
freq: 請參考 pandas resample 用法, "T" 為分, "S"為秒
"5T" 為 5分Kline, "30S" 為30秒Kline
return a kline dataframe
'''
# 只保留成交時間,成交價與量資料
df = EventOSQ.ticks.query(f'bstrStockNo == "{query_stock}"').copy()
df = df.filter(['Datetime', 'price', 'volume'], axis=1)
# 將成交時間欄位資料按格式轉換為 datetime 資料
df['Datetime'] = pd.to_datetime(df['Datetime'], format='%Y%m%d%H%M%S')
# 設定資料以成交時間欄位為序列索引
df = df.set_index('Datetime')
# return OHLCV Kline
kline = df.resample(rule=freq).agg({'price': 'ohlc', 'volume': 'sum'}).dropna()
kline.columns = kline.columns.get_level_values(1)
return kline
# plot kline
def plot_candlestick(df):
figure = plotly.graph_objects.Figure(
data=[
plotly.graph_objects.Candlestick(
x=df.index,
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name='K line',
),
],
# 設定 XY 顯示格式
layout=plotly.graph_objects.Layout(
xaxis=plotly.graph_objects.layout.XAxis(
tickformat='%Y-%m-%d %H:%M'
),
yaxis=plotly.graph_objects.layout.YAxis(
tickformat='.2f'
)
)
)
figure.show()
# get an event loop
loop = asyncio.get_event_loop()
pumping_loop = loop.create_task(pump_task())
print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S,"), "Event pumping is ready!")
# 建立物件,避免重複 createObject
# 登錄物件
if 'skC' not in globals():
skC = cc.CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
# 海期報價物件
if 'skOSQ' not in globals():
skOSQ = cc.CreateObject(sk.SKOSQuoteLib , interface=sk.ISKOSQuoteLib)
# 回報物件
if 'skR' not in globals():
skR = cc.CreateObject(sk.SKReplyLib, interface=sk.ISKReplyLib)
# # # 建立 event handler
# SKOSQ event handler
class skOSQ_events:
def __init__(self):
self.OverseaProductsDetail = []
# 以dataframe方式存放ticks
self.ticks = pd.DataFrame(
{'Datetime': pd.Series(dtype='str'),
'price': pd.Series(dtype='float'),
'volume': pd.Series(dtype='int')},
index = pd.MultiIndex(levels=[[],[],[],[]],
codes=[[],[],[],[]],
names=['bstrStockNo', 'nPtr', 'nDate', 'nTime']),
)
def OnConnect(self, nKind, nCode):
'''連線海期主機狀況回報'''
print(f'skOSQ_OnConnect nCode={nCode}, nKind={nKind}')
def OnOverseaProductsDetail(self, bstrValue):
'''查詢海期/報價下單商品代號'''
if "##" not in self.OverseaProductsDetail:
self.OverseaProductsDetail.append(bstrValue.split(','))
else:
print("skOSQ_OverseaProductsDetail downloading is completed.")
def OnNotifyQuoteLONG(self, sIndex):
'''requestStock 報價回報'''
# 儘量避免在這裡使用繁複的運算,這裡僅在 console 端印出報價
ts = sk.SKFOREIGNLONG()
skOSQ.SKOSQuoteLib_GetStockByIndexLONG(sIndex, ts)
print(ts.bstrExchangeNo, ts.bstrStockNo, ts.nClose, ts.nTickQty)
def OnNotifyTicksNineDigitLONG (self, nIndex, nPtr, nDate, nTime,
nClose, nQty):
'''requestTick 回報'''
# 儘量避免在這裡使用繁複的運算
ts = sk.SKFOREIGN_9LONG()
skOSQ.SKOSQuoteLib_GetStockByIndexNineDigitLONG(nIndex, ts)
self.ticks.loc[(ts.bstrStockNo, nPtr, nDate, nTime),
["Datetime", "price", "volume"]] = [f"{nDate}{nTime:06}",
nClose/10**ts.sDecimal,
nQty]
def OnNotifyHistoryTicksNineDigitLONG (self, nIndex, nPtr,
nDate, nTime, nClose, nQty):
''' History tick 回報'''
# 儘量避免在這裡使用繁複的運算
ts = sk.SKFOREIGN_9LONG()
ncode = skOSQ.SKOSQuoteLib_GetStockByIndexNineDigitLONG(nIndex, ts)
self.ticks.loc[(ts.bstrStockNo, nPtr, nDate, nTime),
["Datetime", "price", "volume"]] = [f"{nDate}{nTime:06}",
nClose/10**ts.sDecimal,
nQty]
# SKReplyLib event handler
class skR_events:
def OnReplyMessage(self, bstrUserID, bstrMessage):
'''API 2.13.17 以上一定要返回 sConfirmCode=-1'''
sConfirmCode = -1
print('skR_OnReplyMessage ok')
return sConfirmCode
# # 建立 event 跟 event handler 的連結
# Event sink, 事件實體化
EventOSQ = skOSQ_events()
EventR = skR_events()
# 建立 event 跟 event handler 的連結
ConnOSQ = cc.GetEvents(skOSQ, EventOSQ)
ConnR = cc.GetEvents(skR, EventR)
# # 登入及各項初始化作業
# login
print('Login', skC.SKCenterLib_GetReturnCodeMessage(skC.SKCenterLib_Login(ID,PW)))
# 海期商品初始化
nCode = skOSQ.SKOSQuoteLib_Initialize()
print("SKOSQuoteLib_Initialize", skC.SKCenterLib_GetReturnCodeMessage(nCode))
###################################################################################
# 以下皆以手動輸入
# 登入海期報價主機
nCode = skOSQ.SKOSQuoteLib_LeaveMonitor()
nCode = skOSQ.SKOSQuoteLib_EnterMonitorLONG()
print('SKOSQuoteLib_EnterMonitorLONG()', skC.SKCenterLib_GetReturnCodeMessage(nCode))
# 登入海期報價主機,確認 OnConnect 出現 3001 回報後
# 才可 requesttick
StockNo ="CBOT,YM2212"
nCode = skOSQ.SKOSQuoteLib_RequestTicks(0, StockNo)
print(f"Requesting ticks, {StockNo}", skC.SKCenterLib_GetReturnCodeMessage(nCode[1]))
# 檢視 ticks 狀態,熱門商品資料數量很多,可能要等一下資料回傳完畢
EventOSQ.ticks
# 轉換為 1分K,並畫出來,pandas 轉 kline 數據一多,好像有點慢
df_1k = convert_to_kline(query_stock="YM2212" ,freq="1T")
plot_candlestick(df_1k)
# 轉換為 5分K,並畫出來
df_5k = convert_to_kline(query_stock="YM2212",freq="5T")
plot_candlestick(df_5k)
# 多商品 tick 報價
# 一個 page 放一檔 tick 報價商品. page 放 0,好像群益系統會自動分配 page
strCode = ['CBOT,YM0000', 'CBOT,YM2306']
for page, code in enumerate(strCode):
print(skOSQ.SKOSQuoteLib_RequestTicks(page+1, code))
# 轉換多商品 tick to kline
stockList = ['YM0000', 'YM2306']
kline_data = {}
for s in stockList:
kline_data[s] = convert_to_kline(s, '1T')['close']
# 順便計算 20 ma
kline_data[f'{s}_ma20'] = convert_to_kline(s, '1T')['close'].rolling(20).mean()
df_kline = pd.DataFrame(kline_data)
df_kline.plot()

2022年5月9日 星期一

群益 skcom api 海期報價、下單及回報範例

群益海期報價跟下單跟api手冊上寫的有點出入,手冊也沒有明確表示下單的流程,經過一番試誤,可以報價也可以下單了。實在是太少碰海期相關的 api,每次想用的時候都重新經歷一次錯誤,因此寫下來留個紀錄好參考。真的很少用,可能有不少地雷,因此僅供參考,也歡迎大家分享曾經遇過的問題。

幾個容易有錯誤的地方

1. 海期商品與交易所的報價代號跟下單代號有些是不同的,請用 GetOverseaProductDetail 來查詢正確代號。

2. 報價代碼寫法是  "交易所代碼1,商品代碼1#交易所代碼2,商品代碼2", 不同商品間以#字號隔開

3. 海期商品連線報價主機後,只會回應 3001,之後即可查詢報價

3. 海期委託單物件填寫商品代碼跟 GetOverseaProductDetail 查詢的稍有出入,需要加工處理。例如微型小道瓊下單代碼為 MYM_202206,填入委託單物件時事拆成兩個參數,要分別填入商品代碼及年月, 如 bstrStockNo = "MYM" 及 bstrYearMonth = "202206"

4. 要能下單要有幾項前置作業, SKOrderLib_Initialize >> ReadCertByID >> GetUserAccount >> SKOrderLib_LoadOSCommodity

5. "期貨API下單同意書"要記得簽,才能進行海期報價,我都用手機掌中財神 app,下方有個同意書專區,把裡面能簽的都簽了。

6. 有網友詢問如何使用 GetOverSeaFutureOpenInterestGW,手冊寫經由 OnOverSeaFutureOpenInterestGW 回報,測試後發現並沒有反應。深查後發現手冊坑人,原來是經由 OnOFOpenInterestGWReport 來做回報,也一併加入本範例供參考。

Notebook 範例版 jupyter notebook 

py 範例版,僅在 spyder IDE 下測試過

# # 海期報價及下單範例
import pythoncom
import asyncio
import datetime
import pandas as pd
import comtypes.client as cc
# 只有第一次使用 api ,或是更新 api 版本時,才需要呼叫 GetModule
# 會將 SKCOM api 包裝成 python 可用的 package ,並存放在 comtypes.gen 資料夾下
# 更新 api 版本時,記得將 comtypes.gen 資料夾 SKCOMLib 相關檔案刪除,再重新呼叫 GetModule
cc.GetModule('C:\\skcom\\CapitalAPI_2.13.37\\x64\\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
# login ID and PW
# 身份證
ID = 'A123456789'
# 密碼
PW = 'ThisIsUrPW'
print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S,"), 'Set ID and PW')
# # 建立 event pump and event loop
# 新版的jupyterlab event pump 機制好像有改變,因此自行打造一個 event pump機制,目前在 jupyterlab 環境下使用,也有在 spyder IDE 下測試過,都可以正常運行
# working functions, async coruntime to pump events
async def pump_task():
'''在背景裡定時 pump windows messages'''
while True:
pythoncom.PumpWaitingMessages()
# 想要反應更快 可以將 0.1 取更小值
await asyncio.sleep(0.1)
# get an event loop
loop = asyncio.get_event_loop()
pumping_loop = loop.create_task(pump_task())
print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S,"), "Event pumping is ready!")
# # 建立 event handler
# 建立物件,避免重複 createObject
# 登錄物件
if 'skC' not in globals(): skC = cc.CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
# 下單物件
if 'skO' not in globals(): skO = cc.CreateObject(sk.SKOrderLib , interface=sk.ISKOrderLib)
# 海期報價物件
if 'skOSQ' not in globals(): skOSQ = cc.CreateObject(sk.SKOSQuoteLib , interface=sk.ISKOSQuoteLib)
# 回報物件
if 'skR' not in globals(): skR = cc.CreateObject(sk.SKReplyLib, interface=sk.ISKReplyLib)
# 建立事件處理類別
# SKOSQ event handler
class skOSQ_events:
def __init__(self):
self.OverseaProductsDetail = []
def OnConnect(self, nKind, nCode):
'''連線海期主機狀況回報'''
print(f'skOSQ_OnConnect nCode={nCode}, nKind={nKind}')
def OnOverseaProductsDetail(self, bstrValue):
'''查詢海期/報價下單商品代號'''
if "##" not in self.OverseaProductsDetail:
self.OverseaProductsDetail.append(bstrValue.split(','))
else:
print("skOSQ_OverseaProductsDetail downloading is completed.")
def OnNotifyQuoteLONG(self, sIndex):
'''requestStock 報價回報'''
# 儘量避免在這裡使用繁複的運算,這裡僅在 console 端印出報價
ts = sk.SKFOREIGNLONG()
nCode = skOSQ.SKOSQuoteLib_GetStockByIndexLONG(sIndex, ts)
print(ts.bstrExchangeNo, ts.bstrStockNo, ts.nClose, ts.nTickQty)
# SKReplyLib event handler
class skR_events:
def OnReplyMessage(self, bstrUserID, bstrMessage):
'''API 2.13.17 以上一定要返回 sConfirmCode=-1'''
sConfirmCode = -1
print('skR_OnReplyMessage ok')
return sConfirmCode
def OnNewData(self, bstrUserID, bstrData):
'''委託單回報'''
print("skR_OnNewData", bstrData)
# SKOrderLib event handler
class skO_events:
def __init__(self):
self.TFAcc = []
def OnAccount(self, bstrLogInID, bstrAccountData):
strI = bstrAccountData.split(',')
# 找出期貨帳號
if len(strI) > 3 :
if strI[0] == 'TF' :
# 分公司代碼 + 期貨帳號
self.TFAcc = strI[1] + strI[3]
def OnOFOpenInterestGWReport(self, bstrData):
# 回報海期的 OI 資料
print(bstrData)
# # 建立 event 跟 event handler 的連結
# Event sink, 事件實體化
EventOSQ = skOSQ_events()
EventR = skR_events()
EventO = skO_events()
# 建立 event 跟 event handler 的連結
ConnOSQ = cc.GetEvents(skOSQ, EventOSQ)
ConnR = cc.GetEvents(skR, EventR)
ConnO = cc.GetEvents(skO, EventO)
# # 登入及各項初始化作業
# login
print('Login', skC.SKCenterLib_GetReturnCodeMessage(skC.SKCenterLib_Login(ID,PW)))
# 海期商品初始化
nCode = skOSQ.SKOSQuoteLib_Initialize()
print("SKOSQuoteLib_Initialize", skC.SKCenterLib_GetReturnCodeMessage(nCode))
# 下單前置至步驟
# 1. 下單初始化
nCode = skO.SKOrderLib_Initialize()
print("Order Initialize", skC.SKCenterLib_GetReturnCodeMessage(nCode))
# 2. 讀取憑證
nCode = skO.ReadCertByID(ID)
print("ReadCertByID", skC.SKCenterLib_GetReturnCodeMessage(nCode))
# 3. 取得海期帳號
nCode = skO.GetUserAccount()
print("GetUserAccount", skC.SKCenterLib_GetReturnCodeMessage(nCode), EventO.TFAcc)
# 4. 連線委託回報主機
nCode = skR.SKReplyLib_ConnectByID(ID)
print("Connect to ReplyLib server", skC.SKCenterLib_GetReturnCodeMessage(nCode))
# # 登入海期報價主機,確認 OnConnect 出現 3001 回報後始可進行下列步驟
# 以下皆以手動輸入
# 5. 登入海期報價主機
nCode = skOSQ.SKOSQuoteLib_EnterMonitorLONG()
print('SKOSQuoteLib_EnterMonitor()', skC.SKCenterLib_GetReturnCodeMessage(nCode))
# # 下單前需要下載海期商品,才能下單
# 不然會報 1035 錯誤碼
# 6. 登入海期報價主機後,等確認 OnConnect 出現 3001 後,再下載海期商品
nCode = skO.SKOrderLib_LoadOSCommodity()
print('SKOrderLib_LoadOSCommodity', skC.SKCenterLib_GetReturnCodeMessage(nCode))
# # 查詢海期交易所及商品報價與下單代碼
# 等 OnConnect 出現 3001 回報後,可以查詢海期交易所及交易商品代號
# 查詢詳細交易所及商品代號,注意海期下單與報價代號有些不同
EventOSQ.OverseaProductsDetail = []
nCode = skOSQ.SKOSQuoteLib_GetOverseaProductDetail(1)
print("GetOverseaProductDetail", skC.SKCenterLib_GetReturnCodeMessage(nCode))
print("交易所代碼, 交易所名稱, 商品報價代碼, 商品名稱, 交易所下單代碼, 商品下單代碼, 最後交易日")
print(EventOSQ.OverseaProductsDetail[5])
print(EventOSQ.OverseaProductsDetail[-2])
# 下單代碼
# 離開海期報價主機,有需要再使用
# nCode = skOSQ.SKOSQuoteLib_LeaveMonitor()
# print(nCode, skC.SKCenterLib_GetReturnCodeMessage(nCode))
# # 海期報價範例
# 登陸海期商品報價, 格式為 "交易所代碼,商品代碼",不同商品用#隔開,請利用
# GetOverseaProductDetail 查詢
# 登陸海期商品報,接收 callback 為 EventOSQ 的 OnNotifyQuoteLONG
# 注意熱門商品報價頻率會很高,要手動清除,不然 jupterlab 頁面會愈來愈慢
code = skOSQ.SKOSQuoteLib_RequestStocks(1, "CBOT,MYM0000#TCE,JCO2205")
print(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S,"), "RequestStocks", skC.SKCenterLib_GetReturnCodeMessage(code[1])
# # 海期下單物件 OVERSEAFUTUREORDER
# 委託價分子,這是海期商品小數點的部位,可以參考 https://www.order-master.com/doc/topic/54/
# 建立海期委託單物件
# 詳細參數請參考 api 手冊,這裡僅示範可以下單所需的參數
# 以下參數我是先用 api 附的 SKCOMtester.exe 測試,直到可以送單所測出來需要的參數
# 注意 bstr開頭的參數都要以文字型態帶入,特別是 委託價 (bstrOrder),委託價分子(bstrOrderNumerator)
# 根據 GetOverseaProductDetail 取得的下單代碼,
# 如 芝加哥交易所的微型小道瓊期貨,交易所代碼是 CBT, 商品下單代碼是 MYM_202206,
# 但 OVERSEAFUTUREORDER 物件的參數,要再另外拆成 海外期權代號(bstrStockNo) 及 近月商品年月(bstrYearMonth)
# 要將 MYM_202206 拆成 MYM 及 202206
fo = sk.OVERSEAFUTUREORDER()
fo.bstrFullAccount = EventO.TFAcc # 海期帳號,分公司代碼+帳號7碼
fo.bstrExchangeNo = "CBT" # 交易所代碼。
fo.bstrStockNo = "MYM" # 海外期權代號。
fo.bstrYearMonth = "202206" # 近月商品年月( YYYYMM) 6碼
# fo.bstrYearMonth2 # 遠月商品年月( YYYYMM) 6碼 {價差下單使用}
fo.bstrOrder = "31500" # 委託價。
fo.bstrOrderNumerator = "0" # 委託價分子。也就是小數點的部位
# fo.bstrTrigger # 觸發價。
# fo.bstrTriggerNumerator # 觸發價分子。
fo.sBuySell = 0 # 0:買進 1:賣出
# {價差商品,需留意是否為特殊商品-近遠月前的「+、-」符號}
fo.sNewClose = 0 # 新/平倉,0:新倉 {目前海期僅新倉可選}
fo.sDayTrade = 0 # 當沖 0:否, 1:是;{海期價差單不提供當沖}
# 可當沖商品請參考交易所規定。
fo.sTradeType = 0 # 0:ROD 當日有效單; 1:FOK 立即全部成交否則取消; 2:IOC 立即成交否則取消(可部分成交)
# {限價單LMT可選ROD/IOC/FOK,其餘單別固定ROD}
fo.sSpecialTradeType = 0 # 0:LMT 限價單 1:MKT 2:STL 3.STP
fo.nQty = 1 # 交易口數。
# 海期下單 SendOverSeaFutureOrder(bstrLogInID, bAsyncOrder, pOrder)
msg, nCode = skO.SendOverSeaFutureOrder(ID, 0, fo)
print(msg, skC.SKCenterLib_GetReturnCodeMessage(nCode))
## 測試 GetOverSeaFutureOpenInterestGW
# 手冊寫 OnGetOverSeaFutureOpenInterestGW 來回報是錯誤的,應該是 OnOFOpenInterestGWReport 來回報的
ncode = skO.GetOverSeaFutureOpenInterestGW(ID, EventO.TFAcc, 2)
print('GetOverSeaFutureOpenInterestGW', skC.SKCenterLib_GetReturnCodeMessage(ncode))

2022年3月7日 星期一

最近留言區被機器人進駐,有問題請到FB版上提問

 最近留言區被機器人進駐,會重複發一些垃圾留言,先暫停留言功能,有問題請到FB版上提問


FB連結

2021年11月2日 星期二

Add Virtual Environment to Jupyter Notebook

確認有安裝 ipykernel 後,terminal 下移動到新建的虛擬環境資料夾下,例如 my_env_name 執行下列指令:

python -m ipykernel install --user --name=<my_env_name>


ref: Create Virtual Environment using “virtualenv” and add it to Jupyter Notebook | by B. Chen | Towards Data Science

2021年10月6日 星期三

群益API SKReplyLib 回報 OnNewData 範例

現在沒有模擬單帳號可以測試了,因此我用群益下單軟體,下了個很遠不會成交的單子當作委託測試單。

另外最近 jupyter lab 開發不知道為什麼當我使用 %matplotlib auto 的 magic function時,會使整個notebook 當機,因此用 asyncio 自製了一個簡易的 event loop 來定時 pump event

ref:
jupyter跑 asyncio 的用法

範例
from comtypes.client import CreateObject, GetEvents
import comtypes.gen.SKCOMLib as sk
import pythoncom
import asyncio
# 建立物件, 登錄物件, 回報物件
skC = CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
skR = CreateObject(sk.SKReplyLib , interface=sk.ISKReplyLib)
# 輸入身分證與密碼
ID = ''
PW = ''
# working functions, async coruntime to pump events
async def pump_task():
while True:
pythoncom.PumpWaitingMessages()
await asyncio.sleep(0.1)
# 建立事件類別
class skR_events:
def OnReplyMessage(self, bstrUserID, bstrMessage):
'''API 2.13.17 以上一定要返回 sConfirmCode=-1'''
sConfirmCode=-1
print('skR_OnReplyMessage', bstrMessage)
return sConfirmCode
def OnNewData(self, bstrUserID , bstrData):
print('skR_OnNewData', bstrData)
# Event sink, 事件實體
EventR = skR_events()
# make connection to event sink
ConnR = GetEvents(skR, EventR)
print('Making event handeller')
# get an event loop
loop = asyncio.get_event_loop()
pumping_loop = loop.create_task(pump_task())
print('Event pumping!')
# login
nCode=skC.SKCenterLib_Login(ID,PW)
print('Login', skC.SKCenterLib_GetReturnCodeMessage(nCode))
# 連接回報伺服器
skR.SKReplyLib_ConnectByID(ID)


結果


2020年6月24日 星期三

在 linux 下使用wine python 串接群益 SKCOM API

        群益api 是使用 windows 的 COM 技術,在 linux 下要靠 wine 來模擬 windows 的環境。wine 要使用 32 bit 的相容性比較好,因此本篇 linux 系統 , python, skcom.dll 皆是使用 32 bit版。

操作概念是 在 linux 下裝 wine 註冊 SKCOM.dll, 用 wine 安裝 windows 版本的 python,  再用這個windows 版的 python 安裝 comtypes, pywin32 等套件來使用 skcom。 整個環境會是在 wine 底下執行的,操作起來還是有點隔閡,不是很順暢,我也還在摸索 

linux 我使用 lubuntu 18.04 alternative-i386 這個桌面版本, 執行Wine時建議是要在有XWindow的環境下執行,安裝一些 windows 程式,會需要 GUI 的操作 

linux wine 的安裝跟使用是參考這兩篇, 研究的超仔細,大推!! 

安裝 wine, winetricks

  • 建議使用32位元的作業系統來安裝Wine,因為Wine目前64位元的支援很差,它主要是以執行32位元的Windows程式為主!
  • 建議是透過compile Wine原始碼的方式來安裝Wine,也是為了避免32位元的函式庫裝得不夠完整!
  • winetricks 可以幫助安裝 VC++ runtime 2010 ,註冊 SKCOM.dll 時需要用到 
  • 剛裝好的 lubuntu 環境,把 apt 更新至最新,並裝下列開發套件,編譯 Wine 需要用到
$ sudo apt update; apt upgrade
$ sudo apt install openssh-client openssh-server vim software-properties-common gcc g++ vim subversion automake autoconf perl patch build-essential libtool doxygen bison flex zlib1g-dev gperf tofrodos wget curl screen git samba vsftpd bash-completion ftp colordiff libkrb5-dev rar unrar unzip vnstat libssl-dev
  • 補足所需的套件
$ time apt install gnome-devel libx11-dev flex bison qt5-qmake libjpeg-dev libxslt1-dev libglu1-mesa-dev freeglut3-dev prelink libasound2-dev libfreetype6-dev libpng-dev libxml2-dev libxrender-dev libgl1-mesa-dev libgphoto2-dev libmpg123-dev libtiff-dev libpulse-dev liblcms2-dev libcapi20-dev libldap-dev libopenal-dev libv4l-dev libsane-dev libcups2-dev libgsm1-dev libosmesa6-dev libgnutls28-dev libpcap0.8-dev oss4-dev libcdk5-dev libgstreamer-plugins-base1.0-dev libarrayfire-opencl-dev
$ time apt install libsdl2-dev libvulkan-dev
  • 清除一下apt-get抓下來的殘餘檔
$ apt clean
  • 用root帳號登入
  • 先把Wine的git repository上的code拉下來!
$ mkdir -pv /root/packages ; cd /root/packages
$ time git clone https://github.com/wine-mirror/wine

  • 檢查套件是否足夠
$ cd ./wine
$ ./configure 

 #訊息大概剩下下面這樣,就差不多了。
configure: MinGW compiler not found, cross-compiling PE files won't be supported.
configure: libhal development files not found, no legacy dynamic device support.
configure: libFAudio development files not found, XAudio2 won't be supported.
configure: vkd3d development files not found (or too old), Direct3D 12 won't be supported.
  • 接下來編譯並且安裝!編譯會花大約40-60分鐘
$ time make
$ time make install
  • 接下來安裝winetricks!直接從github wget下來就可以用了!
$ mkdir -pv /opt/bin ; cd /opt/bin
$ wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
$ chmod +x ./winetricks
$ ./winetricks -V  

#檢查版本,出現下列訊息就沒問題了
20190615-next - sha256sum: 47304e177f259d6f9c05af01ab42c06531fd8a9716e2751d2fadcd664130feea

Wine 使用 SKCOM api

  • 設定Wine的windows環境,在 XWindow環境下。第一次使用須初始化一個windows 環境,打開Terminal,執行以下指令以設定Wine的環境!我的環境是建立在 ~./home/使用者/.wine 下,.wine 就是windows 虛擬的系統,底下有個 drive_c 資料夾,等於 C:\  槽
$ wineboot  

  • 群益API的SKCOM.dll檔需要 VC++ 2010可轉散發套件, 可透過winetricks來安裝 vcrun2010
$ winetricks vcrun2010 

  • 下載群益API,將API 資料夾 CapitalAPI_2.13.22 下的x86 資料夾搬到 ~/.wine/drive_c/skcom/x86  這等於是存在 windows 的 C:\\skcom\\x86, 之後使用python 呼叫會方便一點
  • cd 到 ~/.wine/drive_c/skcom/x86資料夾下,執行以下指令以註冊群益API:
$ regsvr32 ./SKCOM.dll

drive_c 下路徑的內容,skcom, python, strategy 是我自己創建的,資料夾名稱不要有空格,減少麻煩



wine下的 python環境

  • 用wine 來安裝 windows版的 python
  • 到 python 官網,我選了 Python3.8.3 的 Windows x86 executable installer 這個版本下載
  • 我有嘗試使用miniconda,但 conda 或 pip 位置不在預設路徑上,我搞不定,導致python套件裝不起來  

#使用 wine安裝windows版的python
#會有GUI跳出,可將python裝在 C:\\python 路徑下
$ wine python-3.8.3.exe   

#安裝 comtypes 及 pywin32 套件,其他python套件也可以如此安裝
$ wine pip install comtypes pywine32    


  • wine的windows版的 python 環境建置完成,可以開始 CODING!!
$ wine python



將寫好的 Script.py 交由 window python 執行, 要加wine 不然會呼叫到 linux系統下的 python, 兩個系統還是不相容的

$ wine python Script.py

附上 Script.py 的內容


import pythoncom, time, os
from comtypes.client import GetModule, GetEvents, CreateObject
from datetime import datetime

#第一次使用需要將 SKCOM 包成python 的package
#SKCOM.dll 在linux 下,我是放在 ~./home/yi/.wine/driv_c/skcom/x86/SKCOM.dll
#但在 wine 下,是放在下列路徑, drive_c 就是windows的C槽
GetModule(r'C:\\skcom\x86\SKCOM.dll')
#GetModule會在comtypes.gen 下產生 SKCOMLib package, 之後就用下面方式引用
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)

#輸入身分證與密碼
ID=''
PW=''
#股票代號
strStock="TX00" 

print(str(datetime.now())[0:-4], 'ID & PW entered')

#建立事件類別
class skQ_events:                                
    def OnConnection(self, nKind, nCode):
        print(datetime.now(), 'OnConnection', nKind, nCode)
        if nKind == 3003:
            #nKind==3003 表連線報價主機就緒
            print("quoate server connected..., nkind= ", nKind)
            ncode=skQ.SKQuoteLib_RequestStocks(1, strStock)
            if ncode==0:
                print(strStock, 'requested')    
    
    def OnNotifyQuote(self, sMarket, sIndex):
        ts=sk.SKSTOCK()
        skQ.SKQuoteLib_GetStockByIndex(sMarket, sIndex, ts)
        print(ts.bstrStockName, ts.bstrStockNo,  ts.nClose/10**ts.sDecimal)
    
class skR_events:
    def OnReplyMessage(self, bstrUserID, bstrMessage, sConfirmCode=0xFFFF):
        print('OnReplyMessage', bstrMessage)
        return sConfirmCode
                            
#Event sink, 事件實體  
EventQ=skQ_events()
EventR=skR_events()

#make connection to event sink
ConnectionQ = GetEvents(skQ, EventQ)
ConnectionR = GetEvents(skR, EventR)

if __name__=='__main__':
    #登入
    nCode=skC.SKCenterLib_Login(ID, PW)
    print("Login,", skC.SKCenterLib_GetReturnCodeMessage(nCode))
    #連線報價主機
    print(f"{datetime.now()}, EnterMonitor,", skC.SKCenterLib_GetReturnCodeMessage(skQ.SKQuoteLib_EnterMonitor()))
    # Event loop, 持續檢查有沒有event產生
    pythoncom.PumpMessages()



輸出結果,大概類似下圖,夾雜很多 fixme的警告,但不影響使用







2020年4月27日 星期一

群益API 2.13.22 登入海期報價主機錯誤

最近群益API更新,有好多小bug, 搞得好頭大...

用python呼叫群益API 2.13.22 登入海期報價主機發生錯誤, 會出現

OSError: exception: access violation writing 0x000000000000009C

經多方詢問後, 應該是api bug, 下個版本應該就會修正. 目前非官方的解法,創建 skcom 元件的時候,將海期及海選元件同時建立即可。目前測試可以 正常SKOSQuoate_Entermonitor(), 其他的還沒試過,給大家試試看吧。也不知道其他語言會有這個問題嗎?

skOSQ = CreateObject(sk.SKOSQuoteLib, interface=sk.ISKOSQuoteLib)
# 只要多下面這列就可以正常使用了
skOOQ = CreateObject(sk.SKOOQuoteLib, interface=sk.ISKOOQuoteLib)



2019年10月13日 星期日

群益api 選擇擇權代碼規則

群益API 選擇權代碼規則
感謝 FB 網友提供

Call option : A~L代表1~12月
Put option  : M~X代表1~12月。
群益的編碼邏輯都是 TX+@+strike+$+到期年分。 

@:  可以是O代表一般月結算的選擇權,若以是數字則代表為 1~4 的週選。
$  : 是選擇權到期的月份,所以call跟put是不同的。

ex.
TXO10700L2     台指選, 履約價 10700,  12 月, 2022年 的 call  
TXO10700X2     台指選, 履約價 10700, 12 月, 2022年 的 put

TXO14800A3      台指選, 履約價 14800,  1 月, 2023年 的 call  
TXO14800M3     台指選, 履約價 14800,  1 月, 2023年 的 put

TX213000L2 台指週選 W2, 履約價 13000,  12 月, 2022年 的 call
TX213000X2    台指週選 W2, 履約價 13000,  12 月, 2022年 的 put



Ref:

2019年7月27日 星期六

群益API python 下單範例

今天來示範下單, 請務必搞懂每個參數後在下單喔
我自己不放心所以去申請了模擬平台帳號,在來試試看下單的功能,不過模擬帳號目前沒有提供夜盤的功能,就加減用吧!! 之前介紹模擬平台的文章,大家參考一下囉
模擬平台有練功跟競賽兩種帳號,我沒有研究,隨便拿一個來用



 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
from comtypes.client import GetModule, CreateObject, GetEvents
GetModule('C:\\skcom\\CapitalApi_2.13.17\\x64\\SKCOM.dll')
import comtypes.gen.SKCOMLib as sk
from datetime import datetime
import getpass

#建立物件,避免重複 createObject
#登錄物件
if 'skC' not in globals(): skC=CreateObject(sk.SKCenterLib, interface=sk.ISKCenterLib)
#下單物件
if 'skO' not in globals(): skO=CreateObject(sk.SKOrderLib , interface=sk.ISKOrderLib)   
#回報物件
if 'skR' not in globals(): skR=CreateObject(sk.SKReplyLib , interface=sk.ISKReplyLib)   

#輸入身分證與密碼

ID=''
PW=''
print(datetime.now(), 'ID & PW')

#建立事件類別             
class skO_events:
    def __init__(self):
        self.TFAcc=[]
        
    def OnAccount(self, bstrLogInID, bstrAccountData):
        strI=bstrAccountData.split(',')
        #找出期貨帳號
        if len(strI) > 3 :
            if strI[0] == 'TF' :
                self.TFAcc = strI[1]+strI[3]
            
class skR_events:        
    def OnReplyMessage(self, bstrUserID, bstrMessage, sConfirmCode=0xFFFF):
        '''API 2.13.17 一定要返回 sConfirmCode=0xFFFF'''
        print('skR_OnReplyMessage', bstrMessage)
        return sConfirmCode
    
    def OnData(self, bstrUserID, bstrData):
         #成交回報
        self.bstrOnData.append(datetime.now().strftime('%H:%M:%S,') + bstrData)
        strI = bstrData.split(",")
        print("skR_OnData", strI)
                        
    def OnNewData(self, bstrUserID , bstrData):
        print('skR_OnNewData', bstrData)

#Event sink, 事件實體
EventO=skO_events()
EventR=skR_events()

#make connection to event sink
ConnO = GetEvents(skO, EventO) 
ConnR = GetEvents(skR, EventR) 

print(datetime.now(), 'Making event objects')

%matplotlib auto
#登入模擬帳號
nCode=skC.SKCenterLib_ResetServer ("morder1.capital.com.tw")
print('set server to morder1.capital.com.tw', skC.SKCenterLib_GetReturnCodeMessage(nCode))

#login
nCode=skC.SKCenterLib_Login(ID,PW)
print('Login', skC.SKCenterLib_GetReturnCodeMessage(nCode))

#初始 Order 物件
nCode=skO.SKOrderLib_Initialize()
print("Initialize ", skC.SKCenterLib_GetReturnCodeMessage(nCode))

#初始 Cert by ID 物件,模擬平台不需要這個,會出現錯誤
nCode=skO.ReadCertByID(ID)
print("ReadCertByID ", skC.SKCenterLib_GetReturnCodeMessage(nCode))

#Get User TF Account
nCode=skO.GetUserAccount()
print("GetUserAccount ", skC.SKCenterLib_GetReturnCodeMessage(nCode), EventO.TFAcc)

#設定期貨單參數,請自行調整囉,注意參數的資料型別,例如 bstr開頭的是要輸入文字型態
#以下請再jupyter 裡用另外一個cell 跑
fo=sk.FUTUREORDER()
fo.bstrFullAccount=EventO.TFAcc      #TF 帳號
fo.bstrStockNo='MTX00'
fo.sBuySell=0                         #0 buy, 1 sell
fo.bstrPrice='10700'               #委託價格,「M」表示市價,{移動停損、MIT皆無須價格}
fo.nQty=1                              #交易口數
fo.sDayTrade=0                     #當沖0:否 1:是,可當沖商品請參考交易所規定。 
fo.sNewClose=2                     #新平倉,0:新倉 1:平倉 2:自動{新期貨、選擇權使用}
fo.sTradeType=1                    #0:ROD  1:IOC  2:FOK
fo.sReserved=0                     #盤別,0:盤中(T盤及T+1盤);1:T盤預約{新期貨、停損單使用}

#下單
nCode=skO.SendFutureOrder(ID, False, fo)
print(nCode)