配当再投資で総リターンをシミュレーションする

7.1.14

配当再投資で総リターンをシミュレーションする

最終更新 2020-07-29 読了時間 2 分
まとめ
  • 配当を再投資するシナリオと現金保持するシナリオを比較し、複利効果を定量的に確認する。
  • pandasで月次の配当再投資ループを実装し、ポートフォリオの評価額推移をシミュレーションする。
  • CAGR・最大ドローダウンなどの指標で、両シナリオのリスク・リターンを評価する。

直感 #

配当を現金のまま受け取る場合と、すぐに再投資する場合では長期の総リターンに大きな差が生まれます。再投資では配当で追加の株式を購入し、その株式からもさらに配当が得られるため、複利効果が働きます。この差は投資期間が長いほど大きくなり、10年以上の長期投資では総リターンの数十%を配当再投資が占めることも珍しくありません。

詳細な解説 #

擬似データの生成 #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pathlib import Path

np.random.seed(21)
plt.style.use("scripts/k_dm.mplstyle")

dates = pd.date_range("2015-01-01", periods=9 * 12, freq="M")
price = 100 * np.exp(np.cumsum(np.random.normal(0.005, 0.04, len(dates))))
dividend_yield = np.random.uniform(0.015, 0.025, len(dates))  # 年率1.5〜2.5%

frame = pd.DataFrame({"price": price, "dividend_yield": dividend_yield}, index=dates)
frame["dividend_cash"] = frame["price"] * frame["dividend_yield"] / 12

シナリオ1: 配当を現金のまま保持 #

配当は受け取るが再投資せず、株式1株 + 累積配当金で評価します。

1
2
cash_hold = frame["dividend_cash"].cumsum()
total_value_cash = frame["price"] + cash_hold

シナリオ2: 配当を即座に再投資 #

配当で追加の株式を購入し、保有株数を増やします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
shares = 1.0
cash = 0.0
portfolio_value = []

for price, dividend in zip(frame["price"], frame["dividend_cash"]):
    cash += dividend
    additional_shares = cash / price
    shares += additional_shares
    cash = 0.0
    portfolio_value.append(shares * price)

total_value_reinvest = pd.Series(portfolio_value, index=frame.index)

結果を比較 #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
comparison = pd.DataFrame(
    {
        "現金保持": total_value_cash,
        "再投資": total_value_reinvest,
    }
)

fig, ax = plt.subplots(figsize=(9, 4.2))
comparison.plot(ax=ax)
ax.set_title("配当再投資シミュレーション(擬似データ)")
ax.set_ylabel("評価額(基準=100)")
ax.grid(alpha=0.3)

output = Path("static/images/finance/main/dividend_reinvestment.svg")
output.parent.mkdir(parents=True, exist_ok=True)
fig.tight_layout()
fig.savefig(output)

配当再投資シミュレーション結果


再投資による追加リターンの内訳 #

再投資がどの程度のリターン上乗せになったかを分離して確認します。

1
2
3
4
5
6
7
final_cash = total_value_cash.iloc[-1]
final_reinvest = total_value_reinvest.iloc[-1]
reinvest_bonus = final_reinvest - final_cash

print(f"現金保持の最終評価額:  {final_cash:.1f}")
print(f"再投資の最終評価額:    {final_reinvest:.1f}")
print(f"再投資による上乗せ:    {reinvest_bonus:.1f} ({reinvest_bonus/final_cash*100:.1f}%)")

CAGR(年平均成長率)の比較 #

長期投資の成果を比較するにはCAGR(Compound Annual Growth Rate)が有効です。

1
2
3
4
5
6
7
8
years = len(dates) / 12

cagr_cash = (total_value_cash.iloc[-1] / 100) ** (1 / years) - 1
cagr_reinvest = (total_value_reinvest.iloc[-1] / 100) ** (1 / years) - 1

print(f"CAGR(現金保持): {cagr_cash:.2%}")
print(f"CAGR(再投資):   {cagr_reinvest:.2%}")
print(f"差分:             {cagr_reinvest - cagr_cash:.2%}")

最大ドローダウンの比較 #

再投資シナリオでは保有株数が増えるため、下落局面での評価額の減少幅も大きくなります。リスク面も確認します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def max_drawdown(series: pd.Series) -> float:
    cummax = series.cummax()
    drawdown = (series - cummax) / cummax
    return drawdown.min()

mdd_cash = max_drawdown(total_value_cash)
mdd_reinvest = max_drawdown(total_value_reinvest)

print(f"最大ドローダウン(現金保持): {mdd_cash:.2%}")
print(f"最大ドローダウン(再投資):   {mdd_reinvest:.2%}")

実務に向けて #

  • 実際のデータを利用する際は、配当落ち日・支払日を考慮して再投資のタイミングを合わせます。
  • 海外株の場合は源泉徴収税や為替影響を考慮する必要があります。税引後配当を用意し、合計ネットリターンを比較するとより現実的です。
  • ポートフォリオ全体では、銘柄ごとの配当再投資をまとめて日次で行うか、一定金額が貯まった段階でまとめて再投資するなど、運用ルールを明示して検証しましょう。
  • DRIPプラン(配当再投資プラン)を提供する証券会社では手数料無料で自動再投資が可能なため、実装コストの違いも考慮に入れます。