Rust 量化金融庫 libitofin 介紹
libitofin 是 QuantLib 的 Rust 移植版,並透過 itofin 支援 Python 呼叫。本文探討定價函式庫相較於試算表的優勢,包含期限結構與計日慣例的處理,以及為何在生產環境中應鎖定標記版本以確保穩定性。
定價函式庫能提供試算表公式所沒有的功能
試算表中的 Black-Scholes 儲存格只需輸入五個參數即可回傳價格。公式本身最簡單,真正的核心在於圍繞公式的四個層級,而這些層級正是函式庫的價值所在。
期限結構(Term structures)。 折現率是一條跨越不同到期日的曲線,並針對市場實際報價點之間的缺口提供插值規則。下方的面板展示了原始資料:單一日期下的美國國庫券報價期限。
每個數據背後的精確 SQL 語法
SELECT
arrayElement(tenors, i) AS tenor,
round(arrayElement(rates, i), 2) AS yield_pct,
formatDateTime(curve_date, '%b %e, %Y') AS as_of
FROM
(
SELECT
date AS curve_date,
['1 month', '3 months', '6 months', '1 year', '2 years', '3 years',
'5 years', '7 years', '10 years', '20 years', '30 years'] AS tenors,
[toFloat64(yield_1_month), toFloat64(yield_3_month), toFloat64(yield_6_month),
toFloat64(yield_1_year), toFloat64(yield_2_year), toFloat64(yield_3_year),
toFloat64(yield_5_year), toFloat64(yield_7_year), toFloat64(yield_10_year),
toFloat64(yield_20_year), toFloat64(yield_30_year)] AS rates,
arrayJoin(range(1, 12)) AS i
FROM global_markets.treasury_yields
WHERE date = (SELECT max(date) FROM global_markets.treasury_yields)
)
WHERE yield_pct > 0
ORDER BY i截至 Aug 10, 2026,該報價曲線包含 7 個期限,從 3.79% 的 1 month 到 5.25% 的 30 years。試算表處理此類問題的方式是透過查詢與寫死的 4% 利率。函式庫則使用「曲線物件」,所有金融工具皆依此定價,並採用特定的插值法(如零息利率線性插值、折現因子對數線性插值、單調樣條插值)以及針對最後一個數據點之後的特定外插政策。只要將該物件移動一個基點(basis point),帳簿中所有敏感度指標都會隨之同步調整。
計日慣例(Day-count conventions)。 利息是按年化分數累計的,而該分數的定義取決於金融工具所採用的慣例。Actual/360 將經過天數除以 360;Actual/365 則除以 365。30/360 系列則假定每個月皆為 30 天。Business/252 則是將交易日與 252 天的年度進行對比,這需要載入包含假日資訊的真實交易所日曆。假設借款一百萬美元,利率 5%,期限 90 天:在同一筆交易中,Actual/360 會累計 12,500 美元利息,而 Actual/365 則累計 12,329 美元。下方的面板說明了為何營業日基礎需要日曆而非單純的除數。
每個數據背後的精確 SQL 語法
SELECT
formatDateTime(toStartOfMonth(date), '%Y-%m') AS month,
countDistinct(date) AS trading_days,
toUInt8(toDayOfMonth(toLastDayOfMonth(max(date)))) AS calendar_days
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= toStartOfMonth(today() - 365)
AND date < toStartOfMonth(today())
GROUP BY month
ORDER BY month在 12 個月期間,2026-07 共有 22 個交易日,對應 31 個日曆天數。沒有任何算術規則能直接算出第一個數字,它必須來自假日日曆,且每個月的結果都不同。函式庫會針對各個交易場所與國家提供這些日曆;而試算表則要求使用者自行維護。
校準機制(Calibration machinery)。 模型參數在任何地方都不會直接報價。您必須透過將模型價格與觀察到的市場價格進行擬合(fitting)來選取參數,並隨著市場表面(surface)的變動進行重新擬合。這是一個有界最小平方法問題,函式庫提供了完整的運算迴圈:包含 Levenberg-Marquardt 最佳化演算法、確保變異數為正值且無需嚴格限制的參數轉換、針對報價集的成本函數,以及在無法收斂時會明確報錯而非默默回傳初始猜測值的收斂準則。
數值運算層(A numerics layer)。 所有功能的底層皆為線性代數與積分運算。QR 與 SVD 分解用於解決擬合產生的系統,求積法與傅立葉積分用於計算公式為積分形式的模型,而求根法(root finders)則用於反推隱含波動率。這一層雖然枯燥,卻正是最容易被錯誤實作的部分。常見的錯誤是手寫 Newton 解法,在流動性高的價平(at-the-money)報價上能收斂,但在深價外(deep out-of-the-money)報價上卻會發散。其次是矩陣反轉在近奇異(near-singular)擬合中失去精度,導致回傳看似合理但錯誤的參數。如果您打算從零開始建立心智模型,開源量化交易書籍會比任何函式庫的 API 參考文件更適合作為起點。
什麼是 libitofin,它是 Rust 版的 QuantLib 嗎?
是的,就核心意義而言。它是 QuantLib 設計在 Rust 語言上的移植,且專案聲明其已通過 QuantLib 自身的測試套件驗證。這是移植數值函式庫最誠實的做法:結果是與參考實作進行比對,而非與手寫的預期結果進行比對。Python 的介面是一個名為 itofin 的套件,因此 Python 流程無需在迴圈中引入 C++ 工具鏈即可呼叫 Rust 引擎。
更重要的標籤是「pre-1.0」。根據 Rust 的版本控制慣例,0.x 版本不保證次版本之間的相容性:從 0.4 到 0.5 可能會重新命名、移動或刪除任何內容。請將此 API 視為變動目標,並養成以下習慣:
- 在鎖定檔(lockfile)中固定確切的標籤版本,並有意識地進行升級,同時以您自己的測試套件作為把關。
- 在函式庫類型外層建立一層輕量級封裝,以便在重新命名時只需修改一個檔案,而非四十個。
- 記錄產生數據時所使用的函式庫版本,以便在重新執行結果不一致時,能指向升級原因而非市場因素。
- 在 1.0 版本發布前,請將生產環境的保證金、抵押品與監管風險數據保留在具備相容性承諾的系統上。
以上並非對該專案的批評。Pre-1.0 是精確的自我描述,對於一個大型函式庫的年輕移植版而言,這是正確的定位。失敗模式在於讀者將其視為 QuantLib 的隨插即用替代品,結果在季度中途因次版本更新導致簽章變更。安裝說明也會隨版本變動,且 cargo 與 pip 在解析依賴時都需要網路存取,因此請閱讀您打算鎖定的標籤版本所對應的 README,而非複製部落格文章(包括本文)中的片段。
Python、編譯引擎還是 Rust?
兩個問題即可決定,且與個人偏好無關。您每秒需要重新定價多少次?您的數據是否需要在不同流程間保持一致?鏈結(chain)規模決定了第一個問題的規模。
每個數據背後的精確 SQL 語法
WITH (SELECT max(date) FROM global_markets.options_greeks) AS last_session
SELECT
underlying_symbol AS symbol,
countDistinct(ticker) AS contracts_priced,
formatDateTime(max(date), '%b %e, %Y') AS as_of
FROM global_markets.options_greeks
WHERE date = last_session
AND underlying_symbol IN ('SPY', 'AAPL', 'NVDA', 'MSFT', 'KO')
AND volume > 0
GROUP BY symbol
ORDER BY contracts_priced DESC在 Aug 11, 2026,SPY 在單一交易時段內有 5336 個不同的合約交易,而 KO 則有 360 個。對廣泛的鏈結進行一次定價並非難事。但若要在每次報價更新時,針對帳簿中所有標的資產的每個合約計算五種敏感度指標,這就是一個具有不同限制條件的程式。
當迴圈速度以每分鐘數千次估值計算,且周邊工作為研究、分析或每日結算時,請繼續使用 Python 搭配成熟的函式庫。QuantLib 自身的 Python 綁定是成熟的選擇:相同的 C++ 引擎、最廣泛的金融工具覆蓋範圍,以及多年的生產環境驗證。在研究程式碼中,速度很少是限制因素,覆蓋範圍與正確性才是。
當迴圈運算密集但周邊程式碼不密集時,請從 Python 呼叫編譯引擎。需要注意的成本是邊界本身。從 Python 進行逐合約呼叫會在每次跨越邊界時產生額外開銷,解決方法是將陣列傳遞給引擎並取回陣列。這正是 itofin 與 QuantLib-Python 共同瞄準的定位。
當定價迴圈本身就是產品時,請使用 Rust:例如報價服務內的定價器、不可延誤的排程風險運算,或是部署在沒有 Python 環境的機器上的二進位檔案。第二個問題也適用於此。浮點數運算結果取決於運算順序,因此同一模型實作兩次可能會在小數末位出現差異,而研究筆記與生產服務不一致會導致一週的排查工作。使用同一個引擎可消除這類差異,這也是為何無論使用何種語言,編譯核心搭配綁定都是持久的論點。同樣的直覺也適用於策略研究,如 可重現的回測所示。
校準目標的實際位置
校準需要對標的物,而該對標物即為市場隱含波動率表面。其求根運算部分已在 隱含波動率的計算方式中涵蓋。下方的形狀即為模型必須匹配的目標。
每個數據背後的精確 SQL 語法
SELECT
multiIf(days_to_expiry <= 7, '0 to 7 days',
days_to_expiry <= 30, '8 to 30 days',
days_to_expiry <= 60, '31 to 60 days',
days_to_expiry <= 120, '61 to 120 days',
days_to_expiry <= 240, '121 to 240 days',
'241 days or more') AS dte_bucket,
round(avg(implied_volatility) * 100, 1) AS iv_pct,
countDistinct(ticker) AS contracts
FROM global_markets.options_greeks
WHERE underlying_symbol = 'AAPL'
AND date >= today() - 10
AND days_to_expiry >= 0
AND iv_converged = 1
AND volume > 0
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.05
GROUP BY dte_bucket
ORDER BY min(days_to_expiry)在價平附近,0 to 7 days 區間的 AAPL 合約在觀察期間的平均隱含波動率為 29.6%,而 241 days or more 則為 29.3%。攜帶單一波動率參數的模型無法同時滿足這兩點,這正是為什麼存在波動率期限結構模型的原因。將模型擬合至此類表面即為校準步驟,而從擬合模型中得出的敏感度即為希臘字母(greeks),詳見 選擇權希臘字母詳解。
這些面板是如何建立的
曲線面板讀取國庫券系列中最近的一個報價日期,並將其十一個期限欄位展開為列,剔除當日無報價的期限。交易時段面板計算 SPY 磁帶上每個月的不同日期,這是計算完整交易所交易時段數量的有效代理指標。鏈結面板計算最新可用時段內成交量非零的不同合約代碼,並按標的資產分組。波動率面板僅保留已收斂且成交量非零,且履約價在標的收盤價 5% 以內的數據,這是標準的價平區間;前段區間包含當日到期的合約。
常見問題
libitofin 是 QuantLib 的隨插即用替代品嗎?
不是。截至 2026 年 8 月,它是一個 pre-1.0 的移植版,僅涵蓋 QuantLib 部分功能,並透過 QuantLib 自身的測試套件驗證結果。QuantLib 本身(透過 Python 綁定使用)在生產環境中仍然是更廣泛且穩定的選擇。
對於定價函式庫而言,pre-1.0 代表什麼?
根據 Rust 的版本控制慣例,0.x 版本不提供相容性承諾:下一個次版本可以自由重新命名或刪除任何內容。在實務上,這意味著您需要固定確切的標籤版本,並在每次升級時重新執行您自己的測試套件。
我需要會寫 Rust 才能使用 libitofin 嗎?
不需要。該專案發布了一個名為 itofin 的 Python 套件,因此引擎可以從一般的 Python 流程中呼叫。當定價迴圈本身就是您要交付的產品時,撰寫 Rust 才變得重要。
定價函式庫能提供試算表公式所沒有的功能嗎?
它提供曲線而非單一利率、具備真實交易所日曆支援的計日慣例、將模型參數擬合至報價的校準迴圈,以及上述三者底層經過測試的數值運算層。封閉式公式只是工作中最微小的一部分。
程式語言會改變選擇權價格嗎?
數學上不會。但它會改變可重現性:浮點數結果取決於運算順序,因此同一模型的兩種實作可能會在末位數字上產生差異。使用同一個引擎進行研究與生產,可以消除這種差距。
此處的每個面板下方皆附有其確切的 SQL 語法,展開即可查看計算方式。同樣的曲線、日曆與鏈結問題,也可以在 Strasmore 終端機上以簡單的英文詢問。