「複利がすごい」という話は何度も聞いた。でも、具体的にいくら増えるのか、自分の積立条件で試したことはありますか? 表の数字を眺めるだけでは、複利の「加速する感覚」は腹落ちしません。
筆者は製造業の開発現場で、DX推進やデータ分析に携わるエンジニアです。ものづくりの現場では「理論値を自分で計算して確かめる」ことが当たり前ですが、投資となると不思議と「誰かの結論」をそのまま信じてしまう人が多いように感じます。
この記事では、Pythonで複利の効果を3パターンで可視化します。所要時間は約30分。読み終わる頃には、自分の積立条件(月額・年利・期間)を入れるだけで将来の資産額を計算できるようになります。(記事#01から読み始めるのがおすすめです。前回の記事#02では、インデックス投資の合理性をDX3原則で分解しました。)
結論:複利は「知っている」と「自分で計算して確かめた」の間に大きな差がある。エンジニアなら、コードで腹落ちさせよう。
動作環境
- Python 3.11 / matplotlib 3.8 / numpy 1.26
- Google Colab でもローカル環境でも動作します
- 所要時間:約30分(コードのコピペ+実行+条件変更)
免責事項
本記事は投資助言を目的としたものではなく、技術・分析手法の紹介です。記事中の情報は教育目的であり、特定の銘柄・金融商品の売買を推奨するものではありません。投資判断はご自身の責任で行ってください。
そもそも複利とは何か:数式で理解する
複利の計算式は、エンジニアならすぐに理解できるシンプルな式です。
複利の基本式
将来の資産 = 元本 × (1 + 年利率) ^ 年数
例:100万円を年利7%で30年運用した場合
100万 × (1.07)^30 = 約761万円
※ インフレ考慮前の名目額です。実質購買力は年2〜3%のインフレを想定すると約4.4倍相当になります。
ポイントは 指数関数 であることです。線形(直線的)ではなく、時間が経つほど加速度的に増える。この「加速する感覚」を、グラフで実感してみましょう。
実装①:年利別の資産成長をグラフで比較する
まずは最もシンプルなケースから。100万円を一括投資して、年利5%・7%・10%で30年間運用した場合の資産推移を可視化します。
import matplotlib.pyplot as plt
import numpy as np
# --- 日本語フォントの設定(環境に合わせて変更してください) ---
# Mac: plt.rcParams['font.family'] = 'Hiragino Sans'
# Windows: plt.rcParams['font.family'] = 'Yu Gothic'
# Linux: plt.rcParams['font.family'] = 'Noto Sans CJK JP'
# --- 設定 ---
initial: float = 100 # 初期投資額(万円)
years: int = 30
rates: list[float] = [0.05, 0.07, 0.10] # 年利 5%, 7%, 10%
labels: list[str] = ["5%", "7%", "10%"]
colors: list[str] = ["#38a169", "#3182ce", "#805ad5"] # 基礎/応用/発展カラー
# --- 複利計算 ---
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(0, years + 1)
for rate, label, color in zip(rates, labels, colors):
y = initial * (1 + rate) ** x
ax.plot(x, y, label=f"年利 {label}", color=color, linewidth=2.5)
# --- 単利(参考線) ---
y_simple = initial * (1 + 0.07 * x)
ax.plot(x, y_simple, label="単利 7%(参考)", color="#718096",
linewidth=1.5, linestyle="--")
# --- グラフ装飾 ---
ax.set_xlabel("年数", fontsize=12)
ax.set_ylabel("資産額(万円)", fontsize=12)
ax.set_title("複利の効果:年利別の資産成長(初期投資100万円)", fontsize=14)
ax.legend(fontsize=11)
ax.grid(True, alpha=0.3)
ax.set_xlim(0, years)
ax.set_ylim(0, 2000)
plt.tight_layout()
plt.savefig("compound_interest_comparison.png", dpi=150)
plt.show()
このコードを実行すると、以下のことが一目でわかります。
- 最初の10年はどの年利もほぼ同じに見える(差が小さい)
- 20年を超えると急激に差が開く(指数関数の特徴)
- 単利(点線)と複利の差が後半になるほど圧倒的に広がる
エンジニア的に言い換えると
複利は O(e^n) 、単利は O(n) です。アルゴリズムの計算量を考える時と同じで、入力(年数)が大きくなるほど指数関数の方が圧倒的に大きくなる。この直感は、投資期間の設計に直結します。
実装②:毎月3万円の積立投資をシミュレーションする
一括投資で100万円を用意できる人は多くありません。現実的なのは毎月コツコツ積み立てるパターンです。毎月3万円を年利7%で積立投資した場合をシミュレーションしてみましょう。
import matplotlib.pyplot as plt
import numpy as np
# --- 設定 ---
monthly: float = 3 # 毎月の積立額(万円)
annual_rate: float = 0.07
months_list: list[int] = [10 * 12, 20 * 12, 30 * 12] # 10年, 20年, 30年
monthly_rate: float = annual_rate / 12
# --- 積立複利計算 ---
def calc_tsumitate(monthly_amount: float, monthly_rate: float, total_months: int) -> list[float]:
"""毎月の積立複利を計算し、月次の資産推移を返す"""
balance: list[float] = []
total: float = 0
for m in range(1, total_months + 1):
total = (total + monthly_amount) * (1 + monthly_rate)
balance.append(total)
return balance
# --- 30年分のシミュレーション ---
max_months: int = 30 * 12
balance = calc_tsumitate(monthly, monthly_rate, max_months)
principal = [monthly * (m + 1) for m in range(max_months)] # 元本累計
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(1, max_months + 1) / 12 # 年に変換
ax.fill_between(x, principal, alpha=0.3, color="#718096", label="元本累計")
ax.fill_between(x, balance, principal, alpha=0.3, color="#3182ce", label="運用益")
ax.plot(x, balance, color="#3182ce", linewidth=2.5, label="資産総額")
ax.plot(x, principal, color="#718096", linewidth=1.5, linestyle="--")
# --- マイルストーン表示 ---
milestones: dict[int, str] = {10: "#38a169", 20: "#3182ce", 30: "#805ad5"}
for year, color in milestones.items():
idx = year * 12 - 1
ax.plot(year, balance[idx], "o", color=color, markersize=10, zorder=5)
ax.annotate(f"{year}年: {balance[idx]:.0f}万円",
xy=(year, balance[idx]),
xytext=(year + 1, balance[idx] + 200),
fontsize=10, color=color, fontweight="bold",
arrowprops=dict(arrowstyle="->", color=color))
ax.set_xlabel("年数", fontsize=12)
ax.set_ylabel("資産額(万円)", fontsize=12)
ax.set_title("毎月3万円 × 年利7% の積立シミュレーション", fontsize=14)
ax.legend(fontsize=11, loc="upper left")
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 30)
plt.tight_layout()
plt.savefig("tsumitate_simulation.png", dpi=150)
plt.show()
実行結果を表にまとめます。
| 期間 | 元本累計 | 資産総額 | 運用益 | 運用益の割合 |
|---|---|---|---|---|
| 10年 | 360万円 | 約519万円 | +159万円 | 31% |
| 20年 | 720万円 | 約1,563万円 | +843万円 | 54% |
| 30年 | 1,080万円 | 約3,660万円 | +2,580万円 | 70% |
※ 上記はすべてインフレ考慮前の名目額です。年2〜3%のインフレを想定すると、30年後の実質購買力は名目額の約55〜75%程度になります。
注目すべきポイントは2つです。
- 30年後の資産の70%が運用益:自分が入れたお金(元本)よりも、お金が生んだお金の方が多い
- 後半10年(20年→30年)の増加額が圧倒的:20年目の1,563万円から30年目の3,660万円へ、たった10年で+2,097万円。最初の20年で貯めた額を超えている
ポイント:「時間」が最大の武器
このシミュレーションから見えるのは、「いくら積み立てるか」よりも「いつ始めるか」の方がインパクトが大きいということです。毎月5万円を20年積み立てるよりも、毎月3万円を30年積み立てた方が資産総額は大きくなります。DXの「仕組みを早く作って長く回す」と全く同じ構造です。
実装③:「72の法則」をコードで検証する
投資の世界で有名な暗算テクニックに「72の法則」があります。
72の法則
資産が2倍になるまでの年数 ≒ 72 ÷ 年利(%)
例:年利7%なら → 72 ÷ 7 ≒ 約10.3年で2倍
本当にこの近似は正しいのか? エンジニアなら検証してみましょう。
import numpy as np
print(f"{'年利':>6} | {'72の法則':>8} | {'実際の年数':>10} | {'誤差':>6}")
print("-" * 45)
for rate_pct in range(1, 21):
rate: float = rate_pct / 100
# 72の法則
rule72: float = 72 / rate_pct
# 実際の年数: 2 = (1 + r)^n → n = ln(2) / ln(1 + r)
actual: float = np.log(2) / np.log(1 + rate)
error: float = abs(rule72 - actual) / actual * 100
print(f"{rate_pct:>5}% | {rule72:>7.1f}年 | {actual:>9.1f}年 | {error:>5.1f}%")
実行結果(一部抜粋):
| 年利 | 72の法則 | 実際の年数 | 誤差 |
|---|---|---|---|
| 3% | 24.0年 | 23.4年 | 2.5% |
| 5% | 14.4年 | 14.2年 | 1.4% |
| 7% | 10.3年 | 10.2年 | 0.4% |
| 10% | 7.2年 | 7.3年 | 0.9% |
| 15% | 4.8年 | 5.0年 | 3.6% |
| 20% | 3.6年 | 3.8年 | 5.2% |
結果から分かること:
- 年利5〜10%の範囲では誤差1%程度で非常に正確
- 年利が極端に高い(15%以上)と誤差が大きくなる
- インデックス投資の想定利回り(5〜8%)では「72の法則」はほぼ正確
エンジニア的に言い換えると
72の法則は ln(2) ≒ 0.693 の近似です。72 / r ≒ 0.693 / ln(1+r/100)。低い利率ではテイラー展開の第一項で十分な近似になるため、精度が高い。これは工学でよく使う「小角度近似(sinθ ≒ θ)」と同じ発想です。
応用:自分の条件でシミュレーションしてみよう
ここまでのコードを関数化して、自分の条件で簡単にシミュレーションできるようにしましょう。v1のコードに TypedDict と型ヒントを追加して、再利用しやすい形に整えます。
from typing import TypedDict
class SimulationResult(TypedDict):
"""積立投資シミュレーションの結果を表す型"""
元本: str
資産総額: str
運用益: str
運用益率: str
倍率: str
二倍到達: str
def simulate_tsumitate(
monthly_万円: float,
annual_rate_pct: float,
years: int,
) -> SimulationResult:
"""積立投資のシミュレーション
Args:
monthly_万円: 毎月の積立額(万円)
annual_rate_pct: 年利(%)例: 7
years: 投資期間(年)
Returns:
SimulationResult: 元本、資産総額、運用益などの計算結果
"""
monthly_rate: float = (annual_rate_pct / 100) / 12
total_months: int = years * 12
balance: float = 0
for _ in range(total_months):
balance = (balance + monthly_万円) * (1 + monthly_rate)
principal: float = monthly_万円 * total_months
profit: float = balance - principal
return SimulationResult(
元本=f"{principal:,.0f}万円",
資産総額=f"{balance:,.0f}万円",
運用益=f"+{profit:,.0f}万円",
運用益率=f"{profit / principal * 100:.1f}%",
倍率=f"{balance / principal:.1f}倍",
二倍到達=f"約{72 / annual_rate_pct:.0f}年(72の法則)",
)
# --- 自分の条件を入れてみよう ---
print("=== 毎月3万円 × 年利7% × 30年 ===")
result = simulate_tsumitate(monthly_万円=3, annual_rate_pct=7, years=30)
for k, v in result.items():
print(f" {k}: {v}")
print()
print("=== 毎月5万円 × 年利5% × 20年 ===")
result = simulate_tsumitate(monthly_万円=5, annual_rate_pct=5, years=20)
for k, v in result.items():
print(f" {k}: {v}")
print()
print("=== 毎月1万円 × 年利7% × 40年 ===")
result = simulate_tsumitate(monthly_万円=1, annual_rate_pct=7, years=40)
for k, v in result.items():
print(f" {k}: {v}")
出力例:
=== 毎月3万円 × 年利7% × 30年 ===
元本: 1,080万円
資産総額: 3,660万円
運用益: +2,580万円
運用益率: 238.9%
倍率: 3.4倍
二倍到達: 約10年(72の法則)
=== 毎月5万円 × 年利5% × 20年 ===
元本: 1,200万円
資産総額: 2,055万円
運用益: +855万円
運用益率: 71.3%
倍率: 1.7倍
二倍到達: 約14年(72の法則)
=== 毎月1万円 × 年利7% × 40年 ===
元本: 480万円
資産総額: 2,625万円
運用益: +2,145万円
運用益率: 446.9%
倍率: 5.5倍
二倍到達: 約10年(72の法則)
3つ目の例が印象的です。毎月たった1万円でも、40年続ければ2,625万円。運用益率は447%で、入れたお金の5.5倍がリターンとして返ってくる計算です(インフレ考慮前の名目額。実質購買力は約4.4倍相当になります)。
もちろん、これは年利7%が40年間続いた場合の理論値です。実際の市場は上下しますが、S&P500の過去100年の平均がまさにこの水準であることは、記事#02で確認した通りです。次回の記事#04では、実データを使ってこの理論値がどの程度現実と一致するかを検証します。
DX思考:1回きりコード vs 再利用コード
ここで TypedDict と型ヒントを追加したのは、単なる「お作法」ではありません。エンジニアなら「1回きりのスクリプト」と「再利用できる関数」の違いを知っているはずです。
- 1回きりのコード:動けばOK。でも、条件を変えるたびにコード本体を書き換える必要がある
- 再利用コード:引数と戻り値の型を明示することで、他の人(未来の自分を含む)が安心して使える
投資シミュレーションは、条件を何度も変えて試すものです。だからこそ「関数化+型定義」で再利用性を高めることに意味があります。これはDXの「自動化」原則そのものです。
本業で痛感した「1回きりコード」の限界
「再利用できるコード」の重要性は、筆者が本業で痛感した経験から来ています。
製造業の開発現場では、実験データの分析が日常的に発生します。筆者が担当したあるプロジェクトでは、モーターの性能試験データを毎週分析してレポートにまとめる必要がありました。
最初は「Excelマクロ」で対応していました。VBAでグラフを自動生成するマクロを書いて、毎週の分析作業を効率化した——つもりでした。
ところが、3ヶ月後に問題が起きました。試験条件が変わり、データのフォーマットが変更されたのです。Excelマクロはセル位置をハードコーディングしていたため、フォーマット変更に対応するには、マクロ全体を書き直す必要がありました。しかも、マクロの中身を書いた筆者自身が、3ヶ月前のコードの意図を思い出せない状態でした。
この失敗をきっかけに、筆者は分析コードをPythonスクリプトに置き換えました。関数化して、引数でデータパスや条件を渡せるようにし、型ヒントとdocstringを丁寧に書きました。結果として、試験条件が変わっても引数を変えるだけで対応でき、同僚も安心してコードを再利用できるようになりました。
投資に置き換えると
「Excelで複利計算した表を1回作って満足する」のは、1回きりのマクロと同じです。条件(月額、年利、期間)を変えて何度も試せる関数を持っておくことで、「自分の状況が変わった時にすぐ再計算できる」という安心感が生まれます。これが「仕組みを持つ」ということです。
まとめ:複利を「知っている」から「確かめた」へ
この記事で実装した3つのコードから見えたことをまとめます。
- 複利は指数関数。後半になるほど加速する。「早く始めて長く続ける」ことの数学的な根拠
- 30年の積立投資では、資産の70%が運用益。時間を味方にすれば、元本よりも「お金が生んだお金」の方が大きくなる
- 72の法則は年利5〜10%で誤差1%以下。インデックス投資の想定利回りでは十分実用的な暗算ツール
「複利がすごい」ということは誰もが聞いたことがあるはずです。でも、自分の手でコードを書いて、グラフを描いて、数字を確認する——この体験を経ると、「知っている」が「確信している」に変わります。
これが、エンジニアの「検証する力」の価値です。
今日からできる3つのアクション
「複利の効果はわかった。でも、具体的に何から始めればいい?」——そんな方のために、今日すぐにできることを3つ挙げます。
アクション1:自分の条件でシミュレーションを実行する
この記事の simulate_tsumitate 関数をコピーして、自分の条件で実行してみてください。
- 毎月の積立可能額:手取りの10〜20%が目安(例:手取り25万円なら2.5〜5万円)
- 年利の想定:インデックス投資なら5〜7%が現実的な範囲
- 投資期間:定年までの年数を入力してみる
数字を変えて何パターンも試すことで、「自分の場合はどうなるか」が見えてきます。
アクション2:コードを改造して理解を深める
エンジニアなら、コードを読むだけでなく「改造する」ことで理解が深まります。例えば以下の改造を試してみてください。
- 年利をマイナス(-10%の暴落年を含む)にして、暴落後の回復をシミュレーション
- 途中で積立額を増やす(昇給シミュレーション)パターンを追加
- インフレ率を引いた「実質リターン」でグラフを描き直す
アクション3:次回の記事で実データと比較する
今回のシミュレーションは理論値です。次回の記事#04では、S&P500の実際の株価データを使って、この理論値がどの程度現実と一致するかを検証します。記事#01で触れた「データドリブン」の実践編です。Python環境の準備がまだの方は、Google Colabでも動作しますので、アカウントだけ用意しておいてください。
次回予告:インデックス vs 個別株、20年分のデータで検証
次回(記事#04)では、S&P500と個別株(Apple, Toyota等)の実際のリターンを20年分のデータで比較します。
- yfinanceで株価データを取得する方法
- インデックスと個別株のリターン・リスク(標準偏差)を比較
- 「個別株で勝てるのか?」をデータで検証する
今回は理論値でのシミュレーションでしたが、次回はいよいよ実データを扱います。コードのチラ見せです。
import yfinance as yf
# S&P500 と個別株の20年分データを取得
sp500 = yf.download("^GSPC", start="2004-01-01", end="2024-01-01")["Close"]
apple = yf.download("AAPL", start="2004-01-01", end="2024-01-01")["Close"]
# 累積リターンを比較(次回の記事で詳しく実装します)
シリーズ全体像:投資×DX 3段階モデル
- 基礎編 #01〜#10:インデックス投資 × DX思想(標準化・データドリブン・自動化)
- 応用編 #11〜#20:高配当株 × データパイプライン(Python自動スクリーニング)
- 発展編 #21〜#30:成長株CAN-SLIM × アーキテクチャ設計力
投資の具体的な始め方は記事#09「NISA・iDeCoの最適活用をエンジニア的に設計する」で詳しく解説予定です。
免責事項
本記事は投資助言を目的としたものではなく、技術・分析手法の紹介です。投資判断はご自身の責任で行ってください。

コメント