orz

趣味のブログです

ボリンジャーバンドで売り買いした場合のシミュレーション (ファーストリテイリングの場合)


前書き

ボリンジャーバンドのロジックで売り買いのやり取りした場合でシミュレーションしてみました。

ボリンジャーバンドのロジックですが、ある特定の期間の移動平均線標準偏差±σ, ±2σを加える。

  • +2σのバンドラインに来たら株を買い、-2σのラインに来たら株を売る (順張りのロジック)
  • -2σのバンドラインに来たら株を買い、+2σのラインに来たら株を売る (逆張りのロジック)

このふたつでシミュレーションするとどうなるかを検証してみました。

準備

10年分の株価を
kabuoji3.com
から引っ張ってきました。

次のプログラムを使って、10年分のcsvを自動取得してみました。

import chromedriver_binary 
from selenium import webdriver
import pyautogui as pg 
import time
#取り出す株コードと年を変数として、取得する
def csv_get(stock_number,year):
    DRIVER_PATH = ("C:\/chromedriver")
    # DRIVER_PATH = '/Users/Kenta/Desktop/Selenium/chromedriver' # ローカル
    # DRIVER_PATH = '/app/.chromedriver/bin/chromedriver'        # heroku

    # ブラウザの起動、銘柄コードと年を受け取って開く(できた)
    driver = webdriver.Chrome(executable_path=DRIVER_PATH)
    driver.get("https://kabuoji3.com/stock/{}/{}/".format(stock_number,year))
    driver.maximize_window()

    #ダウンロードページに移動
    selector = '#base_box > div > div:nth-child(3) > form > button'
    element = driver.find_element_by_css_selector(selector)
    element.click()
    
    selector = '#base_box > div > div.mt_10.tc > form > button'
    element = driver.find_element_by_css_selector(selector)
    element.click()
    
    pg.presskey("Enter")
    print (stock_number,"の",year,"年のcsvデータをダウンロードしました")
for x in range(1997,2021):
    csv_get(9983,x)


このようにして、取得しました。銘柄コードと年数範囲を変えればほかの銘柄にも対応しています。

実際にやってみる

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import openpyxl as px
import copy
from statistics import mean
col_names = ["始値","高値","安値","終値","出来高" ,"終値調整値"] #カラムの名前指定
i = 1 #結合の時に使うダミー変数
#空のデータフレーム作成
df2 = pd.DataFrame(index=[])
#2021年から1997年のデータを全部結合させる, CSVで読み込んだ
for x in range(2021,1997,-1):
    filename ="./9983_"+str(x)+".csv"
    df = pd.read_csv(filename, header = None,names=col_names, encoding ='cp932',skiprows=2)
    if i == 1:
        df2 = copy.copy(df) #copyでデータ転写
    else:
        df2 =pd.concat([df2,df]) #読み込んだdfを結合させる
    i+=1
#プロット用のデータを抜き出す
owarine=[]
day = []
for x in range(len(df2.終値)):
    try:
        owarine.append(int(df2.終値[x])) 
    except:
        continue
owarine.reverse()
day = list(range(0,len(df2.終値),1))

#5日移動平均線
sma5 = []
day_sma5 = day[4:]
for x in range(len(owarine)):
    if (x-4) >= 0:
        sma5 = np.append(sma5,mean(owarine[(x-4):x]))
    else:
        continue

#25日移動平均線と標準偏差の算出
sma25 = []
day_sma25 = day[24:]
std=[]
for x in range(len(owarine)):
    if (x-24) >= 0:
        sma25 = np.append(sma25,mean(owarine[(x-24):x]))
        std = np.append(std,np.std(owarine[(x-24):x]))
    else:
        continue

#125日移動平均線と標準偏差の算出
sma125 = []
day_sma125 = day[124:]
for x in range(len(owarine)):
    if (x-124) >= 0:
        sma125 = np.append(sma125,mean(owarine[(x-124):x]))
    else:
        continue

#ロジックで売り買いしてみる
syuueki =[]#収益を入れる空のリスト
syuueki_g = [] #逆張りした時のリスト
#エクセルを開く。あらかじめセルにキャプションつける
wb = px.Workbook() 
sheet = wb.active
sheet["A1"].value ="ボリンジャーバンドで順張りのやり取りした場合のシミュレーション結果"
sheet["A2"].value ="収益"
sheet["B2"].value ="イベントログ"


sheet["F1"].value ="ボリンジャーバンドで逆張りのやり取りした場合のシミュレーション結果"
sheet["F2"].value ="収益"
sheet["G2"].value ="イベントログ"
count = 1 #イベント変数
count_g =1 #逆張り用のイベント変数
for x in day:
    if x-24>0:
        if owarine[x] > (2*std[x-24]+sma25[x-24]):
            syuueki.append(-1*owarine[x])
            sheet["A"+str(count+2)].value =-1*owarine[x]
            sheet["B"+str(count+2)].value ="株を買いました"
            count += 1
        elif owarine[x] <(-2*std[x-24]+sma25[x-24]):
            syuueki.append(owarine[x])
            sheet["A"+str(count+2)].value =owarine[x]
            sheet["B"+str(count+2)].value ="株を売りました"
            count += 1
        else:
             continue
for x in day:
    if x-24>0:
        if owarine[x] < (-2*std[x-24]+sma25[x-24]):
            syuueki_g.append(-1*owarine[x])
            sheet["F"+str(count_g+2)].value =-1*owarine[x]
            sheet["G"+str(count_g+2)].value ="株を買いました"
            count_g += 1
        elif owarine[x] >(2*std[x-24]+sma25[x-24]):
            syuueki_g.append(owarine[x])
            sheet["F"+str(count_g+2)].value =owarine[x]
            sheet["G"+str(count_g+2)].value ="株を売りました"
            count_g += 1
        else:
             continue
sheet["D3"].value = "順張りの収益の結果"
sheet["D4"].value = sum(syuueki)
sheet["I3"].value = "逆張りの収益の結果"
sheet["I4"].value = sum(syuueki_g)

print ("ファーストリテイリングの銘柄でボリンジャーバンドのロジックでシミュレーションしてみました\n")
print ("順張りロジックなら",count,"回取引しました\n逆張りロジックなら",count_g,"回取引しました")
print ("順張りロジックの合計の収益は",100*sum(syuueki),"円でした\n逆張りロジックの収益は",100*sum(syuueki_g),"円でした")
wb.save("テスト結果.xlsx")

以上のコードを組んで計算してみました。

やってみた結果

出力ですが、以下の画像のようになりました。
順張りの場合と逆張りの場合で正負が逆転していますのが気になりますが、機械的にやりとりして1億の利益・損失が出ているようですね。
f:id:orshibuya0926:20210121220515p:plain

次の課題

  • RSIなどほかのテクニカル手法を組み合わせたシミュレーション
  • ビットコインの値段をリアルタイムで取得して、LINEで通知するプログラム (LINE APIでできるとか)