標題(建議)
list_trades() occasionally returns a phantom "PendingSubmit" trade with empty ordno that never resolves and cannot be cancelled
環境
- shioaji 1.7.0
- Python 3.12
- 正式帳戶(
simulation=False),期貨帳戶(futopt_account)
- 商品:微型臺指期貨(TMF)
問題描述
list_trades() 偶爾會回傳一筆狀態為 PendingSubmit 的委託紀錄,具有以下特徵:
ordno(交易所委託單號)欄位是空字串——正常委託(不論 pending 或已成交)這個欄位一律有值
- 在短時間內(約 1 秒內)反覆呼叫
update_status(account) + list_trades() 重新查詢,這筆紀錄完全沒有任何變化(ordno 持續空白、deal_quantity/cancel_quantity 持續為 0、狀態不變)
- 對這筆委託呼叫
cancel_order(trade) 會失敗,回傳:
StatusCode: 400, Detail: Please run update_status first to get trade details.
即使呼叫 cancel_order() 之前已經呼叫過 update_status()
- 這筆委託在永豐的看盤 App/實際帳戶介面上完全不存在——使用者直接用 App 查詢委託明細,找不到對應的真實委託
- 這次發生時,前後數分鐘內沒有任何連線中斷/重連事件(已排除跟斷線重連相關)
由於我們的程式邏輯會把 list_trades() 回傳的 pending 委託口數計入部位計算(用來決定要補下多少口),這筆幽靈委託導致程式誤判「還有 1 口買單掛著」,因而多算了應該補償的賣出口數,造成實際交易口數跟預期不符,需要人工介入修正。
重現資料(正式環境真實 log,已去除帳號識別資訊)
幽靈委託(連續查詢 3 次,狀態完全凍結):
[broker] pending-check id=9338d51f ordno= action=Action.Buy qty=1 deal_qty=0 cancel_qty=0 status='PendingSubmit'
[broker] pending-check id=9338d51f ordno= action=Action.Buy qty=1 deal_qty=0 cancel_qty=0 status='PendingSubmit'
[broker] cancel_order error: StatusCode: 400, Detail: Please run update_status first to get trade details.
[broker] pending-check id=9338d51f ordno= action=Action.Buy qty=1 deal_qty=0 cancel_qty=0 status='PendingSubmit'
(三次查詢間隔約 1 秒,每次查詢前都呼叫過 update_status(account))
對照組:同一套查詢邏輯觀察到的正常委託(有 ordno、正常走完生命週期):
[broker] pending-check id=84a3a27c ordno=vn021 action=Action.Buy qty=1 deal_qty=0 cancel_qty=0 status='Submitted'
...(後續)...
[broker] pending-check id=84a3a27c ordno=vn021 action=Action.Buy qty=1 deal_qty=1 cancel_qty=0 status='Filled'
呼叫程式碼(Python,簡化版)
def _get_pending_tmf_trades(self):
self._api.update_status(self._api.futopt_account)
result = []
for trade in self._api.list_trades():
code = getattr(trade.contract, "code", "")
if not code.startswith("TMF"):
continue
status = trade.status.status
status_val = str(getattr(status, "value", status))
if status_val not in {"PendingSubmit", "PreSubmitted", "Submitted", "PartFilled"}:
continue
result.append(trade)
return result
想請教維護者的問題
list_trades() 在什麼情況下會回傳一筆 status='PendingSubmit' 但 ordno 是空字串的紀錄?是否為某種本地端佇列/快取殘留,而非交易所端真實存在的委託?
cancel_order() 對這類紀錄回報「Please run update_status first」,是否就是 SDK 內部用來標示「這筆紀錄資料不完整/不是即時同步狀態」的預期行為?
- 有沒有建議的方式可以可靠地判別/過濾掉這類幽靈紀錄(例如是否可以信任「
ordno 為空」這個判斷依據,還是有其他更準確的欄位)?
- 這個現象是否為已知問題,有沒有其他使用者回報過類似狀況?
補充:這次事故不是唯一一次
我們在 2026-07-29 也遇過類似情況(同一套邏輯偵測到一筆來源不明、口數為 +3 的 pending 委託,當時尚未加上詳細診斷 log,無法確認 ordno 是否同樣為空,但行為模式一致:刪不掉、使用者帳戶介面查無此委託)。這次(2026-08-12)是第一次能明確記錄到 ordno 為空這個特徵。
標題(建議)
list_trades()occasionally returns a phantom "PendingSubmit" trade with emptyordnothat never resolves and cannot be cancelled環境
simulation=False),期貨帳戶(futopt_account)問題描述
list_trades()偶爾會回傳一筆狀態為PendingSubmit的委託紀錄,具有以下特徵:ordno(交易所委託單號)欄位是空字串——正常委託(不論 pending 或已成交)這個欄位一律有值update_status(account)+list_trades()重新查詢,這筆紀錄完全沒有任何變化(ordno持續空白、deal_quantity/cancel_quantity持續為 0、狀態不變)cancel_order(trade)會失敗,回傳:cancel_order()之前已經呼叫過update_status()由於我們的程式邏輯會把
list_trades()回傳的 pending 委託口數計入部位計算(用來決定要補下多少口),這筆幽靈委託導致程式誤判「還有 1 口買單掛著」,因而多算了應該補償的賣出口數,造成實際交易口數跟預期不符,需要人工介入修正。重現資料(正式環境真實 log,已去除帳號識別資訊)
幽靈委託(連續查詢 3 次,狀態完全凍結):
(三次查詢間隔約 1 秒,每次查詢前都呼叫過
update_status(account))對照組:同一套查詢邏輯觀察到的正常委託(有
ordno、正常走完生命週期):呼叫程式碼(Python,簡化版)
想請教維護者的問題
list_trades()在什麼情況下會回傳一筆status='PendingSubmit'但ordno是空字串的紀錄?是否為某種本地端佇列/快取殘留,而非交易所端真實存在的委託?cancel_order()對這類紀錄回報「Please run update_status first」,是否就是 SDK 內部用來標示「這筆紀錄資料不完整/不是即時同步狀態」的預期行為?ordno為空」這個判斷依據,還是有其他更準確的欄位)?補充:這次事故不是唯一一次
我們在 2026-07-29 也遇過類似情況(同一套邏輯偵測到一筆來源不明、口數為 +3 的 pending 委託,當時尚未加上詳細診斷 log,無法確認
ordno是否同樣為空,但行為模式一致:刪不掉、使用者帳戶介面查無此委託)。這次(2026-08-12)是第一次能明確記錄到ordno為空這個特徵。