Pythonで金融資産取り崩しシミュレーション

Pythonで金融資産の取り崩しシミュレーションを行ってみます。プログラミング言語が使えるとこういうシミュレーションをさっと作れるのが便利です。Excelなどの表計算で行うことも可能ですが慣れればこちらの方がはるかに簡単です。この記事では、ちょっとだけ複雑な条件の取り崩しシミュレーションをPythonで作成してみました。
資産取り崩しシミュレーションとは
「1000万円を年率4%で運用しながら毎年100万円ずつ取り崩した場合」などが資産取り崩しシミュレーションとしては一般的です。この手のやつならWebで数値を入力すれば計算してくれるサイトもたくさんあります。
せっかく自作するの、今回は少し凝ったシミュレーションを行いたいと思います
- 最初、現金〇円と運用資産〇円からスタート
- 運用資産は毎年年利〇%で運用
- 毎年、〇円ずつ現金を取り崩し
- 65歳からは年金が年間〇円受給できる
- 現金が〇円を切ったら、運用資産を取り崩して現金が〇円になるようにする
今回のシミュレーションでは、「支出は現金から行い、現金が一定額を下回ったら現金を補充しておく」という取り崩し戦略になります。この戦略のメリットは、運用している資産を毎年取り崩すわけではないので、暴落時に数年は耐えられる可能性があるということです。
また、年金の受給も加味するようにしました。
個人的には数年の生活資金は現金で保有しておく方がよいと思うので、このやり方が良さそうだと感じます。

もっと複雑なシミュレーションでも良かったですが、とりあえずこのシミュレーションでプログラムしてみます。
Pythonでプログラミング
ライブラリのインポート
import pandas as pd
import random
パラメータの設定
パラメータはconfig
というクラスにまとめました。パラメータは以下になります。
- 投資資産
investment_assets
は株や債券、投資信託などで保有する資産額です。rate
は想定する運用利率です。risk
は想定する変動幅です。運用利率は平均rate
, 偏差risk
の正規分布に従って変動するとします。 - 現金資産
現金がtrans_rate
を下回ったら、max_money
になるまで投資資産を売却して現金を補充します。cur_money
は、シミュレーション開始時の保有額です。 - 年間支出
年間支出(expand
)は生活費用です。 - 年金額
65歳から受け取れる年金額(pension
)です。 - シミュレーション期間と開始時年齢
シミュレーションする期間(years
)と、開始時の年齢(start_age
)です。
class config :
# 投資資産の部
investment_assets = 4000_0000 # 円
rate = 0.04 # 金利
risk = 0.15 # リスク
# 現金資産
max_money = 1000_0000 # 現金資産(円)
trans_rate = 300_0000 # これ以下になったら投資資産を現金化してmax_moneyまでお金を増やす
cur_money = 1000_0000 # 現金資産(円)
# 年間支出
expand = 15_0000 * 12 # 月の支出x12ヶ月
# 65歳からの年金額
pension = 100_0000 # 年金額
years = 40 # 期間
start_age = 50 # 開始年齢
例では、4000万円の投資資産、1000万円の現金を保有している状態からスタートです。年齢は50歳で年間180万円(15万円x12ヶ月)取り崩します。また、年金は65歳から年100万円、運用利率は4%を想定しています。
シミュレーションをプログラミング
do_sim
は、シミュレーションを行う関数です。引数として、config, output, use_risk
を受け取ります。
- output : 結果を画面に出力するかどうかのフラグです
- use_risk : リスクを含めた計算を行うかどうかのフラグです
def do_sim(config, output = True, use_risk = False) :
df = pd.DataFrame(columns=["年数", "年齢", "現金", "投資資産", "増分"])
cur_money = config.cur_money
investment_assets = config.investment_assets
for i in range(config.years) :
# 年の初めに切り崩す
cur_money -= config.expand
if config.start_age+i >= 65 :
cur_money += config.pension
if cur_money < config.trans_rate :
diff = min(config.max_money - cur_money, investment_assets)
cur_money += diff
investment_assets -= diff
# 年の終わりに金利をつける
rate = config.rate
if use_risk :
rate = random.gauss(config.rate, config.risk)
increase = int(investment_assets * rate)
investment_assets = investment_assets + increase
if output :
print(f"{i+1}年目 {config.start_age+i}歳 {cur_money/10000} {investment_assets/10000} {increase/10000}万円")
df.loc[len(df)] = [i+1, config.start_age+i, cur_money, investment_assets, increase]
return df
プログラムでは、初期の現金と資産額をcur_money
とinvestment_assets
に代入してfor
文で毎年の変化をシミュレーションしています。
このプログラムでは、期初に取り崩しを行い期末に利子がつく前提でのシミュレーションを行っています。

取り崩しと利子がつくタイミングは重要なので、きちんと考えて並べることが重要です。
まず、支出を現金から引いたあと、65歳を超えた場合、現在の現金保有額に年金分を加算しています。これがtrans_rate
を下回った場合は、金融資産を取り崩してmax_money
になるようにします。
risk=True
の場合は、ガウス分布(正規分布)による乱数をrate
に代入しています。これで、毎年の利率をリスク込みで計算できます。
最後にoutput=True
ならば結果を表示しています。
また、データフレーム(pandas)を作成して、それを戻り値として返しています。
以上がシミュレーション部分です。
実行結果
上記の関数を呼び出せば、シミュレーションが可能です。以下は、呼び出し部分です。また、結果をcsvファイル(result.csv
)として書き出しています。書き出したcsvファイルは、excelなどの表計算ソフトで読み込ませることができるので、結果を分析するのに役立ちます。
df = do_sim(config, use_risk=False, output=True)
print(f"年間支出: {config.expand/10000}万円 年金不足額: {(config.expand - config.pension)/10000}万円")
print("✅result.csvとして結果を書き出しました")
df.to_csv("result.csv", index=False)
リスクなしの計算
use_risk=False
と設定しているのでリスクなしの結果となります。
1年目 50歳 820.0 4160.0 160.0万円
2年目 51歳 640.0 4326.4 166.4万円
3年目 52歳 460.0 4499.456 173.056万円
4年目 53歳 1000.0 3930.6342 151.1782万円
5年目 54歳 820.0 4087.8595 157.2253万円
6年目 55歳 640.0 4251.3738 163.5143万円
7年目 56歳 460.0 4421.4287 170.0549万円
8年目 57歳 1000.0 3849.4858 148.0571万円
9年目 58歳 820.0 4003.4652 153.9794万円
10年目 59歳 640.0 4163.6038 160.1386万円
11年目 60歳 460.0 4330.1479 166.5441万円
12年目 61歳 1000.0 3754.5538 144.4059万円
13年目 62歳 820.0 3904.7359 150.1821万円
14年目 63歳 640.0 4060.9253 156.1894万円
15年目 64歳 460.0 4223.3623 162.437万円
16年目 65歳 380.0 4392.2967 168.9344万円
17年目 66歳 300.0 4567.9885 175.6918万円
18年目 67歳 1000.0 3939.508 151.5195万円
19年目 68歳 920.0 4097.0883 157.5803万円
20年目 69歳 840.0 4260.9718 163.8835万円
21年目 70歳 760.0 4431.4106 170.4388万円
22年目 71歳 680.0 4608.667 177.2564万円
23年目 72歳 600.0 4793.0136 184.3466万円
24年目 73歳 520.0 4984.7341 191.7205万円
25年目 74歳 440.0 5184.1234 199.3893万円
26年目 75歳 360.0 5391.4883 207.3649万円
27年目 76歳 1000.0 4858.3478 186.8595万円
28年目 77歳 920.0 5052.6817 194.3339万円
29年目 78歳 840.0 5254.7889 202.1072万円
30年目 79歳 760.0 5464.9804 210.1915万円
31年目 80歳 680.0 5683.5796 218.5992万円
32年目 81歳 600.0 5910.9227 227.3431万円
33年目 82歳 520.0 6147.3596 236.4369万円
34年目 83歳 440.0 6393.2539 245.8943万円
35年目 84歳 360.0 6648.984 255.7301万円
36年目 85歳 1000.0 6166.1433 237.1593万円
37年目 86歳 920.0 6412.789 246.6457万円
38年目 87歳 840.0 6669.3005 256.5115万円
39年目 88歳 760.0 6936.0725 266.772万円
40年目 89歳 680.0 7213.5154 277.4429万円
年間支出: 180.0万円 年金不足額: 80.0万円
✅result.csvとして結果を書き出しました
結果を見ると、資産は減るどころか増えることがわかります。つまり、5000万円で生活費が15万円の場合は、資産が尽きることはないという結果になりました。
ただ、これはリスクなしの場合です。次はリスクありで見てみます。
リスクありの計算
また、use_risk=True
として実行すると、リスク込みでの計算になります。
df = do_sim(config, use_risk=True, output=True)
print(f"年間支出: {config.expand/10000}万円 年金不足額: {(config.expand - config.pension)/10000}万円")
print("✅result.csvとして結果を書き出しました")
df.to_csv("result.csv", index=False)
以下は実行結果の例です。乱数を使っているので毎回実行結果が変わりますが、この結果では、89歳まで現金が残っていますが、投資資産の方は0になっていることがわかります。リスク込みだと運用益がマイナスになる場合もシミュレーションしますが、運用結果によっては資産が尽きる可能性があることがわかります。
1年目 50歳 820.0 3931.57 -68.43万円
2年目 51歳 640.0 4140.6425 209.0725万円
3年目 52歳 460.0 4158.3326 17.6901万円
4年目 53歳 1000.0 3625.4249 187.0923万円
5年目 54歳 820.0 3003.2911 -622.1338万円
6年目 55歳 640.0 2707.9751 -295.316万円
7年目 56歳 460.0 3109.3395 401.3644万円
8年目 57歳 1000.0 2352.8437 -36.4958万円
9年目 58歳 820.0 2479.03 126.1863万円
10年目 59歳 640.0 2227.1177 -251.9123万円
11年目 60歳 460.0 2348.1247 121.007万円
12年目 61歳 1000.0 1849.0847 220.96万円
13年目 62歳 820.0 1425.6908 -423.3939万円
14年目 63歳 640.0 1654.3115 228.6207万円
15年目 64歳 460.0 1753.5699 99.2584万円
16年目 65歳 380.0 1440.301 -313.2689万円
17年目 66歳 300.0 2029.8225 589.5215万円
18年目 67歳 1000.0 1144.6578 -105.1647万円
19年目 68歳 920.0 1047.8327 -96.8251万円
20年目 69歳 840.0 1148.6058 100.7731万円
21年目 70歳 760.0 1178.185 29.5792万円
22年目 71歳 680.0 1055.3492 -122.8358万円
23年目 72歳 600.0 1215.2226 159.8734万円
24年目 73歳 520.0 1044.316 -170.9066万円
25年目 74歳 440.0 767.101 -277.215万円
26年目 75歳 360.0 933.8227 166.7217万円
27年目 76歳 1000.0 197.5808 -16.2419万円
28年目 77歳 920.0 237.564 39.9832万円
29年目 78歳 840.0 266.4157 28.8517万円
30年目 79歳 760.0 298.2605 31.8448万円
31年目 80歳 680.0 305.7651 7.5046万円
32年目 81歳 600.0 358.5157 52.7506万円
33年目 82歳 520.0 385.4211 26.9054万円
34年目 83歳 440.0 420.4307 35.0096万円
35年目 84歳 360.0 452.5869 32.1562万円
36年目 85歳 732.5869 0.0 0.0万円
37年目 86歳 652.5869 0.0 0.0万円
38年目 87歳 572.5869 0.0 0.0万円
39年目 88歳 492.5869 0.0 0.0万円
40年目 89歳 412.5869 0.0 0.0万円
年間支出: 180.0万円 年金不足額: 80.0万円
✅result.csvとして結果を書き出しました
ソースコード全体
以下、全体のコードです
# 資産取り崩しシミュレーション
import pandas as pd
import random
class config :
# 投資資産の部
investment_assets = 4000_0000 # 円
rate = 0.04 # 金利
risk = 0.15 # リスク
# 現金資産
max_money = 1000_0000 # 現金資産(円)
trans_rate = 300_0000 # これ以下になったら投資資産を現金化してmax_moneyまでお金を増やす
cur_money = 1000_0000 # 現金資産(円)
# 年間支出
expand = 15_0000 * 12 # 月の支出x12ヶ月
# 65歳からの年金額
pension = 100_0000 # 年金額
years = 40 # 期間
start_age = 50 # 開始年齢
#
# ルール:
# - 資産は毎年rateで増える
# - 現金は初期でmax_money持っている
# - 現金がtrans_rateより少なくなったら投資資産を売却して現金をmax_moneyだけ用意する
# - 毎年、expandだけ支出する
# - years期間の間運用して切り崩した場合をシミュレーション
#
def do_sim(config, output = True, use_risk = False) :
df = pd.DataFrame(columns=["年数", "年齢", "現金", "投資資産", "増分"])
cur_money = config.cur_money
investment_assets = config.investment_assets
for i in range(config.years) :
# 年の初めに切り崩す
cur_money -= config.expand
if config.start_age+i >= 65 :
cur_money += config.pension
if cur_money < config.trans_rate :
diff = min(config.max_money - cur_money, investment_assets)
cur_money += diff
investment_assets -= diff
# 年の終わりに金利をつける
rate = config.rate
if use_risk :
rate = random.gauss(config.rate, config.risk)
increase = int(investment_assets * rate)
investment_assets = investment_assets + increase
if output :
print(f"{i+1}年目 {config.start_age+i}歳 {cur_money/10000} {investment_assets/10000} {increase/10000}万円")
df.loc[len(df)] = [i+1, config.start_age+i, cur_money, investment_assets, increase]
return df
df = do_sim(config, use_risk=True, output=True)
print(f"年間支出: {config.expand/10000}万円 年金不足額: {(config.expand - config.pension)/10000}万円")
print("✅result.csvとして結果を書き出しました")
df.to_csv("result.csv", index=False)
まとめ
Pythonで取り崩しシミュレーションを作成してみました。細かなシチュエーションを想定してシミュレーションする場合は、Excelなどの表計算ソフトを使うより、プログラミングした方が格段に楽です。
今回は簡単なプログラムにしましたが、「マイナス利益だった年はギリギリまで売却を遅らせてまつ」などの条件を組み込むことも簡単です。いろいろ試してみると面白いと思います。