Python
シミュレーション
投資

ドルコスト平均法をシミュレーションしてみた

More than 1 year has passed since last update.


はじめに

株や投資信託を購入する際の、買い方としてドルコスト平均法というものがあります。株や投資信託などの商品を定期的定額で購入することでリスクを低減できるというものです。

よく見るスライドでは、恣意的な株価/基準価格の遷移を仮定して書いてあったり、データ数が少なかったりして納得感が低いと感じていました。理論的にリスクが低減するのは明らかですが。そこで実際の投資信託の基準価格データをもとに、シミュレーションしてみようという試みです。


シミュレーションの前提


シミュレーションに使う投資信託

三井住友トラスト・アセットメントの外国株式インデックスe


評価指標

今回のシミュレーションでは購入を開始してから1年後のROIで比較します。

ROI = \frac{1年後保有資産 - 1年間投下金額}{1年間投下金額}


手法1(一括購入)

あるタイミングで一定額(10万円分)を購入します。


手法2(一定口数定期購入)

あるタイミングから1年間に渡って毎月25日に一定口数(1万円)を購入します。


手法3(一定金額定期購入)

あるタイミングから1年間に渡って毎月25日に一定金額(1万円)を購入します。


シミュレーション

購入開始時期を100通りに変化させて、結果のROI分布を比較することでリスク評価を行います。

import pandas as pd

df = pd.read_csv('http://www.smtam.jp/fund_data/csv/110057.csv',
names=['day', 'price', 'income', 'asset'], skiprows=1)
df.loc[:, 'day'] = pd.to_datetime(df.day)
print df.shape
df.head(10)

image

import matplotlib

import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, figsize=(12, 8))
df.plot('day', 'price', ax =ax, label=u'基準価格')
ax.set_ylabel(u'基準価格')
ax.set_xlabel(u'日付')

image

import  numpy as np

def package(timing):
num = []
invest = []
price = 100000
for i, r in df.iterrows():
if i == timing:
num_add = int(10000.0 * price/ r.price)
num.append(num[i-1] + num_add if len(num) > 0 else num_add)
invest.append(invest[i-1] + price if len(invest) > 0 else price)
else:
num.append(num[i-1] if len(num) > 0 else 0)
invest.append(invest[i-1] if len(invest) > 0 else 0)
return num, invest

def constant_num(start_timing):
num = []
invest = []
for i, r in df.iterrows():
if r.day.day == 25 and i >= start_timing:
num_add = 10000
invest_add = r.price
num.append(num[i-1] + num_add if len(num) > 0 else num_add)
invest.append(invest[i-1] + invest_add if len(invest) > 0 else invest_add)
else:
num.append(num[i-1] if len(num) > 0 else 0)
invest.append(invest[i-1] if len(invest) > 0 else 0)
return num, invest

def doller_cost(start_timing):
num = []
invest = []
price = 10000
for i, r in df.iterrows():
if r.day.day == 25 and i >= start_timing:
num_add = int(10000.0 * price/ r.price)
num.append(num[i-1] + num_add if len(num) > 0 else num_add)
invest.append(invest[i-1] + price if len(invest) > 0 else price)
else:
num.append(num[i-1] if len(num) > 0 else 0)
invest.append(invest[i-1] if len(invest) > 0 else 0)
return num, invest

def sim(function, label, color):
fig, ax = plt.subplots(1, figsize=(12, 8))
final_ratio = []
for i in np.arange(0, 100) * 10:
num, invest = function(i)
num = pd.Series(num)
invest = pd.Series(invest)
df.loc[:, 'ratio'] = (num * df.price / 10000.0 - invest.astype(float)) / invest.astype(float)
df.plot('day', 'ratio', ax=ax,alpha=0.1, color=color)

final_ratio.append(df.iloc[i + 365].ratio)
ax.set_title(label)
ax.set_ylabel('ROI')
ax.set_xlabel(u'日付')
ax.legend_.remove()
return final_ratio

package_ratio = sim(package, u'一括購入', 'blue')
constant_ratio = sim(constant_num, u'一定口数定期購入', 'green')
dc_ratio = sim(doller_cost, u'一定金額定期購入', 'red')

fig, ax = plt.subplots(1, figsize=(12, 8))
pd.Series(package_ratio).hist(ax=ax, color='blue', alpha=0.3, normed=True, label=u'一括購入')
pd.Series(constant_ratio).hist(ax=ax, color='green', alpha=0.3, normed=True, label=u'一定口数定期購入')
pd.Series(dc_ratio).hist(ax=ax, color='red', alpha=0.3, normed=True, label=u'一定金額定期購入')
ax.set_xlabel('ROI')
ax.set_ylabel('freq(normed)')
ax.legend()

image

image

image

image


わかったこと


  • 一括購入はROIの分散が大きいことがシミュレーション出来た

  • 定期定額購入と定期定量購入の違いはそんなに大きくなかった