Strasmore Research
學習 Matt Connor作者: Matt Connor · 更新於 2026-08-04

交易機器人的熔斷機制與每日虧損上限

了解交易機器人如何透過每日虧損上限及波動度調整部位,在異常交易時停止送單,降低單一交易時段的損失擴大風險。

交易機器人的交易熔斷機制,是指在達到既定限額後,阻止自動化策略繼續送出委託的規則。這些機制位於策略與券商之間的風險控管層,並會套用至每一筆委託,不論策略本身是否同意。策略決定交易標的與方向;風險控管層則決定是否允許交易發生。

這種分離正是整體設計的核心。由策略自行監控自身風險,代表在自身假設失效的當下,沒有獨立的檢查機制;而那正是最需要檢查的時刻。

交易機器人的斷路器作用

風險控管層包含四個部分。每一個部分都用來防止一種特定且常見的故障。

  • 硬性上限:限制部位規模、每一檔標的的名目曝險,以及下單頻率。這些上限能控制原本可能無限擴大的程式錯誤損失。
  • 回撤斷路器:當帳戶在本交易時段的跌幅達到既定金額,或從權益峰值回撤達到既定金額時,停止接受新訂單。
  • 按比例調整的下單規模:根據近期波動度,或依 Kelly bet 的一部分設定下單規模,而不是固定股數。即使市場波動區間持續變化,也能大致維持每筆交易的風險。
  • 僅可追加的稽核日誌:記錄每一項決策,包括遭風險控管層拒絕的訂單。這是唯一能區分「策略判斷錯誤」與「檢查程序根本未執行」的紀錄。

以下內容都屬於上述四個部分之一,並將其具體化。

交易機器人的合理每日虧損上限是多少?

每日虧損上限會在當日交易時段的虧損超過門檻後,停止送出新訂單。門檻的設定是校準問題,而不是偏好問題:若設在一般市場雜訊範圍內,機器人多數星期都會處於停用狀態;若設得遠高於一般波動,則幾乎永遠不會觸發。起點在於觀察市場本身以特定幅度下跌的交易日出現頻率。

查詢SPY按跌幅區分的下跌日數(按年),2018年至2026年7月
每個數據背後的精確 SQL 語法
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2017-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY d
),
with_prev AS (
    SELECT d,
           close_px,
           any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
    FROM daily
)
SELECT toYear(d) AS year,
       countIf(close_px / prev_close - 1 <= -0.01) AS down_1pct_days,
       countIf(close_px / prev_close - 1 <= -0.02) AS down_2pct_days,
       countIf(close_px / prev_close - 1 <= -0.03) AS down_3pct_days
FROM with_prev
WHERE prev_close > 0
  AND d >= toDate('2018-01-01')
GROUP BY year
ORDER BY year
Run this yourself

跌幅達 1% 或以上的交易日,在 20192020 中分別有 1545 個;一年約有 250 個交易日。跌幅達 3% 或以上的交易日則完全不同:2019 中有 0 個,2020 中有 16 個。9 的最後一列僅涵蓋截至 2026年7月31日的交易日。

這條分布線呈現的是不均勻的群聚,而非穩定的平均分布。這種群聚正是設計每日虧損上限時的關鍵。劇烈下跌的交易日往往會接連出現。若機器人在群聚的第一天停用、第二天便恢復交易,實際上並沒有真正停用。

兩種門檻各自發揮不同作用。每日虧損上限通常設為帳戶權益的 2%,用來結束當日交易。從權益高點計算的移動回撤上限通常約為 10%,達到後則停止策略,等待人工審查。前者是日常防護,後者預期很少觸發。若機器人只有每日虧損上限,帳戶可能每次下跌 2%,持續累積虧損,卻始終不會觸發任何其他停損機制。

波動率縮放如何改變部位規模?

波動率目標法會根據近期實現波動率,反向調整部位規模:當每日價格區間擴大一倍時,部位大致減半,讓每筆交易的美元風險維持在接近固定的水準。此處的實現波動率,是每日報酬率標準差的年化值;其變化幅度往往超出多數人的預期。

查詢SPY每月實現波動率,以及12%波動率目標所對應的持倉部位
每個數據背後的精確 SQL 語法
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2023-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY d
),
rets AS (
    SELECT d,
           close_px / any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) - 1 AS ret
    FROM daily
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
       round(stddevSamp(ret) * sqrt(252) * 100, 1) AS realized_vol_pct,
       round(least(100.0, 1200.0 / (stddevSamp(ret) * sqrt(252) * 100)), 1) AS vol_target_size_pct
FROM rets
WHERE d >= toDate('2024-01-01')
  AND isFinite(ret)
GROUP BY toStartOfMonth(d)
HAVING count() >= 15
ORDER BY toStartOfMonth(d)
Run this yourself

實現波動率以年化方式衡量,數值為 11.1%,出現在 2024-0112% 的 2026-07,涵蓋 31 個月。第二欄將每個讀值換算為採用 12% 波動率目標時的部位規模,並以完整部位為上限:相較於 99.7% 的 2026-07,為 100% 的 2024-01。策略相同、信念相同,但持有股數可能大不相同。

Kelly criterion 則從另一端處理相同問題,根據估計優勢與變異數決定部位規模,而不僅依賴波動率。多數系統化交易者只採用 Kelly criterion 的一部分,通常為 half Kelly 或 quarter Kelly,因為這兩項輸入值都是根據有限樣本估計而來。Kelly criterion 部位規模會說明相關計算方式。

為什麼交易機器人在停損後持續重新進場?

停損觸發,部位平倉。九十秒後,進場條件再次成立,機器人重新進場,再度承受相同虧損,如此反覆。沒有任何單一元件故障。策略依照設計執行,停損也依照設計執行,但帳戶仍逐趟交易持續失血。

交易頻率直接來自價格路徑。本面板按交易時段統計 SPY 從高於開盤價 0.1% 以上的位置,移動至低於開盤價 0.1% 以上的位置,或反向移動的次數。

查詢SPY每個交易日穿越自身開盤價的次數(按月)
每個數據背後的精確 SQL 語法
WITH mins AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           window_start AS ts,
           toFloat64(close) AS px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2025-08-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
),
opens AS (
    SELECT d, argMin(px, ts) AS open_px
    FROM mins
    GROUP BY d
),
zoned AS (
    SELECT m.d AS d,
           m.ts AS ts,
           multiIf(m.px >= o.open_px * 1.001, 1,
                   m.px <= o.open_px * 0.999, -1,
                   0) AS zone
    FROM mins AS m
    INNER JOIN opens AS o ON m.d = o.d
),
flips AS (
    SELECT d,
           zone,
           any(zone) OVER (PARTITION BY d ORDER BY ts ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_zone
    FROM zoned
    WHERE zone != 0
),
per_day AS (
    SELECT d, countIf(prev_zone != 0 AND zone != prev_zone) AS crossings
    FROM flips
    GROUP BY d
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
       round(avg(crossings), 1) AS avg_crossings_per_session,
       max(crossings) AS max_crossings_in_a_session
FROM per_day
GROUP BY toStartOfMonth(d)
ORDER BY toStartOfMonth(d)
Run this yourself

SPY 在 2025-08 每個交易時段平均穿越該區間 0.7 次,並在 2026-07 平均穿越 1.5 次;其中有一個交易時段在 2026-07 記錄到 5 次穿越。任何在價格位階一側開倉、另一側停損的規則,單日都有同樣多次的觸發機會。

四項機制可以抑制這種情況。

  • 每次停損後設定冷卻期,以分鐘或 K 棒計算;在此期間,該標的不得有新訂單通過風險控管層。
  • 設定單一標的的每日交易次數上限,將無限循環轉為有上限的循環。
  • 設定具鎖存功能的暫停旗標。每日虧損上限一旦觸發,旗標就會維持啟用,直到人員手動清除。
  • 將該旗標持久化儲存在程序記憶體之外。監督程序重新啟動當機的交易機器人時,若交給它一個全新的狀態,就會繞過這個旗標原本要防止的情況。

最後一項最容易被忽略,即使其他措施都已正確實施。網格交易機器人 本來就會分層掛出多筆訂單,因此交易次數上限是核心控制機制,而不是裝飾性設定。

當機器人依據過時的價格資料流交易時,會發生什麼事?

停止更新的報價看起來仍然是一個數字。機器人讀取該報價,據此為委託定價,然後將委託送進已經變動的市場。這類故障通常不易察覺:系統不會拋出例外,也不會記錄錯誤;只有事後才會發現成交結果異常。

最容易清楚量化的情況是隔夜跳空。此時,已知價格在數小時內維持不變,但可交易價格持續變動。

查詢隔夜跳空:前一日收盤價至次日開盤價,6檔標的,2024年1月至2026年7月
每個數據背後的精確 SQL 語法
WITH daily AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMin(toFloat64(open), window_start) AS open_px,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'KO', 'MSFT', 'AAPL', 'NVDA', 'TSLA')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2024-01-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, d
),
gaps AS (
    SELECT ticker,
           d,
           open_px,
           any(close_px) OVER (PARTITION BY ticker ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
    FROM daily
)
SELECT ticker,
       round(quantileDeterministic(0.5)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS median_gap_pct,
       round(quantileDeterministic(0.95)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS p95_gap_pct,
       round(max(abs(open_px / prev_close - 1) * 100), 2) AS max_gap_pct
FROM gaps
WHERE prev_close > 0
GROUP BY ticker
ORDER BY p95_gap_pct DESC
Run this yourself

以第95百分位跳空幅度計算,幅度最大的標的為 TSLA,達 4.41%;相較之下,KO1%。一般夜間的波動小得多:兩者的跳空中位數分別為 1.01% 與 0.24%。風險控管層的設計,就是為了處理這些尾端情境;在所測量的期間內,TSLA 出現的單次最大跳空為 14.57%。這些就是機器人依據一段時間前讀取的價格行動時可能面臨的價差。為什麼股票會在隔夜跳空說明了其中的運作機制。

防禦措施成本低廉。為每一筆風險控管層將據以定價的報價設定最長允許存續時間;對日內策略而言,通常是幾秒。除資料本身外,也要個別接收資料流的心跳訊號,以區分連線無回應與市場交投清淡。應將資料缺失視為停牌,而不是持續持有原值,因為機器人在沒有價格的情況下,也無法評估出場條件。

風險層應設定哪些硬性上限?

  • 單一標的的最大名目金額,占帳戶權益的比重。設定10%的上限,可避免單一標的出現重大虧損時拖累整個帳戶。
  • 所有未平倉部位的最大總名目金額。將上限設為權益的100%,代表不使用槓桿。這項決策應明確訂定,而不是沿用券商的預設值。
  • 每分鐘及每日的最大下單筆數。每分鐘10筆對多數零售策略而言已相當寬鬆,同時仍能限制失控迴圈在一分鐘內的影響。
  • 單筆訂單金額上限,占該標的平均每日成交量的比重。設定1%的上限,可避免交易機器人推動自己試圖交易的價格;平均每日成交量就是分母。

上述每一項都應歸入風險層,而非策略層;在回測、紙上交易與實盤交易中,也都應執行相同的程式碼路徑。只有實盤交易才存在的限制,就是從未經過測試的限制。

交易機器人的稽核日誌需要記錄哪些內容?

僅可附加的日誌會為每項決策寫入一筆紀錄,且從不修改或刪除。每筆紀錄都應包含時間戳記、所採用的報價及其時效、所有已執行的限額檢查及各自的判定結果、送出的委託,以及券商的回覆。遭拒的委託與成交委託應以同等重要性記錄。

重建決策過程才是重點。糟糕的交易時段過了六週後,問題從來不是損益是多少,而是哪項檢查通過,以及當時採用了什麼輸入。若沒有記錄輸入,最後就只能根據市場狀態重新推導機器人的狀態。這與回測中的 前視偏誤 是同一種錯誤:使用系統在決策當下尚未掌握的資訊。

riskguard 專案是這種分離設計的一項開源實作。它將限額檢查放在策略呼叫的元件中,而不是把邏輯分散在策略本身。這只是多種設計之一,值得閱讀,但不宜未經評估就直接採用。無論依賴哪個專案,都應固定使用標記版本,而不是預設分支。同一項回測若分兩次執行,分支內容可能已經改變;而悄悄變動的風險層,甚至比沒有風險層更糟。

為何首次部署會在模擬交易券商上運行

券商介接器預設使用模擬交易環境,而實盤交易則必須明確設定旗標。這項設計是為了避免一個常見但嚴重的錯誤:複製設定檔,或未被覆寫的環境變數,導致系統以真實資金送出實際訂單。

模擬交易也會產生一項重要成果:在即時價格上,透過與實盤相同的風險層所建立的決策紀錄。這份紀錄能顯示哪些限制條件被觸發、哪些未被觸發。它可用來驗證風險層,但這與策略能否獲利是兩個不同問題。投入真實資金前先進行模擬交易說明模擬交易紀錄能證明什麼、不能證明什麼;多代理 AI 交易系統則說明,當多個代理都能下單時,停止交易的權限為何必須置於所有代理之外。

交易機器人斷路器常見問答

交易機器人中的斷路器是什麼?

這是風險控制層中的一項規則。當達到設定的限制時,規則會停止機器人送出新訂單。最常見的限制是單日虧損門檻,或帳戶權益相對於峰值的回撤。它獨立於交易策略運作,會套用至每筆訂單,且在解除條件成立前維持觸發狀態。

市場多久會出現一次下跌2%的交易日?

SPY 在 20195 個交易日下跌至少2%,而 2020 的相同交易日數為 25;每年約有250個交易日。平靜年份與壓力年份之間存在這種差異,因此虧損限制應根據歷史資料校準,而不是憑直覺設定。

如何避免機器人在停損後重新進場?

每次停損後設定冷卻期間,並限制每個標的的單日交易次數,就能將無上限的迴圈轉為有界流程。停止交易的旗標也必須鎖定,並持久化儲存在程序記憶體之外。否則,監控程式重新啟動當機的機器人時,會將它恢復為全新的未停止狀態。

機器人如何判斷價格資料是否已經過時?

機器人應在依據報價為訂單定價前,檢查每筆報價的資料年齡,並將資料流的心跳訊號與資料內容分開監控。隔夜跳空顯示了過時價格可能掩蓋的幅度:2024年1月至2026年7月期間,隔夜價格變動的第95百分位在 TSLA 達到 4.41%。

小型交易機器人真的需要稽核日誌嗎?

成交日誌會記錄實際發生的交易。決策日誌則會記錄機器人認為自己獲准執行的操作。只有後者能協助區分錯誤的策略與根本未執行的風險檢查。採用僅追加寫入的形式,並納入遭拒訂單,是最低限度且具實用價值的版本。


以上每個數值都來自以分鐘線資料執行的儲存查詢,每個面板都能開啟其背後的 SQL。你也可以在 Strasmore 終端機上,將相同查詢套用至自己的標的清單。

#risk-management#trading-bots#drawdown#position-sizing#automation