Python 接群益API 收不到事件?先檢查這 4 行的順序
登入回 0,成功。掛事件,沒有例外。訂閱函式,回傳正常。
然後——什麼都沒發生。
這個問題最難的地方,是它沒有給你任何線索:沒有錯誤碼、沒有例外、沒有一個可以拿去搜尋的字串。你手上只有「它不動」這件事。

目錄
群益API 收不到事件,但每個函式都回傳成功?
群益API 收不到事件的時候,懷疑的順序通常是這樣的:
| 你會先懷疑 | 但是 |
|---|---|
| 是不是沒訂閱成功? | 訂閱函式回傳正常 |
| 是不是商品代碼寫錯? | 換一個確定存在的代碼,一樣沒反應 |
| 是不是盤後沒資料? | 盤中再試,還是沒有 |
| 是不是權限問題? | 登入回 0,事件也掛上去了 |
四個方向都排除之後,多數人會回頭再讀一次自己的訂閱邏輯——而那段程式碼是對的。
問題不在你寫的任何一行,在一個你沒有寫、也看不見的地方:整個行程的 COM 執行緒模式。
為什麼 C# 的人不會遇到這個問題?
這是群益API 收不到事件會卡很久的原因之一:你搜尋不到這個問題。
網路上關於這套元件的範例以 C# 為主。而 C# 的視窗程式(WinForms、WPF)自帶訊息迴圈——它的 UI 執行緒本來就是一個正常運作的 STA,這件事由框架處理掉了,寫程式的人不需要知道它存在。
所以同一套元件,在 C# 下不會遇到這個狀況,自然也不會有人寫文章討論它。
如果你用 Python 卡在這裡,那不是你做錯了什麼,是你用的語言沒有幫你處理這一層。 這個認知本身就值得先講——它可以讓你停止懷疑自己的訂閱邏輯,把注意力移到對的地方。
STA 與 MTA:官方怎麼說
要理解群益API 收不到事件的檢查點,先看 COM 的執行緒模型。COM 把執行緒分成兩種 apartment 模式,微軟官方文件的對照如下:
| 模式 | CoInitializeEx 旗標 | 官方建議使用時機 |
|---|---|---|
| STA(單一執行緒 Apartment) | COINIT_APARTMENTTHREADED | 執行緒有訊息迴圈(例如 UI 執行緒),或所用的 COM 物件需要訊息幫浦 |
| MTA(多執行緒 Apartment) | COINIT_MULTITHREADED | 執行緒做背景工作、沒有訊息迴圈,且 COM 物件是執行緒安全或 agile 的 |
官方另有一段關於 STA 的重要提醒:STA 執行緒必須抽送訊息;如果 STA 執行緒在沒有抽送訊息的情況下阻塞等待,送進該 apartment 的 COM 呼叫就永遠不會被派送。
讀到這裡,很自然會想:那原因是不是就是沒有抽送訊息?
不是。 comtypes 提供的 PumpEvents 正是一個訊息抽送迴圈——也就是說,下一節要講的實測環境符合官方這段的要求,事件卻依然沒有進來。
官方這段說明並不足以解釋我們觀察到的現象。 把它寫出來,一方面是因為它是理解 STA/MTA 的必要背景,另一方面是要先把「是不是沒抽送訊息」這條路堵起來——不要往那個方向查,那裡沒有答案。
實測:在這個組合下,群益API 收不到事件
先把條件講清楚,因為這是單一環境的一次觀察,不是反覆驗證過的通則:
| 項目 | 版本 |
|---|---|
| SKCOM | 2.13.58 x64 |
| Python | 3.12 |
| comtypes | 1.4.16 |
在這個組合下,群益API 收不到事件的具體樣貌是:
- comtypes 預設走 STA,並提供
PumpEvents作為訊息抽送迴圈。 - 在這個預設組合下,事件完全收不到。
- 而且可以確認掛載是成功的——advise 沒有失敗,登入也回
0。 - 改成 MTA 之後,事件就正常進來了。
至於為什麼 STA 搭配訊息抽送迴圈會收不到,我們沒有查明。 上一節已經說過,官方那段解釋不了它。這裡只陳述觀察到的現象與有效的處理方式,不推測機制——因為推測出來的機制聽起來會很合理,而合理跟正確是兩件事。
也因為只有一次單一環境的觀察,這篇不會告訴你「Python 接群益API 一定要用 MTA」。準確的說法是:在上面那個版本組合下必須設成 MTA,其他組合我們沒有驗證過。
解法:這四行的順序決定它生不生效
import sys
# 必須在 import comtypes 之前設定,否則不生效,而且不會報錯
sys.coinit_flags = 0x0 # 0x0 = COINIT_MULTITHREADED
import comtypes.client解決群益API 收不到事件的關鍵就在這四行,而重點不在語法,在順序。
sys.coinit_flags 必須在 import comtypes 之前設定。comtypes 在匯入的當下就依這個值完成初始化——設晚了,它不會生效。
而最麻煩的是:設錯順序不會有任何錯誤訊息。 程式照跑、匯入成功、後面每一個函式也都回傳正常,然後你又回到文章開頭那個狀態——什麼都沒發生。
這是一個無聲失敗,套在另一個無聲失敗上面。 如果你已經知道要設 MTA、也寫了那一行,群益API 收不到事件的狀況卻還在,先檢查那行在不在 import comtypes 前面。
改成 MTA 之後,等待事件不要再用 PumpEvents
換成 MTA 就不需要訊息抽送迴圈了。等待事件的方式改成輪詢 sink 上的旗標,讓事件在背景被派送進來:
import time
# MTA 下不需要 PumpEvents,事件會在背景被派送進來
class QuoteSink:
def __init__(self):
self.received = False
# 官方簽名:OnConnect(int nCode, int nSocketCode)
def OnConnect(self, nCode, nSocketCode):
self.received = True # 回呼只做最輕量的標記
sink = QuoteSink()
connection = comtypes.client.GetEvents(quote_lib, sink)
# 用輪詢等待,不要在這裡阻塞住
timeout = time.time() + 10
while not sink.received and time.time() < timeout:
time.sleep(0.1)注意回呼裡只做了一件事:把旗標設起來。這不是為了讓範例簡單,而是下一節的紀律。
另外,登入之前必須先註冊 OnReplyMessage,否則 SKCenterLib_Login 會回 2017——這一條 C# 與 Python 一致,差別只在輸出參數的映射方式(Python 的 comtypes 以回傳值對應,寫 return -1)。這部分在〈群益API 是什麼〉講過,本篇不重述。
MTA 不取代回呼裡的那四條紀律
最後一件事,也是最容易被誤會的:設成 MTA 解決的是群益API 收不到事件這個問題,不解決「回呼裡能做什麼」。
〈群益API 事件回呼跑在哪個執行緒〉那四條紀律照樣適用——不要在回呼裡更新畫面、不要呼叫耗時查詢、不要阻塞等待、不要重入元件。上面範例的回呼只設一個旗標,就是這個原因。
而且在 MTA 下還要更小心一件事:依 MTA 的定義,該 apartment 裡的物件可以被那個 apartment 的任何執行緒直接呼叫,也就是回呼可能跑在任意一條執行緒上。跨執行緒的資料保護要做得比 STA 下更嚴謹。
(這一點是從官方對 MTA 的定義推導出來的,不是我們量測的結果。)
常見問題
群益API 收不到事件,但登入和訂閱都成功,是哪裡寫錯了?
不一定是你寫錯。在 Python 端有一個常被忽略的檢查點:行程的 COM 執行緒模式。實測在 SKCOM 2.13.58 x64 + Python 3.12 + comtypes 1.4.16 的組合下,預設的 STA 收不到事件,改成 MTA 之後就正常。
加上 PumpEvents 訊息迴圈就能收到事件嗎?
在上述那個組合下實測是收不到的。要注意 PumpEvents 本身就是訊息抽送迴圈——也就是說,那個環境符合微軟文件對 STA 的要求,事件仍然沒有進來。原因我們沒有查明。
為什麼網路上查不到這個問題?
關於這套元件的範例以 C# 為主,而 C# 的視窗程式自帶訊息迴圈,UI 執行緒本來就是正常運作的 STA,不會遇到這個狀況。
sys.coinit_flags 我寫了,為什麼還是沒用?
檢查它在不在 import comtypes 前面。comtypes 在匯入的當下就依這個值初始化,設晚了不會生效,而且不會有任何錯誤訊息。
改成 MTA 之後,回呼裡就可以放心做事了嗎?
不行。MTA 解決的是事件進不進得來,回呼裡的四條紀律沒有改變;而且 MTA 下回呼可能跑在任意執行緒上,跨執行緒的資料保護要更小心。
風險揭露
期貨與選擇權屬高槓桿商品,價格波動可能造成超過原始保證金的損失,交易人須自負交易責任。本文為程式開發技術教學,說明 Python 端 COM 執行緒模式的設定與檢查方式,不構成投資建議,也不保證任何交易結果。程式化交易並不降低市場風險,反而可能因程式錯誤造成非預期的委託行為——本文描述的無聲失敗正是這類風險的來源之一。
投資人教育資源
| 機構 | 資源 |
|---|---|
| 臺灣期貨交易所(TAIFEX) | 期貨及選擇權數位學習網 |
| 證券暨期貨市場發展基金會 | 證券期貨市場教育推廣 |
| 金融智慧網 | 金管會金融知識平台 |
| 中華民國期貨業商業同業公會 | 期貨業法規與宣導 |
| 證券投資人及期貨交易人保護中心 | 投資人保護與申訴 |
延伸閱讀
- 〈群益API 事件回呼跑在哪個執行緒〉——回呼裡不能做的四件事;排除群益API 收不到事件之後,接著要守的就是那四條。
- 〈群益API 是什麼〉——COM、STA、Interop 組件與
OnReplyMessage的輸出參數映射都在那篇定義過。
參考資料
- Processes, Threads, and Apartments – Microsoft Learn(STA/MTA 的定義、
CoInitializeEx旗標、STA 需抽送訊息的說明) - 本篇核心現象(該組合下 STA 收不到事件、MTA 正常)為 2026-07-18 單一環境實測,非官方文件記載,亦未經多環境驗證;其機制未查明。
- 「MTA 下回呼可能跑在任意執行緒」為官方 MTA 定義的推導,非實測結果。
免責聲明
本文章僅作為群益API實作經驗分享,不構成投資建議,且策略及程式皆應自行撰寫。期貨及衍生性金融商品交易屬高風險投資,請謹慎評估自身風險承擔能力。







