跳轉到

Quote Adapter 與資料格式

這一頁的目的,是把外部資料來源與內部回測引擎之間的邊界講清楚。

如果你未來要:

  • 替換 shioaji
  • 接自己的資料源
  • 寫新的行情 adapter
  • 把回測系統抽成可重用架構

這一頁最重要。

專案目前有哪些資料來源

目前在 app.py 中可見的資料源有:

  • shioaji
  • databento
  • 部分舊路徑有 polygon

對應實作位於:

  • src/quote/shioaji_quote.py
  • src/quote/databento_quote.py

主流程怎麼選資料源

fetch_data(ticker, start_time, end_time) 會依 ticker_list 中設定的 source 決定用哪個 adapter。

因此從系統角度來看:

  • 外部資料源本身不是核心
  • fetch_data() 才是主流程真正依賴的資料抽象入口

目前 adapter 的真實介面

雖然專案裡沒有正式宣告 ProtocolBaseQuoteAdapter,但實際上有一個隱性介面

  • 輸入:
  • ticker
  • start_time / start_date
  • end_time / end_date
  • 輸出:
  • pandas.DataFrame

而且這個 DataFrame 至少要有:

  • datetime
  • open
  • high
  • low
  • close
  • volume

可選欄位常見還有:

  • symbol
  • amount

內部回測真正吃的是什麼

不是原始 DataFrame,而是 DataFeed

DataFeed 的底層元素是 OHLCV

class OHLCV(BaseModel):
    datetime: str
    open: float
    high: float
    low: float
    close: float
    volume: float

也就是說,從架構觀點來看:

  • Adapter 層輸出 DataFrame
  • 核心回測層輸入 DataFeed

data_feed_from_dataframe_with_timeframe() 是兩者之間的轉換器。

目前 shioaji 實際用到的套件面

你目前不是整個系統都深度依賴 shioaji,而是集中在 ShioajiQuote 裡。

實際依賴很小:

  • sj.Shioaji(simulation=True)
  • api.login(...)
  • api.Contracts.Futures.TXF.TXFR1
  • api.Contracts.Futures.TXF.TXFR2
  • api.kbars(...)

因此如果你未來想替換成自己的資料來源,有兩種做法。

方案 A:模仿你自己的 adapter

最實用的方式是只保留你自己的 adapter 介面,例如:

class QuoteAdapter:
    def get_txfr1_data(self, ticker, start_date=None, end_date=None) -> pd.DataFrame:
        ...

這樣你只要替換 ShioajiQuote,主流程幾乎不用動。

方案 B:正式抽象成 provider interface

若要做得更乾淨,建議抽象成類似:

class QuoteProvider(Protocol):
    def get_data(
        self,
        ticker: str,
        start_time: str | datetime,
        end_time: str | datetime,
    ) -> pd.DataFrame:
        ...

然後在 fetch_data() 中統一呼叫 get_data()

如果你要重構,我建議的標準 adapter 規格

輸入

  • ticker: str
  • start_time: str | datetime
  • end_time: str | datetime

輸出

  • pd.DataFrame

必備欄位

  • datetime
  • open
  • high
  • low
  • close
  • volume

可選欄位

  • symbol
  • amount

資料要求

  • datetime 可被 pd.to_datetime() 正確解析
  • 每列代表一根 bar
  • 資料按時間升冪排序
  • 無重複時間戳

資料標準化責任應放哪裡

最好的做法是:

  • adapter 自己負責把外部資料轉成標準欄位
  • fetch_data() 只負責選擇資料源與交易時段切片
  • data_feed_from_dataframe_with_timeframe() 只負責重採樣與 DataFeed 轉換

這樣分層最乾淨。

現況結論

已經清楚的部分

  • 回測核心要的是 DataFeed
  • OHLCV 的欄位非常清楚

還沒正式清楚的部分

  • adapter 層目前沒有正式 interface
  • 只靠實作約定回 DataFrame

如果未來要讓這個系統更可重建,最值得補的一步就是:

  • 正式抽出 QuoteProvider / QuoteAdapter 介面