乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

投資

最近、積立NISAなるものが
流行ってるみたいなので
シミュレーターを作ってみました。


解説動画はこちら



そもそも、積立NISAとは?
 
2018年1月より開始された
少額投資非課税制度のことで
非課税投資枠が年間40万円で
投資期間が最長20年になります

詳細はこちらをみていただければと思います

金融庁・積立NISA

今回は金融庁が出している
シミュレーターを真似して作ってみました

金融庁・資産運用シミュレーション

こんな感じのをPythonで作ってみます

コードはこんな感じです

from matplotlib import pyplot as plt
import numpy as np
import ipywidgets as widgets
from IPython.display import display
import warnings
warnings.simplefilter('ignore')

# 積立NISAシミュレーター
def show_widgets():
    button = widgets.Button(description='シミュレーション')
    s1 = widgets.IntSlider(value=20000  , min=1000 , max=33000  , step=1000   , description='月の積立金:')
    s2 = widgets.FloatSlider(value=4.0, min=0.1, step=0.1, max=10.0, description='利率:')
    s3 = widgets.IntSlider(value=10  , min=1 , max=20  , step=1 , description='年数:')
    output0 = widgets.Output(layour={'border': '1px solid black'})
    output1 = widgets.Output()
    fig = plt.figure(figsize=(12,6))
    ax = plt.gca()
    
    # クリック時の実行
    def on_click(b: widgets.Button) -> None:
        ax.clear()
        reserve = s1.value
        rate = s2.value
        year = s3.value
        rand_y1,rand_y2 = [],[]
        money,cost = 0,0
        for i in range(1,year+1):
            money += reserve * 12
            cost += reserve * 12
            money = int(money*(1+rate/100))
            diff = money - cost
            rand_y1.append(cost)
            rand_y2.append(diff)
        
        # 棒グラフの描画
        x = list(range(1,len(rand_y1)+1))        
        p1=ax.bar(x , rand_y1)
        p2=ax.bar(x , rand_y2 , bottom=rand_y1)
        l1=list(map(lambda x:'{0:.1f}万円'.format(x/10000), rand_y1))
        l2=list(map(lambda x:'{0:.1f}万円'.format(x/10000), rand_y2))
        l3=list(map(lambda x:'{0:.1f}万円'.format((x[0]+x[1])/10000), zip(rand_y1,rand_y2)))
        # 棒グラフのテキストラベル
        for i in range(len(x)):
            if len(x)<=10:
                size = 10
            elif len(x)<=15:
                size = 8
            elif len(x)<=20:
                size = 7
            else:
                size = 5
            
            ax.text(i +1, rand_y1[i]/2, l1[i], ha='center', color='black',size =size)
            ax.text(i +1, rand_y1[i] + rand_y2[i]/2, l2[i], ha='center', color='black',size =size)
            ax.text(i +1, rand_y1[i] + rand_y2[i] + 20000 , l3[i], ha='center', color='orange',size =size)
        ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: "{:,}".format(int(x))))
        
        with output0:
            output0.clear_output(wait=True)
            out_text = '積立金額 : {0:_>9}円 \n合計利息 : {1:_>9}円 \n最終金額 : {2:_>9}円'
            out = out_text.format(cost , diff , money)
            print(out)
        with output1:
            output1.clear_output(wait=True)
            display(ax.figure)
             
    button.on_click(on_click)
    box1 = widgets.Box([s1,s2])
    box2 = widgets.Box([s3,button])
    display(box1 , box2 , output0 , output1)
    plt.close()
    button.click()
     
show_widgets()

一応GoogleColabでも動くと思うので
試したい方はコピペして
動かしてみてください

ただし、棒グラフの万円の漢字部分が
表示されないだろうと思うので
ご了承下さい

コードのポイントとしては
月の積立金
利率
年数

スライダーで可変にして
これを入力として受け取ります

最終結果は年数分の利息を計算して
積立額にプラスして
最終結果と棒グラフに表示させます

年間40万円までなので
月額は33千円程度が限界ですかね?

これで利率4%だと
10、20年でこうなります。

スクリーンショット 2022-10-15 16.58.26
スクリーンショット 2022-10-15 16.59.18

10年だと積立金額の1.25倍
20年だと積立金額の1.5倍
くらいにはなりそうですね

とはいえ
この制度は始まったばかり
20年後に残っている保証も無いです

毎年必ず4%の利息が貰える
保証もありません

特に今は投資関連が
戦争やら円安やらで
ゲロやばそうな状況ですね

投資をするなら
自己責任でお願いいたします

今日はここまでです
それでは


今回は今話題のFIREについて
検証用のプログラムを作ってみました。

解説動画はこちら




三度の飯よりお金が好きな
乙pyです。

今話題のFIREとは?

Financial Independence , Retire Early
経済的自立と早期リタイアという
訳になると思いますが
資産を手に入れて経済的な自立を
手に入れようというものです。


FIREの目安

月々の生活費の25倍の資産を持つのが目安で
利率4%(5%運用で1%税引き)で運用すれば
生活費=運用益なので資産が減らなくなります。

そうすれば働かなくても
生活費を賄うことができます。

今回はFIREをしたいなと思いましたので
シミュレーターで検証してみましょう。

プログラムはGoogle Colabなどで
利用できるので試してみて下さい。
from matplotlib import pyplot as plt
import numpy as np
import ipywidgets as widgets
from IPython.display import display

out_text = '最終金額 : {0:,} ,年間生活費 : {1:,} \n年間利息 : {2:,} , FIRE倍率 : {3}\n'

# FIREシミュレーター
def show_widgets():
    button = widgets.Button(description='シミュレーション')
    s0 = widgets.IntSlider(value=200000  , min=10000  , max=1000000, step=10000 , description='月の生活費:')
    s1 = widgets.IntSlider(value=2000000, min=0 , max=10000000, step=100000 , description='初期金額:')
    s2 = widgets.IntSlider(value=200000  , min=0 , max=1000000  , step=10000   , description='月の積立金:')
    s3 = widgets.FloatSlider(value=4.0, min=0.1, step=0.1, max=20.0, description='利率:')
    s4 = widgets.IntSlider(value=10  , min=1 , max=50  , step=1 , description='年数:')
    output0 = widgets.Output(layour={'border': '1px solid black'})
    output1 = widgets.Output()
    ax = plt.gca()
    
    def on_click(b: widgets.Button) -> None:
        ax.clear()
        cost = s0.value
        initial = s1.value
        reserve = s2.value
        rate = s3.value
        year = s4.value
        rand_x = []
        money = initial
        for i in range(1,year):
            money += reserve * 12
            money = int(money*(1+rate/100))
            rand_x.append(money)
        f_rate = money / (cost * 12)
        result = '{0:.4}倍'.format(f_rate)
        Interest = int(money*(rate/100))
        ax.plot(list(range(1,len(rand_x)+1)),rand_x)
        ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: "{:,}".format(int(x))))
        with output0:
            output0.clear_output(wait=True)
            out = out_text.format(money, cost * 12 , Interest , result)
            if f_rate>25:
              out += 'FIRE達成しました!!'
            print(out)
        with output1:
            output1.clear_output(wait=True)
            display(ax.figure)
            
    button.on_click(on_click)
    box1 = widgets.Box([s0,s1])
    box2 = widgets.Box([s2,s3])
    box3 = widgets.Box([s4,button])
    display(box1 , box2 , box3 , output0,output1)
    plt.close()
    button.click()
    
show_widgets()

実行すると


スクリーンショット 2022-02-19 16.17.10

こんな感じでスライダーが出てきます。

月の生活費
初期金額
月の積立金
利率
年数
これを変えてシミュレーションボタンを押すと
結果が下にでます。

最終金額
年間生活費 
年間利息
FIRE倍率
これが出ます。

FIRE倍率25倍を越すと達成の表示が出ます。

これを使う際は
生活費や積み立て金を決めて何年経つと
資産がどれくらいになるか・とか

XX年でFIREするには積み立てや利率を
どうすれば良いか・・みたいなのを
シミュレーションできますんで
色々変えて遊んでみて下さい。

手取りで40万くらいないと
月々20万円を運用に回すの厳しいなー
こりゃあしんどい!!!!

というわけで
FIRE結構大変そうですね!
是非遊んでみて下さい

それでは。

今回は株価のデータを用いて
株の売買シミュレーションを
行ってみたいと思います。

解説動画はこちら




自動売買で儲けられるルールを探したい!!!
ということで、株価データを見て
適当なルールを作って売買シミュレーションを
行ってみたいと思います。


こちらのデータを参考にしています。

5分足のデータを用いることとしました。

データのリンク先


今回やりたい事としては

高い時に売って安い時に買う
or
安い時に買って高い時に売る

株の鉄則をそのまま考えてみたいと思います。

まずは日経平均の株価の
データを見てみることとします。

ここから先のコード群は
Google Colabで試すことのできる
コードになっているので
試したい方はコピペしてどうぞ。



直接pandasのデータフレームに取り込むか
データをダウンロードしてから
データフレームに取り込むコードです。

まずはライブラリをインポート
import pandas as pd
import numpy as np
import warnings
warnings.simplefilter('ignore')
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline


データの読み込みは次のコードです
データが「日付、時間、始値、高値、安値、終値」
となっていてヘッダーが無いので英名を付けておきます。
# 直接読み込む場合
df = pd.read_csv('https://atmtech.net/main/n225/Y2020-all.csv',header=None,names=['day','time','open','high','row','close'])

# 手元にダウンロードしてから行う場合
df = pd.read_csv('Y2020-all.csv',header=None,names=['day','time','open','high','row','close'])

# プレビュー
df.head()
スクリーンショット 2021-09-11 16.55.46

次にこのデータには不整合があるようなので
前処理することにします。
df['time'] = df['time'].str.replace('0.395833333','9:30:00')

def time_sep(d):
    l = d['time'].split(':')
    return '{0:02}:{1:02}:{2:02}'.format(int(l[0]),int(l[1]),int(l[2]))

def day_sep(d):
    l = d['day'].split('/')
    return '{0}-{1:02}-{2:02}'.format(int(l[0]),int(l[1]),int(l[2]))

df['time'] = df.apply(time_sep,axis=1)
df['day'] = df.apply(day_sep,axis=1)
df.head()
スクリーンショット 2021-09-11 16.55.50



これで不整合を取り除いて、データも綺麗にしました。

次に、安い時 or 高い時を探りたいので
朝9時の価格を基準にして終値を取得します。
df_9 = df[df['time']=='09:00:00'][['day','close']]
df_9 = df_9.reset_index(drop=True)
df_9.columns = ['day','stand']
df_9.head()


日単位で終値を取りました。
集計してみましょう。
# 集計してみる
pd.pivot_table(merge_df,index='day', columns='time', values='rate')
スクリーンショット 2021-09-11 16.56.12


これだと数字だけなので
よく分からないですよね。

数値だけだと分かりづらいので
グラフ化しましょう。

箱髭図にしてみます。
# 箱髭図を作ってみる
fig = plt.figure(figsize=(16,10))
ax = fig.add_subplot(1, 1, 1)
sns.boxplot(x='time', y='rate', data=merge_df, ax=ax)
plt.xticks(rotation=90)
plt.show()
download-2

次に時間帯ごとに集計をしてみることとします。
平均、中央値を出してみます。
# 時間帯ごとに集計する
calc_df = merge_df[['time','rate']][merge_df['time']!='00:00:00'].groupby(['time']).agg([np.mean,np.median,np.std])
calc_df.columns = ['mean','median','std']
calc_df.head()
折れ線グラフにしてみましょう。
# 折れ線グラフにしてみる
plt.figure(figsize=(16,10))
plt.plot([1 for i in range(len(calc_df['mean']))])
plt.plot(calc_df['mean'],color='red',label="mean")
plt.plot(calc_df['median'],color='green',label="median")
plt.xticks(rotation=90)
plt.legend(fontsize=20)
plt.show()
download-4


これで見ると
平均的に上がっている or 下がっている
中央値でも上がっている or 下がっている

と言うのが分かります。

朝9時に売って
両方ともが下がっている時間帯に買い戻せば
その差額分儲けられるのではと
仮説を立てました。



時間帯ごとに9時の終値から
上がったのか下がったのかの回数も
見てみることにしましょう。
# 価格差でフラグ値を付ける
merge_df['flg'] = merge_df['rate'] >=1

calc2_df = pd.crosstab(merge_df['time'], merge_df['flg'])
calc2_df.columns = ['down','up']
calc2_df = calc2_df.reset_index()
calc2_df = calc2_df[calc2_df['time']!='09:00:00']
calc2_df = calc2_df[calc2_df['time']!='00:00:00']

merge_df.head()

# 100%棒グラフを作る
plt.figure(figsize=(16,6))
plt.plot([121 for i in range(len(calc_df['mean']))])
height1 = np.array(calc2_df['down'])
height2 = np.array(calc2_df['up'])
p1 = plt.bar(calc2_df['time'], height1, color="red")
p2 = plt.bar(calc2_df['time'], height2, bottom=height1, color="green")
plt.xticks(rotation=90)
plt.legend((p2[0], p1[0]), ("UP","DOWN"))
plt.show()
download-5


これで見ると9:20は終値が9:00時点よりも
下がっている回数が多いことが分かります。

平均値や中央値も下がっていましたね。
ということで9時に売って9:20に買い戻すというのを
シミュレーションしてみたいと思います。

売買ルール
資金は1000万円
朝9:00に売って、9:20に買い戻す
売れる株分だけ売って、その分を買い戻す

これをコードにしてみると
money = 10000000
sel_close , buy_close = 0,0
sel_value , buy_value = 0,0
result , quantity = 0,0
result_df = pd.DataFrame()
for row in merge_df[(merge_df['time']=='09:00:00')|(merge_df['time']=='09:20:00')].iterrows():
    data = row[1]
    date = data[0]
    times = data[1]
    close = data[5]
    if times=='09:00:00':
        sel_close = close
        quantity = money//sel_close
        sel_value = quantity * sel_close
    elif times=='09:20:00':
        buy_close = close
        buy_value = quantity * buy_close
        result = (sel_value - buy_value)
        money = money + (sel_value - buy_value)
        tmp_df = pd.DataFrame([[date,sel_close,buy_close,sel_value,buy_value,result,money]],
                              columns=['date','sel_close','buy_close','sel_value','buy_value','result','money'])
        result_df = pd.concat([result_df,tmp_df])

result_df = result_df.reset_index(drop=True)
result_df.head()
スクリーンショット 2021-09-11 16.56.27



さてシミュレーションの結果は
どうなったでしょうか?
売買シミュレーションの結果は??????
plt.figure(figsize=(16,3))
plt.plot(result_df['money'],color='red')
plt.show()
download


そもそもの株価の動きは
どうだったのでしょうか???
plot_df = df[df['time']=='09:00:00']
plot_df = plot_df.reset_index(drop=True)
plt.figure(figsize=(16,3))
plt.plot(plot_df['close'],color='blue')
plt.show()
download-1


結果としては2020年は年初からコロナの影響で
ガツっと下がり、その後は上がり続けています。

売って買い戻すというルールなので
値が下がった方が良くなるのですが
値が上がってもいる状況でも
そこまで酷い成績にならない結果となりました。

この結果は2020年だけなので
なんとも言えないものですが

こう言うルールを検証していけば
自動売買で適応出来るルールが
発見できるかもしれません。

そうしたらシステム化して
ほっぽって置こうかなと
思っています。

今回は株価のデータを使った
売買シミュレーションついて
お送りしました。

それでは。

最近投資を始める方が増えているらしいと
ニュースになっていました。

Pythonという言語は
そういった時系列データを分析するのに
非常に相性の良い言語です。

是非投資を始めるなら
プログラミングの方も
合わせて学んでいきましょう。


解説動画はこちら



今回の株価データは
こちらに掲載されていたものを
利用しています。

株式投資メモ
1321 日経225連動型上場投資信託
https://kabuoji3.com/stock/1321/

スプレッドーシートなどで
CSVファイルにする事で
株価データを読み込みする事ができます。

まずは手作業でCSVファイルを
作ってみてください。

CSVファイルが出来たら
データを読み込んでいきます。

今回は「Google Colabolatry」
というGoogle社が提供している
プログラミングツールのサービスを利用します。

https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja

Googleアカウントを持っている方は
すぐに始める事ができます。

使い方が分からない方は
こちらをみてください。
GoogleColabの使い方

まず最初にデータをアップロードします。
画面左のフォルダマークをクリックして
右クリックからアップロードで
ファイルを配置します。
スクリーンショット 2020-09-21 17.11.06


それができたらデータの読み込みを行います。

「Pandas」ライブラリは
表構造のデータを取り扱うためのライブラリです。

ファイルからデータフレームという形で
データを読み込みします。

これと数値計算用の「numpy」ライブラリ
これを使っていきます。
import pandas as pd
import numpy as np

df = pd.read_csv('stock_1321.csv',index_col=0)
df = df.sort_index(ascending=True)

df
スクリーンショット 2020-09-21 17.14.05


今回のデータはこんな感じになっています。
date 日付
open 始値
high 高値
low 安値
close 終値
volume 出来高
adjust 調整済終値

株価の動きをみていきましょう。
描画用のライブラリである
Plotlyを使って時系列データを描画します。

まずはライブラリの読み込みです。
import plotly
import plotly.graph_objs as go
# Google Colab. やJupyter Lab.でプロットするためには,以下を実行する.
import plotly.io as pio
pio.renderers.default = "colab"
plotly.__version__
4.4.1

続いて表示用データの作成です。
# 表示用のデータを生成しておく
xlabels = np.arange(len(df))
interval = 20 
vals = [df.index[i*interval] for i in range(len(df)//interval)]
labels=[df.index[i*interval] for i in range(len(df)//interval)]
date_format = 'date:{}
open:{}
high:{}
low:{}
close:{}' hovertext = [date_format.format(df.index[i],df.loc[df.index[i],'open'],df.loc[df.index[i],'high'],df.loc[df.index[i],'low'],df.loc[df.index[i],'close']) for i in range(len(df))]

表示するデータを作成できたら
描画を行います。
# ローソク足のプロット
fig = go.Figure(
    # データの指定
    data=go.Candlestick(
        x = xlabels,
        open=df['open'],
        high=df['high'],
        low=df['low'],
        close=df['close'],
        hovertext=hovertext ,
        hoverinfo="text"
        ),
    # グラフのレイアウト設定
    layout = go.Layout(
        xaxis = dict(
            tickvals=vals,
            ticktext=labels,
            tickangle=-45
        ),
    )
)
fig.show()
スクリーンショット 2020-09-21 17.17.41



データフレームには
各種データが揃っているので
ここから色々な数値計算をする事で
各指標を作成していく事ができます。

ただし、この指標の作成は
初心者には少し厳しいと思います。

cufflinksライブラリを用いると
指標の作成を簡単に行う事ができるので
これを使っていきましょう。

import cufflinks as cf

Pandasデータフレームから
一度cf用のデータに変換して描画します。
import cufflinks as cf

qf = cf.QuantFig(df, name='日経 225')

plotly.offline.iplot(
    qf.iplot(asFigure=True)
)
スクリーンショット 2020-09-21 17.20.03


ここに色々な指標を追加していきます。

移動平均(add_sma)
ボリンジャーバンド(add_bollinger_bands)
出来高(add_volume)
RSI(add_rsi)
MACD(add_macd)
qf = cf.QuantFig(df[150:], name='日経 225')

qf.add_sma([10,20],width=2,color=['green','lightgreen'],legendgroup=True)
qf.add_bollinger_bands(periods=20,boll_std=2,colors=['magenta','grey'],fill=True)
qf.add_volume()
#qf.add_rsi(periods=20,color='java')
#qf.add_macd()

plotly.offline.iplot(
    qf.iplot(asFigure=True)
)
スクリーンショット 2020-09-21 17.20.49




指標の他にラインを引く事ができます。

サポートライン
qf.add_support(日付)
抵抗ライン
qf.add_resistance(日付)

日付の指定方法が
少し特殊なので気をつけてください。

日(2桁) 月(英語表記の3桁) 年(2桁)

qf = cf.QuantFig(df[250:], name='日経 225')

# サポートライン
qf.add_support('31Jul20')

# 抵抗ライン
qf.add_resistance('25Aug20')

plotly.offline.iplot(
    qf.iplot(asFigure=True)
)
スクリーンショット 2020-09-21 17.24.20




最後にトレンドをみてみましょう。

トレンドラインを引いてみます。
qf.add_trendline(開始日, 終了日)
qf = cf.QuantFig(df[250:], name='日経 225')

qf.add_trendline('03Aug20', '26Aug20')

plotly.offline.iplot(
    qf.iplot(asFigure=True)
)
スクリーンショット 2020-09-21 17.25.14


データを差し替えれば
様々な個別銘柄の株価を描画して
トレンドなどを把握していく事ができます。

プログラミングが上達したら
各証券会社が提供しているツールよりも
細かな設定を施すことなどが出来る様になります。

自己投資として
プログラミングは
身につけておいて損はありません。

Python言語の文法などが分からない方のために
5時間ほどで学べる動画講座を用意しています。
5時間で学ぶプログラミング基礎 (python編)

是非この機会にプログラミングの方も
始めてみましょう。

分からない所があれば
気兼ねなくYoutubeにコメントをどうぞ

今回はここまでです
それでは。


 

このページのトップヘ