早餐店的帳本前半段用台斤記進貨,後半段改用公克,沒有人在切換那天做任何標記。帳本裡每個數字格式看起來一模一樣,加總也能算出結果,直到某天看到「豬油進貨 3000」才開始懷疑——是三千台斤還是三千公克?差距是三百倍,但帳本本身絕對不會報錯。
投資追蹤系統某天對一支日股 ETF 發出警報:今日收盤價比 200 日均線低了將近九成,觸發停損邏輯。日本市場那天沒有任何異常消息。追查後發現,那支 ETF 在本季剛完成一比十的股票分割。
今天的數字和昨天的尺
常用的報價 API 在當日查詢端回傳的是分割後的名目價格,未經調整。但同一個 API 的歷史資料序列卻是還原權值後的調整價格。兩套不同尺度的數字被靜默地餵進同一個均線計算式。結果自然是把雜訊當成信號。
API 回應格式正確。程式邏輯沒有問題。HTTP 狀態碼 200。JSON schema 驗證通過。唯一錯的是數據源在「今天」和「歷史」之間默默換了計量單位,而且不會有任何錯誤訊息提示。
沒有壞掉的系統
這類問題在表面上極難察覺。你的測試案例不會失敗,因為你測的是格式和連線,不是數據源的前後一致性。你的監控不會報警,因為 API 延遲正常、返回值有效。你的日誌看起來一切正常,除了那個九成跌幅的異常觸發——而那通常會被歸類為市場異常,不是系統問題。
問題是,這不是 API 壞了。這是 API 供應商在某個時間點改變了數據處理邏輯,可能是為了配合新的會計準則、可能是為了對齊其他市場的慣例、可能只是因為某個內部重構。他們不會發公告,因為在他們的角度,這只是「優化」。
解法不是修 API
最後的解法不是去修 API 的數據,也不是寫一個補丁去偵測股票分割事件。而是改用在美股掛牌的同市場代理 ETF——ADR 版本。那支 ETF 沒有經歷同一次分割,數據口徑始終保持一致。
這不是技術上最優雅的解法。但它是唯一不需要持續監控上游數據源行為的解法。當你無法控制數據源的穩定性,你只能選擇不依賴它。
下次當你的系統突然出現一個「不可能的數字」,先別急著檢查程式邏輯。去看看你的數據源是不是在你不知道的時候,換了一把尺。
— 邱柏宇
延伸閱讀
Your API Changed the Ruler Without Telling You
An investment tracking system flagged an alert one day: a Japanese equity ETF closed nearly 90% below its 200-day moving average, triggering stop-loss logic. The Japanese market had no abnormal news that day. Investigation revealed that the ETF had just completed a 1-for-10 stock split that quarter.
Today’s Number, Yesterday’s Ruler
The commonly used quote API returned the post-split nominal price for current-day queries—unadjusted. But the same API’s historical data series used adjusted prices with restored rights. Two different scales of numbers were silently fed into the same moving average calculation. The result was naturally treating noise as signal.
API response format: correct. Program logic: no issues. HTTP status code 200. JSON schema validation passed. The only error was that the data source quietly switched measurement units between “today” and “history,” with no error message to alert you.
Nothing Actually Broke
This type of problem is extremely difficult to detect on the surface. Your test cases won’t fail because you’re testing format and connectivity, not data source consistency across time. Your monitoring won’t alert because API latency is normal and return values are valid. Your logs look fine, except for that 90% drop anomaly trigger—which is usually classified as a market anomaly, not a system problem.
The issue is, the API isn’t broken. The API provider changed their data processing logic at some point, possibly to comply with new accounting standards, possibly to align with other markets’ conventions, possibly just because of an internal refactor. They won’t issue an announcement because from their perspective, this is merely an “optimization.”
The Fix Isn’t Patching the API
The final solution wasn’t to fix the API’s data, nor to write a patch to detect stock split events. It was to switch to the ADR version of the same market proxy ETF listed on US exchanges. That ETF hadn’t experienced the same split, so its data calibration remained consistent throughout.
This isn’t the most elegant technical solution. But it’s the only one that doesn’t require continuous monitoring of upstream data source behavior. When you can’t control a data source’s stability, your only option is to stop depending on it.
Next time your system suddenly produces an “impossible number,” don’t rush to check your program logic. Check whether your data source changed its ruler without telling you.
— 邱柏宇