Sharpe ratio 的無風險利率如何選擇與換算
Sharpe ratio 的無風險利率會隨時間變動,了解如何配對國庫券殖利率與報酬頻率,避免用單一固定利率扭曲長期績效比較。
Sharpe ratio 中的無風險利率,是指在相同期間內、不承擔你正在評估之風險時,可以取得的報酬率。它是一組時間序列,每個期間有一個數值,並以報酬率的貨幣計價。其頻率應與報酬率一致,並逐期扣除。最後才進行年化。
多數已發布的 Sharpe ratio 出錯,原因就在於跳過了這個程序。有人從長達二十年的報酬率歷史中,直接取一個數字,通常是本週國庫券的利率,結果讓2009年與2024年承擔相同的門檻。我們的 Sharpe ratio 指南說明這項比率衡量的內容。本頁則聚焦於幾乎沒有人記錄的輸入值。
無風險利率不是固定值
在二十年期間計算 Sharpe ratio,涵蓋的是一段利率歷史。下方面板以三個月期國庫券為例,將每個曆年彙整為平均值及其波動範圍。
每個數據背後的精確 SQL 語法
SELECT
toString(toYear(date)) AS year,
round(avg(toFloat64(yield_3_month)), 2) AS avg_bill_pct,
round(min(toFloat64(yield_3_month)), 2) AS low_bill_pct,
round(max(toFloat64(yield_3_month)), 2) AS high_bill_pct
FROM global_markets.treasury_yields
WHERE date >= '2005-01-01'
AND yield_3_month IS NOT NULL
GROUP BY year
ORDER BY year年度平均值在3.22%的2005,以及3.74%的2026,涵蓋22個曆年。這兩個數值之間的路徑才是關鍵。利率先降至底部,在接近十年的時間維持低檔,之後又回升。低點與高點欄位顯示利率在單一年內的變動幅度。這也是為什麼即使是一年期 Sharpe ratio,也應使用相符的時間序列,而不是單一報價。
Sharpe ratio 應採用哪一項無風險利率
四項特性決定應選用的利率。
- 短天期。利率在一個衡量期間內必須接近確定。三個月期國庫券適合月度分析。十年期公債則不適合,因為其價格會在你衡量的月份內變動。
- 與報酬率相同的貨幣。以歐元計價的策略,應以歐元國庫券作為評估基準。
- 與報酬率相同的頻率。國庫券殖利率通常以年率報價,因此年率必須先換算為月率,才能與月度報酬率相減。
- 雙方的報酬定義必須具有可比性。國庫券殖利率代表其完整報酬,因此排除股息的策略報酬,並不是在相同基礎上衡量。價格報酬與總報酬說明這項差異。
第三點的換算,目前有兩種慣例。簡單除法是將年率除以十二。複利法則是取一加年率的十二次方根。假設國庫券殖利率為5%,兩種方法得到的月率分別為0.4167%與0.4074%。兩者相差約一個基點,而且會在樣本的每個月份重複累積。本頁的面板採用複利法。如果你關心的是持有國庫券所產生的利息,而不是將其作為報酬門檻,股息殖利率與國庫券殖利率及閒置現金的配置方式可提供相關說明。
如何建立月度超額報酬序列
建立方式是機械性的:取每個月最後一個收盤價,計算當月報酬率;將該月份的國庫券報價換算為月率;再將兩者相減。所得結果是一組超額報酬序列,每月一個數值。月度報酬率的計算方式詳細說明報酬率部分。
每個數據背後的精確 SQL 語法
WITH
monthly_px AS
(
SELECT
toStartOfMonth(date) AS m,
argMax(toFloat64(close), date) AS month_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2019-12-01'
AND date < '2025-01-01'
GROUP BY m
),
prior_px AS
(
SELECT
addMonths(m, 1) AS m,
month_close AS prev_close
FROM monthly_px
),
monthly_rf AS
(
SELECT
toStartOfMonth(date) AS m,
pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_month
FROM global_markets.treasury_yields
WHERE date >= '2019-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
GROUP BY m
)
SELECT
toString(cur.m) AS month,
round(100 * (cur.month_close / prv.prev_close - 1), 2) AS spy_ret_pct,
round(100 * rf.rf_month, 3) AS rf_pct,
round(100 * (cur.month_close / prv.prev_close - 1 - rf.rf_month), 2) AS excess_pct
FROM monthly_px AS cur
INNER JOIN prior_px AS prv ON prv.m = cur.m
INNER JOIN monthly_rf AS rf ON rf.m = cur.m
ORDER BY cur.m這些是 SPY 的收盤價,因此報酬率欄位是未計入股息的價格報酬。風險利率欄位在所示第一個月份為0.128%,最後一個月份為0.359%。相較於每月可能波動數個百分點的股票報酬,無風險利率看起來只像四捨五入誤差。但在60個月份逐期扣除後,它會成為兩個聲稱衡量相同事物的 Sharpe ratio 之間的全部差異。
先扣除,再年化
當兩組序列對齊後,有兩種運算順序,但結果並不相同。先計算超額報酬:從月度報酬率中扣除月度利率,再將超額報酬序列年化。先年化則是:先將報酬率複利為年度數值,再將國庫券利率複利為年度數值,最後以兩者相減。
每個數據背後的精確 SQL 語法
WITH
monthly_px AS
(
SELECT
toStartOfMonth(date) AS m,
argMax(toFloat64(close), date) AS month_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2004-12-01'
AND date < '2025-01-01'
GROUP BY m
),
prior_px AS
(
SELECT
addMonths(m, 1) AS m,
month_close AS prev_close
FROM monthly_px
),
monthly_rf AS
(
SELECT
toStartOfMonth(date) AS m,
pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_month
FROM global_markets.treasury_yields
WHERE date >= '2004-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
GROUP BY m
),
excess AS
(
SELECT
cur.m AS m,
cur.month_close / prv.prev_close - 1 AS ret,
rf.rf_month AS rf_month,
cur.month_close / prv.prev_close - 1 - rf.rf_month AS exc
FROM monthly_px AS cur
INNER JOIN prior_px AS prv ON prv.m = cur.m
INNER JOIN monthly_rf AS rf ON rf.m = cur.m
)
SELECT
concat(toString(intDiv(count(), 12)), '-year') AS horizon,
round(100 * (exp(12 * avg(log(1 + exc))) - 1), 2) AS excess_first_pct,
round(100 * ((exp(12 * avg(log(1 + ret))) - 1)
- (exp(12 * avg(log(1 + rf_month))) - 1)), 2) AS annualize_first_pct,
round(100 * ((exp(12 * avg(log(1 + ret))) - 1)
- (exp(12 * avg(log(1 + rf_month))) - 1)
- (exp(12 * avg(log(1 + exc))) - 1)), 3) AS gap_pct
FROM excess
CROSS JOIN (SELECT arrayJoin([1, 3, 5, 10, 20]) AS years) AS hz
WHERE m >= subtractYears(toDate('2025-01-01'), years)
GROUP BY years
ORDER BY years在20-year期間內,先計算超額報酬的結果為每年6.49%,另一種順序則為6.59%,兩者相差0.099個百分點。在1-year期間,兩種計算結果相差0.814個百分點。在本頁的每個期間中,先年化的數值都高於先計算超額報酬的數值。差異來自交叉項:將報酬率序列複利為年度數值時,包含了在風險溢酬之上再賺取國庫券利率的效果;但之後再扣除年化國庫券利率,並不會將這部分效果扣回。交叉項與兩個年化數值的乘積成正比,因此國庫券利率越高,差異越大。
年化還有第二個分歧。算術年化是將月度超額報酬的平均值乘以十二。幾何年化則採用複利,計算能重現累積結果的固定年率。假設有兩個期間,第一期報酬為+50%,第二期為-33.3%,最終恰好回到起點。算術平均值為每期+8.35%,幾何平均值則為零。本頁的面板採用複利法。有一項值得保留的註記:在算術年化下,月度平均報酬乘以十二,再減去月度平均國庫券利率乘以十二,在代數上等同於月度平均超額報酬乘以十二。在此慣例下,扣除順序不會改變分子。但分母仍會變動,因為當利率本身持續變化時,超額報酬的標準差就會與原始報酬的標準差出現差異。
採用單一固定利率會如何影響結果
常見的捷徑,是將目前的國庫券殖利率從歷史中每一期的報酬率扣除。下方面板以五個在同一日期結束的期間,分別計算兩種 Sharpe ratio:一次使用相符的月度利率序列,另一次使用該期間結束時適用的國庫券殖利率。
每個數據背後的精確 SQL 語法
WITH
monthly_px AS
(
SELECT
toStartOfMonth(date) AS m,
argMax(toFloat64(close), date) AS month_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2004-12-01'
AND date < '2025-01-01'
GROUP BY m
),
prior_px AS
(
SELECT
addMonths(m, 1) AS m,
month_close AS prev_close
FROM monthly_px
),
monthly_rf AS
(
SELECT
toStartOfMonth(date) AS m,
pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_month
FROM global_markets.treasury_yields
WHERE date >= '2004-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
GROUP BY m
),
excess AS
(
SELECT
cur.m AS m,
cur.month_close / prv.prev_close - 1 AS ret,
rf.rf_month AS rf_month
FROM monthly_px AS cur
INNER JOIN prior_px AS prv ON prv.m = cur.m
INNER JOIN monthly_rf AS rf ON rf.m = cur.m
)
SELECT
concat(toString(intDiv(count(), 12)), '-year') AS horizon,
round(sqrt(12) * avg(ret - rf_month) / stddevSamp(ret - rf_month), 2) AS sharpe_matched_rf,
round(sqrt(12) * avg(ret - rf_fixed) / stddevSamp(ret - rf_fixed), 2) AS sharpe_fixed_rf,
round(abs(sqrt(12) * avg(ret - rf_month) / stddevSamp(ret - rf_month)
- sqrt(12) * avg(ret - rf_fixed) / stddevSamp(ret - rf_fixed)), 2) AS abs_gap
FROM excess
CROSS JOIN
(
SELECT pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_fixed
FROM global_markets.treasury_yields
WHERE date >= '2024-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
) AS fixed_rate
CROSS JOIN (SELECT arrayJoin([1, 3, 5, 10, 20]) AS years) AS hz
WHERE m >= subtractYears(toDate('2025-01-01'), years)
GROUP BY years
ORDER BY years在1-year期間,兩個數值相差0.07。在十二個月期間,固定利率與該期間自身的平均利率之間,能夠偏離的空間不大。在20-year期間,兩者相差0.18個百分點:相符序列為0.49,固定利率則為0.32。誤差取決於你選定的單一利率與實際適用平均利率之間的距離。期間越長,這段距離越有可能擴大。所有後續分析都會承受這項誤差,而波動度目標與部位規模設定正是以這類輸入值為基礎。
貨幣陷阱
如果策略以一種貨幣賺取報酬,卻以另一種貨幣的國庫券作為評估基準,所得數值對兩種貨幣而言都缺乏明確意義。應在同一種貨幣內計算超額報酬:歐元報酬對歐元國庫券,日圓報酬對日圓國庫券。避險策略還有另一項陷阱。貨幣避險的定價依據是遠期匯率,而遠期點數通常接近兩種貨幣的利率差,這已將部分本國利率納入避險後的外幣報酬。若再扣除外幣國庫券利率,就會將同一項利率計算兩次。只要在利率旁標明貨幣,歧義就能消除。
將利率與 Sharpe ratio 一併發布
如果未說明無風險利率的來源與頻率,任何人都無法查核所發布的 Sharpe ratio。兩個交易台可能從完全相同的報酬序列計算出0.8與1.1,而且兩者都可能正確,因為採用的利率序列與換算慣例不同。這個數值應一併提供四項資訊:利率所來自的工具、利率頻率、換算慣例,以及確切的計算期間。這就是讀者可以查核的數值,與只能信賴的數值之間的差異。
資料註記與可重現性
每個面板的利率序列都來自每日國庫券殖利率曲線中的三個月期國庫券,先在每個曆月內取平均,再以一加年率的十二次方根換算為月率。報酬率使用 SPY 月底收盤價,僅計算價格報酬,不含股息。Sharpe ratio 使用月度超額報酬的樣本標準差,並以十二的平方根進行年化。最後兩個面板使用在同一日期結束的期間;固定利率欄位則採用該期間最後一個月的平均國庫券報價。上述內文的每個數值,都來自其旁邊的面板。
常見問題
Sharpe ratio 應使用哪一項無風險利率?
使用與報酬率相同貨幣的短天期政府國庫券,並將其換算為與報酬率相同的頻率。對月度 USD 報酬率而言,這代表一個月期或三個月期美國國庫券。較長天期工具在衡量期間內承擔價格風險,因此不符合無風險部分的要求。
可以從長期報酬歷史中扣除今天的國庫券殖利率嗎?
這是已發布 Sharpe ratio 最常見的錯誤。在上文的20-year期間,固定的期末利率與相符的月度利率序列,對完全相同的報酬率產生相差0.18的結果。
應該先將無風險利率年化,再進行扣除嗎?
不應如此。先將國庫券年率換算為報酬率的頻率,逐期扣除,再於最後將超額報酬序列年化。若分別將兩個部分年化後再相減,結果會留下交叉項。
無風險利率會讓 Sharpe ratio 變動多少?
大致等於利率變化除以年化波動度。假設某策略的年化波動度為15%,若假設利率相差4%,Sharpe ratio 約會變動0.27。這可能就是普通績效與備受稱道績效之間的距離。
算術年化與幾何年化有何差異?
算術年化是將每期超額報酬的平均值乘以一年中的期數。幾何年化則將各期複利,計算能重現累積結果的固定利率。以每期來看,幾何數值小於或等於算術數值;波動度越高,兩者差距越大。
本頁每個面板都附有產生該面板的 SQL,因此可以看見利率序列與計算期間。若要將相同的計算方式套用至另一個 ticker 或另一段歷史資料,請在 Strasmore terminal 以自然語言提出要求。