此为历史版本和 IPFS 入口查阅区,回到作品页
emily19980210
IPFS 指纹 这是什么

作品指纹

股票API分時轉日線的時區陷阱:我們在跨境投資數據處理中的經驗筆記

emily19980210
·
·
最近我們在整理一批美股的分鐘級行情資料時,遇到一個有點惱人的小插曲。用股票API拉回來的分鐘K線,經過我們自己寫的聚合程式轉成日線之後,有少數幾個交易日的開盤價和收盤價,跟券商軟體上的數據硬是差了一小截。起初我們還以為是K線計算模組哪裡出了狀況,把價格公式、資料格式、高低點判斷全都翻出來檢查一遍,程式碼本身卻乾淨得很,一點毛病也挑不出來。

最近我們在整理一批美股的分鐘級行情資料時,遇到一個有點惱人的小插曲。用股票API拉回來的分鐘K線,經過我們自己寫的聚合程式轉成日線之後,有少數幾個交易日的開盤價和收盤價,跟券商軟體上的數據硬是差了一小截。起初我們還以為是K線計算模組哪裡出了狀況,把價格公式、資料格式、高低點判斷全都翻出來檢查一遍,程式碼本身卻乾淨得很,一點毛病也挑不出來。

後來我們靜下心來,把焦點從「怎麼算」移到「什麼時候算」,才赫然發現,真正作怪的並非價格計算本身,而是每筆分鐘資料背後所承載的時間規則。不同市場的交易時間、不同API回傳的時間格式、以及時區轉換的處理方式,全都會影響最終生成的K線。尤其當你仰賴股票API獲取行情資料時,如果沒有在一開始就把時間問題處理妥當,分鐘線拼成日線的過程裡,就很容易出現資料錯位,而且往往錯得不知不覺。

為什麼我們選擇自己合成日線,而不是直接買現成資料

對我們這種同時關注多個市場的跨境投資者來說,資料成本一直是個需要精打細算的項目。如果每一個市場都去訂閱官方日線服務,一整年下來的費用其實相當可觀,對小團隊或個人研究者來說,性價比不見得划算。所以我們後來採取了一個相對務實的做法:透過股票API取得原始的分鐘級數據,再依照自己的需求,在內部系統中合成日線。

這樣做的好處很明顯:

  • 成本大幅下降,只需要負擔API的存取費用

  • 可以完全掌控K線的組成邏輯,例如要納入哪些交易時段、如何處理盤前盤後資料

  • 能依據不同策略需求,彈性產生不同時間區段的合成K線

但代價是,我們必須自己扛起資料品質的責任。時間一旦處理得不夠精準,後面所有的回測、策略分析、即時圖表,全都會建立在一個歪斜的基礎上。

我們在時間處理上最在意的幾件事

在開始動手寫轉換程式之前,我們先釐清了對這條資料管線的基本要求:

  • 日線的開高低收,必須與交易所正式公佈的數值一致

  • 歷史資料與即時資料,必須使用完全相同的時間轉換規則

  • 遇到美國夏令時間或冬令時間切換,系統要能自動適應

  • 不同資料來源合併時,時間格式和時區基準要能統一

只要其中任何一項沒有做好,回測出來的信號就可能跟實際市場脫鉤,而且這種脫鉤往往非常隱蔽,不容易在短時間內被發現。

讓我們頭痛的那個時區偏移

最初我們的日線聚合邏輯非常直覺:直接依照API回傳的日期欄位來分組,然後把每一組裡的第一筆當開盤、最後一筆當收盤、最高最低也照算。這套邏輯在單一時區的市場裡,大致上不會出什麼差錯。但美股市場的交易時間是以美東時間為準,而不少行情API回傳的卻是UTC時間。於是,問題就來了。

我們用一個簡單的例子來呈現這個落差。美國夏令時間期間,美東市場在早上九點半開盤,換算成UTC是下午一點半。大盤在美東下午四點收盤,換算成UTC是晚上八點。請看下表:

如果我們完全不進行時區轉換,直接用UTC的日期來切割交易日,那麼美東下午時段(大約UTC晚上七點到八點之間)的分鐘線,就可能因為跨過了UTC的午夜分界,而被錯誤地歸到隔天。結果就是,原本屬於同一個交易日的資料硬生生被拆成兩半,當天的收盤價少了最後一個小時,隔天的開盤價又混入了前一天的尾巴。這種狀況平時不容易察覺,但只要一跑歷史回測,累積下來的誤差就足以讓策略的績效曲線出現明顯的偏移。

解決方案:把時間轉換拉到所有計算之前

意識到問題的根源之後,我們重新調整了資料處理的順序。現在我們的原則很簡單:任何資料進入系統,第一件事就是先搞定時間,再來談K線計算。 具體的流程是這樣:

  1. 取得API回傳的原始時間戳記

  2. 判斷該標的所屬的交易所時區

  3. 利用 Python 的 zoneinfo 模組轉換成交易所當地時間

  4. 依照正式交易時段進行切割,最後才做日線聚合

以美股為例,我們會先把時間統一轉成 America/New_York,接下來的所有分組與計算,都只認這個時區。下面這段程式碼是我們目前資料管線中穩定運行的轉換邏輯:

from datetime import datetime
from zoneinfo import ZoneInfo

utc_time = datetime.strptime(
    "2026-07-01 13:30:00",
    "%Y-%m-%d %H:%M:%S"
)

utc_time = utc_time.replace(
    tzinfo=ZoneInfo("UTC")
)

market_time = utc_time.astimezone(
    ZoneInfo("America/New_York")
)

print(market_time)

這樣處理之後,系統會自動根據時區規則套用夏令時間或冬令時間,我們再也不用自己手動判斷到底要加幾個小時、減幾個小時。光是這一點,就省掉了過去很多不必要的錯誤。

交易日不等於自然日:那些盤前盤後的雜訊

時區問題解決了,但我們很快又撞上另一個容易忽略的細節:交易日跟自然日並不完全相同。很多行情API除了回傳正式交易時間的資料之外,也會一併把盤前和盤後的成交紀錄塞進來。如果我們只看日期欄位就全部丟進日線計算,那些非正式時段的少量成交,就可能反過來干擾開盤價或收盤價的判斷。

所以我們現在會在生成日線之前,先明確劃定資料範圍:

  • 只採用正式交易時段(美股為美東時間 09:30 至 16:00)的分鐘線

  • 盤前與盤後資料另外存放,若有需要再單獨調用

  • 搭配交易日曆,處理半日市、提早收盤、節假日等特殊情況

這樣一來,日線的組成乾淨許多,也比較能反映真實的市場流動性。

即時行情也需要一致的時間處理

如果說處理歷史分鐘資料時,時間錯誤還可以在事後從結果中看出端倪,那麼即時行情就完全不同了。即時資料是一筆一筆持續進來的,任何一筆的時間處理出錯,都會直接污染正在生成的即時K線,而且事後幾乎不可能回頭修正。

我們在串接即時行情時,就是把時間轉換模組直接放在資料入口的最前端。收到的每一筆 tick,都會先解析時間欄位、轉成交易所當地時間,然後才送進分鐘K線的合成器。後來我們選用了一個成本相對合理的即時行情來源 AllTick 來做 WebSocket 串接測試,也因為前面已經把時間模組獨立出來了,整個整合過程比想像中順利不少。

下面這段是我們處理即時行情資料的基本架構:

import websocket
import json
from datetime import datetime
from zoneinfo import ZoneInfo

def on_message(ws, message):
    data = json.loads(message)

    trade_time = data["tradeTime"]

    dt = datetime.strptime(
        trade_time,
        "%Y-%m-%d %H:%M:%S"
    )

    market_time = dt.replace(
        tzinfo=ZoneInfo("America/New_York")
    )

    print(
        data["symbol"],
        data["price"],
        market_time
    )

ws = websocket.WebSocketApp(
    "wss://api.alltick.co/stock/websocket",
    on_message=on_message
)

ws.run_forever()

在實際專案中,我們會把時間轉換單獨封裝成一個共用模組。不管是歷史資料的批次匯入,還是即時的 WebSocket 推播,都走同一套規則,這樣就能避免不同入口各自為政,產生難以追蹤的時間差異。

我們在資料處理過程中特別留意的幾點

分分鐘線拼日線這件事情,看似簡單,但其實埋了不少小細節。以下幾點是我們自己踩過坑之後,特別會留意的:

  • 不同資料來源的時間格式可能完全不一樣,有些給UTC,有些給交易所當地時間。多來源合併前,一定要先做格式與時區的正規化。

  • 原始時間戳記一定要保留下來。日後若發現某一根K線異常,原始時間往往是最快定位問題的線索。

  • 不要預設每個交易日都有固定數量的分鐘線。遇到節假日、提前收盤或臨時停牌,當天的資料筆數都會變動。

  • 時間轉換邏輯最好集中管理,不要散落在不同的腳本裡面,否則改了一個地方,另一個地方又忘了同步。

寫在最後:時間才是行情系統最隱形的根基

經過這段時間的折騰,我們越來越深刻地體會到,很多看似K線計算的異常,其實都不是數學公式出了問題,而是最基礎的時間資料沒有被妥善對待。分鐘K線轉日線,表面上只是一個資料聚合的動作,但背後牽涉到交易時間、時區轉換、交易日規則,甚至即時與歷史的一致性。

對於像我們這樣,希望用股票API自建行情系統的跨境投資者來說,把時間處理的流程固定下來,絕對是一筆很值得的投資。時間軸一旦穩定,不管是回測、策略分析,還是即時看盤,所有結果都會更貼近真實市場的樣貌。我們也還在持續優化這條資料管線,但至少現在看著不再跳空的日線,心裡踏實多了。

CC BY-NC-ND 4.0 授权