投資理財統計數據

扣掉通膨調整後的股市與債市報酬(1928-2022)

我從《Historical Returns on Stocks, Bonds and Bills: 1928-2022》調取了美國1928年-2022年的資產報酬,分別是:S&P 500 (includes dividends)、3-month T.Bill 、US T. Bond、Baa Corporate Bond、Real Estate、Gold。

另外我也《Consumer Price Index, 1800-》調取了美國歷年的CPI指數。

將兩者扣除後,我想看五種資產類年的實質報酬,並利用Python分析資料與繪製圖表,我將程式碼留存以利往後學習與檢視。


股票與債券5年滾動報酬(rolling returns)

首先我繪製了股票與債券的5年滾動報酬(rolling returns),這是衡量資產長期投資表現的指標,也可以直觀的理解持有5年,期間不同時期我們檢視資產的報酬率會如何。

如下圖:

在這張圖中,深藍色的線條代表 S&P 500 的 5 年滾動報酬率,而深橘色的線條代表美國國債的 5 年滾動報酬率。

將報酬率年化,後轉換為每年度的平均報酬率,如下圖

股票的5年年化報酬率落在 -10.2% 到 25.9% 之間;

債券的的5年年化報酬率落在-8.7% 到 15.7% 之間。


有多少比例股票優於債券?

在這張圖中,我好奇股票有多少比例贏過債券。

從這組數據來看,S&P 500 的 5 年滾動報酬率超過美國國債的比例約為 79.1%。

約有接近80%的時間中,投資股市5年的成效是優於美國債券的。

這表示在大約 79.1% 的時間裡,投資 S&P 500 的 5 年滾動報酬率是高於投資美國國債的。換句話說,股票在這段時間內贏過債券的機率是相當高的。

將股票的報酬減去債券,重新繪製如下圖:

這張圖代表每一個 5 年期間中,S&P 500 的報酬率與美國國債的報酬率的差異。

圖中紅色虛線(y=0)之上代表,S&P 500 的 5 年滾動報酬率優於美國國債,簡單來說股市超過債券;

紅色虛線之下的部分則表示 S&P 500 的 5 年滾動報酬率低於美國國債。


股市的報酬低於債市的時代背景是?

我將股市落後債市的背景以淺灰色凸顯出來,並調閱了當時的事件背景。

1932年至1934年:這是大蕭條(Great Depression)期間,是全球最嚴重的經濟衰退之一。由於1929年的股市崩潰,全球經濟陷入深重的困境,導致大量失業和貧困。

1940年至1941年:在這段期間,世界正在經歷第二次世界大戰。戰爭使得經濟活動受到重大干擾,並導致許多投資者尋求安全的資產,例如債券。

1973年至1974年:這段期間稱為石油危機,當時石油輸出國組織(OPEC)對西方國家進行了石油禁運,導致石油價格飆升,並引發經濟衰退和高通脹。

1977年:這一年美國經歷了一段較短的經濟衰退,導致失業率上升,經濟增長放緩。

1985年至1986年:這是儲蓄和貸款危機期間,當時許多儲蓄和貸款協會由於不良貸款和投資失敗而倒閉,導致金融市場波動。

2002年至2005年:這段時間是在網路泡沫破裂後,許多科技股價格暴跌,並導致全球股市下跌。

2008年至2012年:全球金融危機期間,由於房地產市場崩潰和金融機構的信貸危機,全球經濟陷入重大衰退。

我的觀察

1、風險對沖

從5年的滾動報酬可以看到分散投資的好處,接近八成的時間中,股市年化報酬率優於債市,而且每當股市落入負報酬區域時,債市都能維持正報酬。

2、在經濟衰退或金融危機時期,債券提供了保護。

將在大蕭條、石油危機、網路泡沫或是其他衰退期間,投資者透過債券尋求保護,債券這種安全的資產可以帶來比較高的收益。

3、五年的投資期限報酬仍然有很大的變化,蘊含較高的不確定性。

即使持有5年,股市的年化報酬仍然可能落在-10.2% 到 25.9%之間,持有五年也可能看不到投資的收益,甚至有可能還是會賠錢,這是我們在制定投資時間框架上要留意的。


Python代碼

分析Excel

import pandas as pd

# Load the excel file
file_path = "/mnt/data/chartby year (after inflation).xlsx"
data = pd.read_excel(file_path)

# Show the first few rows of the dataframe
data.head()

繪製滾動報酬

import matplotlib.pyplot as plt

# Calculate 5-year rolling return
data['S&P 500 (includes dividends) 5yr rolling'] = data['S&P 500 (includes dividends)'].rolling(window=5).sum()
data['US T. Bond 5yr rolling'] = data['US T.Bond'].rolling(window=5).sum()

# Create a new column to indicate whether S&P 500 outperformed T. Bonds in each 5-year period data['S&P 500 wins'] = data['S&P 500 (includes dividends) 5yr rolling'] > data['US T. Bond 5yr rolling']

# Plot 5-year rolling return
plt.figure(figsize=(14, 7))
plt.plot(data['Year'], data['S&P 500 (includes dividends) 5yr rolling'], label='S&P 500 (includes dividends) 5yr rolling')
plt.plot(data['Year'], data['US T. Bond 5yr rolling'], label='US T. Bond 5yr rolling')
plt.legend()
plt.title('5-year rolling returns of S&P 500 and US T. Bonds')
plt.xlabel('Year')
plt.ylabel('Return')
plt.grid(True)
plt.show()

# Calculate the proportion of periods where S&P 500 outperformed T. Bonds
proportion_sp500_wins = data['S&P 500 wins'].sum() / data['S&P 500 wins'].count()

proportion_sp500_wins

年化報酬率

# Calculate annualized 5-year rolling return
data['S&P 500 (includes dividends) 5yr rolling annualized'] = (1 + data['S&P 500 (includes dividends)']).rolling(window=5).apply(lambda x: x.prod()**(1/5) - 1, raw=True)
data['US T. Bond 5yr rolling annualized'] = (1 + data['US T. Bond']).rolling(window=5).apply(lambda x: x.prod()**(1/5) - 1, raw=True)

# Plot annualized 5-year rolling return
plt.figure(figsize=(14, 7))
plt.plot(data['Year'], data['S&P 500 (includes dividends) 5yr rolling annualized'], label='S&P 500 (includes dividends) 5yr rolling annualized', color='navy')
plt.plot(data['Year'], data['US T. Bond 5yr rolling annualized'], label='US T. Bond 5yr rolling annualized', color='darkorange')
plt.legend()
plt.title('5-year annualized rolling returns of S&P 500 and US T. Bonds')
plt.xlabel('Year')
plt.ylabel('Return')
plt.grid(True)
plt.show()

# Calculate the range of annualized 5-year rolling returns for S&P 500 and US T. Bonds
sp500_rolling_return_annualized_range = (data['S&P 500 (includes dividends) 5yr rolling annualized'].min(), data['S&P 500 (includes dividends) 5yr rolling annualized'].max())
us_bond_rolling_return_annualized_range = (data['US T. Bond 5yr rolling annualized'].min(), data['US T. Bond 5yr rolling annualized'].max())

sp500_rolling_return_annualized_range, us_bond_rolling_return_annualized_range

股票贏過債券的比率

# Calculate the proportion of periods where the difference is greater than 0 (S&P 500 outperformed T. Bonds)

proportion_diff_positive = (data['Rolling Return Difference'] > 0).sum() / data['Rolling Return Difference'].count()

proportion_diff_positive

股票減去債券

# Plot the difference with more distinguishable color
plt.figure(figsize=(14, 7))
plt.plot(data['Year'], data['Rolling Return Difference'], label='S&P 500 - US T. Bond 5yr rolling', color='forestgreen')
plt.axhline(y=0, color='r', linestyle='--')  # Add a horizontal line at y=0 for reference
plt.legend()
plt.title('Difference in 5-year rolling returns between S&P 500 and US T. Bonds')
plt.xlabel('Year')
plt.ylabel('Difference in Return')
plt.grid(True)
plt.show()


你好,我是蔡至誠PG,《阿爾發證券投顧》教育長,《我畢業五年,用ETF賺到400萬》作者,《提早五年退休:PG 財經個人財務調配術》講師。

定期定額投資美股ETF增加被動收入,我們公司推出的機器人理財平台能讓你一站式做好規劃,幫你追蹤財務目標達成率,幫你挑選低成本的ETF投資組合,投資之後24小時追蹤與自動再平衡

陪您一起安心達成財務目標,點擊下方連結加入官方LINE@預約諮詢,讓今天的投資更輕鬆,明天的生活更美好!

Back to top button