口下手エンジニアの悪あがき

自動車エンジニアのつぶやき

かゆい所に手が届く積立シミュレーションをpythonで#3

積立シミュレーションで毎月の積立額を途中で1回変更するプログラムを前回完成させましたが、次はせっかくのプログラミングであるので、1回変更するだけ、というのは寂しいものがあります。  

ganbaruengineer.hatenablog.com

そもそも積立というものは人それぞれのライフステージのもとに計画的に決めていくわけで、単身生活、夫婦2人暮らし、子ども家族、子どもの受験、などなど、例えば下図のようにライフステージは何回も何回も目まぐるしく変わります。そのステージに合わせて細かくシミュレーションしていくことで、将来の不安が軽減するというものです。  

図1.ライフステージにおける積立額の変化

そこで、前回のプログラムをさらに拡張して「積立額変更1回」から「積立額の変更を任意のn回実施できる」シミュレーションにしたいと思います。

変数の設定

積立額、積立期間を複数(n回)実施することになるため、それらの変数を複数個設定する必要がありますが、何回やるかはその都度設定したいために、プログラムの中で何回変更するかをあらかじめ決めておくわけにはいきませんから、単独の変数ではなくリストに格納しようと思います。  

変数 内容
seed_money 初期投資金額 整数型(int)
amount_accum 毎月の積立額 リスト型
num_years 積立年数 リスト型
annual_rate 年利 整数型(int)

「毎月の積立額」「積立年数」を積立変更回数分の長さリストで作成し、2つのリストを同じ長さにすることで、変更回数と積立額、積立年数を同時に設定できます。

たとえば、毎月の積立額推移を(10万、5万、3万)として、それぞれの積立期間を(5年、10年、3年)としたとすると、以下のようにします。

amount_accum = [10, 5, 3]
num_years = [5, 10, 3]

その時に、変更回数を「nth」として、

nth = len(amount_accum)

として計算できます。

積立額累積値のリスト化

n回変更した積立額の累積値(deposit)をあとでグラフにするために、リストに格納しておきます。

deposit = [0]
for i in range(nth):
    deposit.append(deposit[i] + amount_accum[i]*12*num_years[i])

積立変更回数(n回)分のループ計算

今では単独の積立期間に対して、年数ごとのループ計算をしていましたが、それをさらにn回分分けてループ計算する必要があるので、ループを入れ子にしてn回分のループを回します。

for j in range(nth):
    for i in range(num_years[j]):
        asset_now = npf.fv(annual_rate/12/100, 12, -amount_accum[j], -asset_now)
        lst_total.append(int(asset_now))
        lst_gain.append(lst_total[-1] - seed_money - deposit[j] - (i+1)*amount_accum[j]*12)
        lst_deposit.append(deposit[j]+(i+1)*amount_accum[j]*12)

まあ変更点はこれだけです、なんと第2回目のコードより短くなりました。プログラミングって感じがしますね。

例えば、初期投資100万円、毎月の積立額(10万、5万、3万)、積立年数(5年、10年、3年)、年利5%としたとすると、

変数 内容 数値
seed_money 初期投資金額 100
amount_accum 毎月の積立額 [10, 5, 3]
num_years 積立年数 [5, 10, 3]
annual_rate 年利 5

で計算してみると、

図2.積立変更3回時のシミュレーション結果

ちゃんと計算できている感じですね。

全コード

import numpy as np
import numpy_financial as npf
import matplotlib.pyplot as plt

def calc(seed_money, amount_accum, num_years, annual_rate=5):
    nth = len(amount_accum)
    asset_now = seed_money
    lst_seed = [seed_money]*(sum(num_years)+1)
    lst_gain = [0]
    lst_deposit = [0]
    lst_total = [seed_money]

    deposit = [0]
    for i in range(nth):
        deposit.append(deposit[i] + amount_accum[i]*12*num_years[i])

    for j in range(nth):
        for i in range(num_years[j]):
            asset_now = npf.fv(annual_rate/12/100, 12, -amount_accum[j], -asset_now)
            lst_total.append(int(asset_now))
            lst_gain.append(lst_total[-1] - seed_money - deposit[j] - (i+1)*amount_accum[j]*12)
            lst_deposit.append(deposit[j]+(i+1)*amount_accum[j]*12)

    t = [i for i in range(sum(num_years) + 1)]
    fig, ax = plt.subplots(figsize=(10,5))
    ax.bar(t, lst_seed,label="initial investment")
    ax.bar(t, lst_deposit,bottom=lst_seed,label="amount of deposit")
    ax.bar(t,lst_gain,bottom=[i+j for i,j in zip(lst_seed,lst_deposit)],label="gain")

    text_y1 = [0.4 * i+seed_money for i in lst_deposit]
    text_y2 = [0.3 * j + i + seed_money for i,j in zip(lst_deposit,lst_gain)]
    for i in range(len(lst_deposit)):
        ax.text(t[i],seed_money*0.4,seed_money, ha="center",size=9)
        ax.text(t[i],text_y1[i],lst_deposit[i], ha="center", size=9)
        ax.text(t[i],text_y2[i],lst_gain[i], ha="center", size=9)
        ax.text(t[i],lst_total[i]+lst_total[-1]/50,lst_total[i],ha="center", size=10, color="k")
    plt.grid(axis='y')
    plt.xticks([i for i in range(sum(num_years)+1)])
    plt.xlabel("Number of Years")
    plt.ylabel("Amount of money(10,000yen)")
    plt.legend()
    plt.show()

annual_rate = 5
seed_money = 100
amount_accum = [10,5,3]
num_years = [5,10,3]

calc(seed_money, amount_accum, num_years, annual_rate)

貯金すらまともにできていませんが この先ずっとお金に困らない方法を教えてください!