top of page
  • 執筆者の写真bookloveru2

pythonで株価分析⑫【コピペで3秒。MACDでバックテスト】

更新日:2021年11月1日


今回は、大人気シリーズ「pythonで株価分析してみた」の第12弾です❕




表題の通り、

『コピペで3秒。』で自作のMACDバックテストできます('ω')ノ

『有名な指標だけど、MACDって儲かるの❓』という疑問に答えます。

ポチるだけで、バックテストの結果が表示されます!(^^)!




今回も、コピペで行ける様、しっかりとpythonコードの解説をしていきますので、グーグルコラボのご準備をお願い致します。


では、早速行ってみましょう!(^^)!


 

目次

コピペ用pythonコードと使い方

一括コード

 


❶コピペ用pythonコードと使い方

まずは必要なライブラリを準備!(^^)!

!pip install mplfinance
import mplfinance as mpf
import datetime
import fix_yahoo_finance as yf
import matplotlib.pyplot as plt
import requests
import argparse
import numpy as np
import seaborn as sns

次は分析開始日と銘柄、任意の移動平均線を設定!(^^)!

次の5項目を入力して下さい。

  1. start:開始日

  2. stock:銘柄(ここではテスラ)

  3. MA1:任意の移動平均線(ここでは5日)

  4. MA2:任意の移動平均線(ここでは25日)

  5. MA3:任意の移動平均線(ここでは60日)

start = "2021-1-1" #@param {type:"string"}
stock = "TSLA" #@param {type:"string"}
MA1 = 5 #@param {type:"number"}
MA2 =  25#@param {type:"number"}
MA3 =  60#@param {type:"number"}

df = yf.download(stock, start=start, end=datetime.date.today())
mpf.plot(df,type='candle',mav=(MA1,MA2,MA3),volume=True,show_nontrading=True)

ここまでの結果です👇

じゃん(*‘ω‘ *)❕

自作のチャートが出来上がりました!(^^)!

今回は今年の初めから現在までのテスラモーターズの株価推移をプロットしました!!





続いて、お待ちかねのMACDバックテストです👇


#simple moving average
def macd(signals):
 
 
    signals['ma1']=signals['Close'].rolling(window=ma1,min_periods=1,center=False).mean()
    signals['ma2']=signals['Close'].rolling(window=ma2,min_periods=1,center=False).mean()
 
 return signals

#signal generation
#when the short moving average is larger than long moving average, we long and hold
#when the short moving average is smaller than long moving average, we clear positions
#the logic behind this is that the momentum has more impact on short moving average
#we can subtract short moving average from long moving average
#the difference between is sometimes positive, it sometimes becomes negative
#thats why it is named as moving average converge/diverge oscillator
def signal_generation(df,method):
 
    signals=method(df)
    signals['positions']=0

 #positions becomes and stays one once the short moving average is above long moving average
    signals['positions'][ma1:]=np.where(signals['ma1'][ma1:]>=signals['ma2'][ma1:],1,0)

 #as positions only imply the holding
 #we take the difference to generate real trade signal
    signals['signals']=signals['positions'].diff()

 #oscillator is the difference between two moving average
 #when it is positive, we long, vice versa
    signals['oscillator']=signals['ma1']-signals['ma2']

 return signals

#plotting the backtesting result
def plot(new, ticker):
 
 #the first plot is the actual close price with long/short positions
    fig=plt.figure()
    ax=fig.add_subplot(111)
 
    new['Close'].plot(label=ticker)
    ax.plot(new.loc[new['signals']==1].index,new['Close'][new['signals']==1],label='LONG',lw=0,marker='^',c='g')
    ax.plot(new.loc[new['signals']==-1].index,new['Close'][new['signals']==-1],label='SHORT',lw=0,marker='v',c='r')

    plt.legend(loc='best')
    plt.grid(True)
    plt.title('Positions')
 
    plt.show()
 
 #the second plot is long/short moving average with oscillator
 #note that i use bar chart for oscillator
    fig=plt.figure()
    cx=fig.add_subplot(211)

    new['oscillator'].plot(kind='bar',color='r')

    plt.legend(loc='best')
    plt.grid(True)
    plt.xticks([])
    plt.xlabel('')
    plt.title('MACD Oscillator')

    bx=fig.add_subplot(212)

    new['ma1'].plot(label='ma1')
    new['ma2'].plot(label='ma2',linestyle=':')
 
    plt.legend(loc='best')
    plt.grid(True)
    plt.show()

def main():
 
 #input the long moving average and short moving average period
 #for the classic MACD, it is 12 and 26
 #once a upon a time you got six trading days in a week
 #so it is two week moving average versus one month moving average
 #for now, the ideal choice would be 10 and 21
 
 global ma1,ma2,stdate,eddate,ticker,slicer

 #macd is easy and effective
 #there is just one issue
 #entry signal is always late
 #watch out for downward EMA spirals!
    ma1=int(input('ma1:'))
    ma2=int(input('ma2:'))
    stdate=input('start date in format yyyy-mm-dd:')
    eddate=input('end date in format yyyy-mm-dd:')
    ticker=input('ticker:')

 #slicing the downloaded dataset
 #if the dataset is too large, backtesting plot would look messy
 #you get too many markers cluster together
    slicer=int(input('slicing:'))

 #downloading data
    df=yf.download(ticker,start=stdate,end=eddate)
 
    new=signal_generation(df,macd)
    new=new[slicer:]
    plot(new, ticker)

if __name__ == '__main__'


かなり長いコードでやんした(*‘ω‘ *)

結果です👇

このコードは実行後に開始日や銘柄の入力を要望してきます。

次の6項目を入力して下さい。

  1. ma1:任意の移動平均線(ここでは5日)

  2. ma2:任意の移動平均線(ここでは25日)

  3. start date:開始日

  4. end date:終了日

  5. ticker:銘柄

  6. slicing:データの分割数(15くらいで良いと思います)



見事にバックテストの結果が出ました(*ノωノ)


今回の例で言うと、【2月の中旬にショート。4月上旬にロング(決済)で見事に利確❕】。その後5月上旬に再度ショートにインしています(・ω・)ノ


MACD上ではテスラは、まだ売りだ!

と言っていますね。







如何でしたでしょうか?(`・ω・´)ゞ

なかなか良いぜ❕と思ってくれた方は、下記のアドレスまでビットコインの少額寄付をお願いします。($・・)/~~~


Bitcoin address

1BnvzhckxyjTLUzCaH3v5S4E6QSzPvxWkA


❷一括コード


!pip install mplfinance
import mplfinance as mpf
import datetime
import fix_yahoo_finance as yf
import matplotlib.pyplot as plt
import requests
import argparse
import numpy as np
import seaborn as sns

start = "2021-1-1" #@param {type:"string"}
stock = "TSLA" #@param {type:"string"}
MA1 = 5 #@param {type:"number"}
MA2 =  25#@param {type:"number"}
MA3 =  60#@param {type:"number"}

df = yf.download(stock, start=start, end=datetime.date.today())
mpf.plot(df,type='candle',mav=(MA1,MA2,MA3),volume=True,show_nontrading=True)

#simple moving average
def macd(signals):
 
 
    signals['ma1']=signals['Close'].rolling(window=ma1,min_periods=1,center=False).mean()
    signals['ma2']=signals['Close'].rolling(window=ma2,min_periods=1,center=False).mean()
 
 return signals

#signal generation
#when the short moving average is larger than long moving average, we long and hold
#when the short moving average is smaller than long moving average, we clear positions
#the logic behind this is that the momentum has more impact on short moving average
#we can subtract short moving average from long moving average
#the difference between is sometimes positive, it sometimes becomes negative
#thats why it is named as moving average converge/diverge oscillator
def signal_generation(df,method):
 
    signals=method(df)
    signals['positions']=0

 #positions becomes and stays one once the short moving average is above long moving average
    signals['positions'][ma1:]=np.where(signals['ma1'][ma1:]>=signals['ma2'][ma1:],1,0)

 #as positions only imply the holding
 #we take the difference to generate real trade signal
    signals['signals']=signals['positions'].diff()

 #oscillator is the difference between two moving average
 #when it is positive, we long, vice versa
    signals['oscillator']=signals['ma1']-signals['ma2']

 return signals

#plotting the backtesting result
def plot(new, ticker):
 
 #the first plot is the actual close price with long/short positions
    fig=plt.figure()
    ax=fig.add_subplot(111)
 
    new['Close'].plot(label=ticker)
    ax.plot(new.loc[new['signals']==1].index,new['Close'][new['signals']==1],label='LONG',lw=0,marker='^',c='g')
    ax.plot(new.loc[new['signals']==-1].index,new['Close'][new['signals']==-1],label='SHORT',lw=0,marker='v',c='r')

    plt.legend(loc='best')
    plt.grid(True)
    plt.title('Positions')
 
    plt.show()
 
 #the second plot is long/short moving average with oscillator
 #note that i use bar chart for oscillator
    fig=plt.figure()
    cx=fig.add_subplot(211)

    new['oscillator'].plot(kind='bar',color='r')

    plt.legend(loc='best')
    plt.grid(True)
    plt.xticks([])
    plt.xlabel('')
    plt.title('MACD Oscillator')

    bx=fig.add_subplot(212)

    new['ma1'].plot(label='ma1')
    new['ma2'].plot(label='ma2',linestyle=':')
 
    plt.legend(loc='best')
    plt.grid(True)
    plt.show()

def main():
 
 #input the long moving average and short moving average period
 #for the classic MACD, it is 12 and 26
 #once a upon a time you got six trading days in a week
 #so it is two week moving average versus one month moving average
 #for now, the ideal choice would be 10 and 21
 
 global ma1,ma2,stdate,eddate,ticker,slicer

 #macd is easy and effective
 #there is just one issue
 #entry signal is always late
 #watch out for downward EMA spirals!
    ma1=int(input('ma1:'))
    ma2=int(input('ma2:'))
    stdate=input('start date in format yyyy-mm-dd:')
    eddate=input('end date in format yyyy-mm-dd:')
    ticker=input('ticker:')

 #slicing the downloaded dataset
 #if the dataset is too large, backtesting plot would look messy
 #you get too many markers cluster together
    slicer=int(input('slicing:'))

 #downloading data
    df=yf.download(ticker,start=stdate,end=eddate)
 
    new=signal_generation(df,macd)
    new=new[slicer:]
    plot(new, ticker)

if __name__ == '__main__':
    main()




では。ばいちゃ(・ω・)ノ


pythonでプログラミングがしたい!! 
pythonを学びたい!という方には、
オンラインプログラミング教室『Aidemy アイデミー』がお勧めです。
ご自身でプログラム環境を用意する必要は無く、サイトへアクセスするだけです。  創業者は東京大学工学部卒の石川聡彦さん。
著書に『人工知能プログラミングのための数学がわかる本』(KADOKAWA/2018年)など。  
無料で、お試しもできますので安心です。
お時間ある方は下記リンクを覗いてみてはいかがでしょうか(*'ω'*)




閲覧数:1,029回0件のコメント
bottom of page