技術メモ

役に立てる技術的な何か、時々自分用の覚書。幅広く色々なことに興味があります。

pythonで為替データを取ってきて移動平均、ボリンジャーバンド、ゴールデンクロス、デッドクロスを可視化

pythonで為替データを分析したり可視化してみたいと考えた。
今回は、リアルタイムでドル円相場を取ってきてローソク足をプロットし、その上に移動平均ボラティリティゴールデンクロスデッドクロスを可視化してみるというところまでやってみる。

データを取ってくる

まずはデータを取ってこないといけない。
以前はCSVファイルを取ってこれるサイトを紹介したけれど、やっぱりリアルタイムでもデータを取ってきたい。(為替の分足CSVデータが無料でダウンロードできるサイト - 技術メモ
そこで今回はOANDAのAPIを使うことにした。
調べた限りOANDAだけが無料でリアルタイムのデータを取れるAPIを出してくれているらしいからだ。
OANDAの登録からキーの取得までは色々なサイトで確認してほしい。

pythonでは、oandapyV20というラッパーを使えばうまく取ってこられるらしい。
The oandapyV20 REST-V20 API wrapper documentation — OANDA REST V20 API Wrapper 0.6.3 documentation

ひとまずサンプルコードを動かしてみる。
コードは下の参考サイトにも載せた ここ を参考にした。

必要なライブラリがなければインストールしておく

pip install pandas
pip install matplotlib
pip install seaborn
pip install oandapyV20

今回はデータの取得と可視化を別のプログラムで書いたのでいったん”candle.csv”としてCSV形式で保存することにした。
account_tokenには自分で取得したアクセストークンを入れてほしい。

import datetime
import pandas
from oandapyV20 import API
import oandapyV20.endpoints.instruments as oandapy

start        = datetime.datetime(year=2018,month=5,day=1)
minutes      = 150 # 150分取得
start        = start.strftime("%Y-%m-%dT%H:%M:00.000000Z")
access_token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
api          = API(access_token = access_token, environment="practice")
request      = oandapy.InstrumentsCandles(instrument = "USD_JPY",
               params = { "alignmentTimezone": "Japan", "from": start, "count": minutes, "granularity": "M1" })
api.request(request)

filename = "candle.csv"
candle = pandas.DataFrame.from_dict([ row['mid'] for row in request.response['candles'] ])
candle['time'] = [ row['time'] for row in request.response['candles'] ]
candle.to_csv(filename)

土日に動かしていたので日付は固定してしまっているが、スタート時刻を変えればリアルタイムでも動かせる。
(*土日は為替相場が閉まってるからデータが取れない!!!)

移動平均線、ボリバンを可視化する

import pandas
import seaborn
import matplotlib.pyplot as plt
from matplotlib.finance import candlestick2_ohlc as plt_candle
seaborn.set_style("whitegrid")

# csvを読み込む
candle = pandas.read_csv('candle.csv')

# 移動平均とボラティリティを求める
window_size  = 5 #5分移動平均を求める
avg_move     = pandas.Series.rolling(candle.c, window = window_size).mean().dropna().reset_index(drop = True)
sigma        = pandas.Series.rolling(candle.c, window = window_size).std(ddof = 0).dropna().reset_index(drop = True)
sigma_plus1  = avg_move + sigma
sigma_plus2  = avg_move + sigma * 2
sigma_plus3  = avg_move + sigma * 3
sigma_minus1 = avg_move - sigma
sigma_minus2 = avg_move - sigma * 2
sigma_minus3 = avg_move - sigma * 3

candle = candle[window_size:].reset_index(drop = True)

# X軸の見た目を整える
# 時間だけを切り出すために先頭からの12文字目から取るようにしている
xticks_number = 15 #15分刻みに目盛りを書く
xticks_index = range(0,len(candle), xticks_number)
xticks_date = [candle.time.values[i][11:16] for i in xticks_index]

figure, ax = plt.subplots()
plt_candle( ax,
            opens = candle.o.values,
            highs = candle.h.values,
            lows = candle.l.values,
            closes = candle.c.values,
            width=0.6,
            colorup='#DC143C',
            colordown='#4169E1')
plt.plot(avg_move, color='#006400')
plt.plot(sigma_plus1, color='#3CB371')
plt.plot(sigma_plus2, color='#9ACD32')
plt.plot(sigma_plus3, color='#ADFF2F')
plt.plot(sigma_minus1, color='#3CB371')
plt.plot(sigma_minus2, color='#9ACD32')
plt.plot(sigma_minus3, color='#ADFF2F')
plt.xticks(xticks_index, xticks_date, rotation=80)
plt.show()

f:id:swdrsker:20180518012800p:plain

5分の移動平均を求めている。
移動平均線ボリンジャーバンドアルゴリズム的に簡単に言うと
それぞれ「過去N本分のローソク足終値の平均、標準偏差」のこと。
標準偏差は1σ、2σ、3σまで求めるのが普通だ。


ここがよくわからないかもしれない

candle = candle[window_size:].reset_index(drop = True)

これは、移動平均と実際のローソク足を合わせることをしている。
移動平均線は過去5分の平均を求めている事を意味するので、最初の4分は意味がないことになる。
5分の移動平均線に対しては4分ずらさないとローソク足が一致しないので、そもそもデータから取り除いてしまえということだ。

意外と手間取ったのが見た目に関してだった。
良い感じで15分毎くらいにX軸を出したかったがあんまり簡単にできる方法が見つからなかった。
xticksという関数を見つけて無理やり良い感じになるようにしたけれどもっといい方法があるかもしれない。
あと、seabornは素晴らしいのでとりあえず使っとけって感じはある。

ゴールデンクロスデッドクロスを可視化

import pandas as pd
import seaborn
import matplotlib.pyplot as plt
from matplotlib.finance import candlestick2_ohlc as plt_candle
seaborn.set_style("whitegrid")

# csvを読み込む
candle = pd.read_csv('candle.csv')

#移動平均を求める
small_window = 5 # 5分平均線を求める
big_window   = 20 # 20分平均線求める
sma5         = pd.Series.rolling(candle.c, window = small_window).mean()
sma20        = pd.Series.rolling(candle.c, window = big_window).mean()

candle = candle[ big_window: ].reset_index(drop=True)
sma5 = sma5[ big_window: ].reset_index(drop=True)
sma20 = sma20[ big_window: ].reset_index(drop=True)

#ゴールデンクロス、デッドクロスを見つける
cross  = sma5 > sma20
golden = (cross != cross.shift(1)) & (cross == True)
dead   = (cross != cross.shift(1)) & (cross == False)

#ゴールデンクロス、デッドクロスの位置をリスト化する
index_g = [i-1 for i, x in enumerate(golden) if x == True]
index_d = [i-1 for i, x in enumerate(dead) if x == True]

# X軸の見た目を整える
# 時間だけを切り出すために先頭からの12文字目から取るようにしている
xticks_number = 15 #15分刻みに目盛りを書く
xticks_index = range(0,len(candle), xticks_number)
xticks_date = [candle.time.values[i][11:16] for i in xticks_index]

figure, ax = plt.subplots()
plt_candle( ax,
            opens = candle.o.values,
            highs = candle.h.values,
            lows = candle.l.values,
            closes = candle.c.values,
            width=0.6,
            colorup='#DC143C',
            colordown='#4169E1')
plt.plot(sma5, color='greenyellow', label='sma5')
plt.plot(sma20, color='darkgreen', label='sma20')
plt.scatter(index_g, sma20[index_g], color='red', s=500, label="golden cross")
plt.scatter(index_d, sma20[index_d], color='blue', s=500, label="dead cross")
plt.xticks(xticks_index, xticks_date, rotation=80)
plt.legend()
plt.show()

f:id:swdrsker:20180518013058p:plain

ゴールデンクロスデッドクロスは5分と20分の移動平均に関するクロスを計算するようにした。
ここでは20分移動平均線を5分移動平均線が下から交差すればゴールデンクロス、上から交差すればデッドクロス、ということにしている。

注意しないといけないことは、こちらは20分の移動平均を使っていることだ。
つまりローソク足に関しては最初の19分、5分の移動平均線に関しては最初の14分が不要ということになる。
それがこの部分にあたる。

candle = candle[ big_window: ].reset_index(drop=True)
sma5 = sma5[ big_window: ].reset_index(drop=True)
sma20 = sma20[ big_window: ].reset_index(drop=True)

どうやらゴールデンクロスデッドクロスについて調べてみると

長期移動平均線が上向きで短期移動平均が長期移動平均を下から上へクロスする場合、買い。(ゴールデンクロス
長期移動平均線が下向きで短期移動平均が長期移動平均を上から下へクロスする場合、売り。(デッドクロス
引用: http://fx.kakaku.com/fx/articleview/?no=21

と書かれてるところもあり、これに従うならもうすこし手を加える必要があるかもしれない。


OANDAのAPIは結構便利そうだ。
課金(口座に25万円以上入金)さえすればトレードに関するリクエストなんかも送れるらしく、リアルタイムで分析しながらシステムトレードなんかもできるかもしれない。
完全自動売買のプログラムによる不労所得生活もきっと夢じゃない。