ドルコスト平均法による積立投資で、毎日買うか、毎月1回買うか

TAGS :

ドルコスト平均法の検証

私は、投資信託を毎日xxx円購入するという積立投資をしています。
時間軸方向の分散投資です。
今までは、毎月1回購入よりも、毎日購入した方が、リスク分散はできているのかなと安易に思っていたのですが、ちゃんと検証してみたいと思います。
ドルコスト平均法が、リスク分散に有利というのはよく言われていますが、毎日購入と毎月購入のどちらに軍配が上がるのでしょうか。

検証する内容は以下です。

  • 毎日購入、毎月1回購入 (1日, 11日, 21日の3パターン) で比較する。非営業日の場合は、お休み明けの営業日に購入する。
  • 日経平均株価 (N225) と ダウ・ジョーンズ工業株価平均 (DJI) で比較する。
  • 投資期間は 5年間 とする。

株価データの取得

投資期間を5年間としたので、2017年6月1日 から 2022年5月31日 まで日経平均株価 (N225)NYダウ (DJI) の株価を取得します。
pandas-datareader を使います。
YahooDailyReader の公式ドキュメント のリンクも書いておきます。

Python

    from pandas_datareader.yahoo.daily import YahooDailyReader

    date_start = pd.to_datetime('2017-06-01 12:00:00', utc=True)
    date_end = pd.to_datetime('2022-05-31 12:00:00', utc=True)
    
    df_n225 = YahooDailyReader(
        symbols='^N225',
        start=date_start,
        end=date_end,
        ).read()
    
    df_dji = YahooDailyReader(
        symbols='^DJI',
        start=date_start,
        end=date_end,
        ).read()

以下のようなデータが取得できます。

High Low Open Close Volume Adj Close
Date
2017-06-01 19887.660156 19686.320312 19692.160156 19860.029297 103500000.0 19860.029297
2017-06-02 20239.810547 19967.000000 19970.230469 20177.279297 150400000.0 20177.279297
2017-06-05 20224.539062 20104.130859 20135.419922 20170.820312 99100000.0 20170.820312
2017-06-06 20152.949219 19948.019531 20122.259766 19979.900391 102000000.0 19979.900391
2017-06-07 20023.240234 19908.070312 19951.679688 19984.619141 99200000.0 19984.619141

終値で株価チャートを描いてみます。円とドルで単位は違うのですが、30,000 前後の価格なので、一つのグラフに描いてしまいます。

Python

    df_n225['Adj Close'].plot(label='N225 Adjust Close')
    df_dji['Adj Close'].plot(label='DJI Adjust Close')
    plt.legend()
    plt.grid(color='gray', linestyle='--', alpha=0.5)
    plt.show()

株価チャート

ドルコスト平均法で積立投資のシミュレーション

評価方法は、最終日 2022年5月31日 の終値で算出した評価額を使用します。
つまり、最終日の終値 ✕ 購入済株数 = 評価額 の高い方が勝ちです。
毎日購入の場合は、毎日千円購入します。NYダウの場合は1000ドル購入とします。
購入株数 = 千円 ÷ その日の終値 です。
毎月購入の場合は、その月の営業日数 ✕ 千円 が、その月の購入代金です。
購入株数 = 購入代金 ÷ 指定営業日の終値 です。

毎日購入の場合の 最終日の評価額 と 元金からの増加率 の算出式です。

Python

    def calc_dollarcost_daily(df, unit):
        total_shares = (1000/df['Adj Close']).cumsum().values[-1]
        final_price  = df.loc[df.index[-1], 'Adj Close']
        final_date_str = df.index[-1].strftime('%Y/%m/%d')
        total_invest = 1000 * len(df)

        print('[毎日購入] {}評価額: {:,.2f}{}  増加率: {:.2f}%'
            .format(
                final_date_str,
                final_price * total_shares,
                unit,
                ((final_price * total_shares) / total_invest - 1) * 100,
                ))
        return

毎月1回購入の場合の 最終日の評価額 と 元金からの増加率 の算出式です。

Python

    import pandas.tseries.offsets as offsets

    def calc_dollarcost_monthly(df, buy_day, unit):
        df['year'] = df.index.year
        df['month'] = df.index.month
        df['day'] = df.index.day

        total_shares = 0
        for year in np.unique(df['year'].values):
            for month in np.unique(df[df['year'] == year]['month'].values):
                # この月の営業日数を算出する。
                days = len(df[(df['year'] == year) & (df['month'] == month)])
                # この月の購入代金を算出する。1000円✕営業日数。
                purchase_amount = 1000 * days
                # 購入指定日の終値を取得する。
                # 購入指定日が営業日でない場合は、後ろへずらす。
                for i in range(0, 10): # 指定日から10日以内に営業日はあるはず。
                    purchase_index = pd.Timestamp(year, month, buy_day) + offsets.Day(i)
                    if purchase_index in df.index:
                        # 購入指定日に最も近い営業日が見つかったら、抜ける。
                        break
                purchase_price = df.at[purchase_index, 'Adj Close']
                # この月に購入した株数を算出する。
                purchase_shares = purchase_amount / purchase_price
                total_shares += purchase_shares
        final_price  = df.loc[df.index[-1], 'Adj Close']
        final_date_str = df.index[-1].strftime('%Y/%m/%d')
        total_invest = 1000 * len(df)

        print('[毎月{:>2}日に購入] {}評価額: {:,.2f}{}  増加率: {:.2f}%'
            .format(
                buy_day,
                final_date_str,
                final_price * total_shares,
                unit,
                ((final_price * total_shares) / total_invest - 1) * 100,
                ))
    return

以下のように、関数を呼び出します。

Python

    calc_dollarcost_daily(df_n225, unit='円')
    calc_dollarcost_monthly(df_n225, buy_day=1, unit='円')
    calc_dollarcost_monthly(df_n225, buy_day=11, unit='円')
    calc_dollarcost_monthly(df_n225, buy_day=21, unit='円')
    print('合計投資額: {:,}円' .format(1000*len(df_n225)))
    
    calc_dollarcost_daily(df_dji, unit='ドル')
    calc_dollarcost_monthly(df_dji, buy_day=1, unit='ドル')
    calc_dollarcost_monthly(df_dji, buy_day=11, unit='ドル')
    calc_dollarcost_monthly(df_dji, buy_day=21, unit='ドル')
    print('合計投資額: {:,}ドル' .format(1000*len(df_dji)))

シミュレーション結果

日経平均株価 (N255) の結果です。
成績は、毎月1日に購入、毎月11日に購入、毎日購入、毎月21日に購入 の順でした。
ちょっとショックでした。毎日購入が1位になる想定だったので。
計算時の端数処理の影響があるか (攻殻機動隊 S.A.C. 2nd GIG のクゼが使った技) と思い、毎日購入の関数をいじってみたのですが、影響は無さそうでした。

[毎日購入] 2022/05/31評価額: 1,421,158.81円 増加率: 16.68%
[毎月 1日に購入] 2022/05/31評価額: 1,425,612.61円 増加率: 17.05%
[毎月11日に購入] 2022/05/31評価額: 1,424,039.54円 増加率: 16.92%
[毎月21日に購入] 2022/05/31評価額: 1,419,850.40円 増加率: 16.57%
合計投資額: 1,218,000円

NYダウ (DJI) の結果です。
成績は、毎月1日に購入、毎月21日に購入、毎月11日に購入、毎日購入 の順でした。

[毎日購入] 2022/05/31評価額: 1,521,157.70ドル 増加率: 20.82%
[毎月 1日に購入] 2022/05/31評価額: 1,530,218.52ドル 増加率: 21.54%
[毎月11日に購入] 2022/05/31評価額: 1,522,395.41ドル 増加率: 20.92%
[毎月21日に購入] 2022/05/31評価額: 1,525,376.21ドル 増加率: 21.16%
合計投資額: 1,259,000ドル

5年間の積立投資シミュレーションの結果しか見ていませんが、これを受けて、毎日購入をやめ、複数の投資信託の購入日を分散させ、毎月1回購入 に切り替えるのもアリかと思いました。