停損執行不該靠「記得」,該靠「忘了會被擋」

停損執行不該靠「記得」,該靠「忘了會被擋」

家裡瓦斯爐有定時自動斷氣裝置,不是因為屋主特別健忘,而是因為「記得關火」這件事本來就不該是防護線。同樣的道理,放進交易系統之後,大多數流程設計上還是會留一個洞:讓 agent 記得做停損檢查。

51,056 元的對帳差異就是這樣來的。

現象

本地快取顯示五檔持倉已平倉,資料庫那頭卻還記錄為持有中。兩本帳差了 51,056 TWD,帳務完全不可信。表面上看,是某次 session 漏了一個寫入步驟。

回溯日誌之後,找到分界點:某次 session 確實對三筆停損賣出完成了執行——成交價、股數都在逐字稿裡,白紙黑字。但只更新了本地 JSON,沒有寫入遠端資料庫。同一批操作還疊了兩個獨立錯誤:一筆回滾沒有還原現金,所有賣出都漏扣手續費。三個錯誤各自成立,疊在一起才讓帳本偏移到這個量級。

容易誤判的地方

第一時間的直覺是「agent 忘記做某個步驟」,於是想到的解法也是「提醒 agent 要記得」。這個診斷方向從一開始就偏了。

真正的問題不在某一次執行,而在整個停損流程的觸發機制:停損檢查依賴 agent 主動記得跑。只要流程的啟動點是「某個 session 想起來要做」,就永遠存在漏掉的機率。不管提醒再多次、在 SOUL 鐵則裡寫多清楚,都只是讓漏掉的機率從 100% 降到某個較小的數字,沒有降到零。

這種設計在低風險場景或許無所謂。在金流、交易、帳本這類有原子性要求的流程裡,「依賴記得」本質上就是未爆彈。

確認方式

把停損檢查抽成獨立排程工作流——不再等 session 觸發,每小時自動跑。然後在快照發布前強制加一道交叉驗證:讀取資料庫與本地快取的持倉和停損價,任何不一致就拒絕發布快照、發出告警;漂移超過 20 分鐘,stops_ok 自動設為 false,整個系統暫停。

這道機制上線前跑端到端測試,立刻抓到兩筆真實帳本漂移:一筆持倉漏記將近一週,另一筆是幻影股數。都是在「記得做」的體制下靜靜存在、沒被發現的問題。

留給未來的話

分界線在這裡:判斷類邏輯(停利時機、選股、展期)仍然適合留給 agent,因為那些本來就需要在模糊情境中做取捨。但執行類邏輯——停損觸發、帳本寫入、快照發布——每一個環節都必須是「不做到位就會被系統擋住」,而不是「希望有人記得」。

排程、強制驗證、fail-closed 三層疊在一起,才算把一個依賴記憶的流程改造成依賴結構的流程。少任何一層,剩下的兩層都只是讓問題晚一點爆。

— 邱柏宇


Stop-Loss Logic Shouldn’t Rely on Memory

The kitchen stove with an automatic gas shut-off timer exists not because the household is forgetful, but because “remember to turn off the gas” was never a serious safety mechanism to begin with. That same logic, applied to a trading system, reveals a structural gap that’s easy to miss until the ledger diverges by a number nobody can ignore.

What Happened

The local cache showed five positions as closed. The database showed them as still held. The discrepancy: 51,056 TWD. Two ledgers, one system, completely inconsistent.

Tracing back through session logs pinpointed the origin: a session that genuinely executed three stop-loss sells — with real execution prices recorded in the transcript — but only updated the local JSON file, never writing to the remote database. Stacked on top: one rollback that failed to restore cash, and every sell missing the brokerage fee deduction. Three independent errors, each valid on its own, compounding into a gap that made the ledger untrustworthy.

The Misdiagnosis Trap

The first instinct was “the agent forgot a step.” The natural follow-up was “remind the agent to remember.” Both are wrong.

The actual problem is that the entire stop-loss execution flow depended on an agent proactively remembering to trigger it. Any process whose starting point is “someone thought to do it this session” carries a non-zero miss rate by design. Reminders, written rules, and reinforced checklists lower that rate — they don’t eliminate it. In domains like trading, payments, or ACID-requiring ledger operations, a non-zero miss rate is the same as a structural failure waiting to surface.

The Fix That Actually Works

Stop-loss checking was extracted into a standalone scheduled workflow — no longer triggered by a session, running automatically on a fixed interval instead. A mandatory cross-validation gate was added before any snapshot publication: reads both the database and the local cache, compares positions and stop prices, and rejects publication if anything diverges. Any drift persisting beyond 20 minutes sets stops_ok to false and halts the system.

Running end-to-end tests before the system went live immediately surfaced two real ledger drifts that had been sitting quietly under the old regime: one position unrecorded for nearly a week, one phantom share count. Both invisible as long as the process depended on memory.

The Line Worth Remembering

Judgment-type logic — when to take profit, which stock to rotate into, whether to extend a position — still belongs to the agent. Those decisions require weighing ambiguous inputs and making tradeoffs. Execution-type logic — stop-loss trigger, ledger write, snapshot publication — needs to be structured so that an incomplete step is physically blocked, not merely discouraged.

Scheduled automation, forced cross-validation, and fail-closed behavior together turn a memory-dependent process into a structure-dependent one. Any one of those layers missing, and the other two are just delaying the next incident.

— 邱柏宇

延伸閱讀