この記事の想定読者
- pythonを使って、自力で為替データを取得することができる
- 為替レートにトレンドラインを引きたい、けど引けない
- トレードで儲けたお金を、慈善事業に寄付したりして誰かを助けたい!(MUST)(`・ω・´)
全部に該当する人だけ読んでね(^ワ^*)←
完成図!
pointは、一定期間内のレートだけを対象にトレンドラインを引いているところ。
期間の範囲指定も可能。
参考にさせていただいた記事
PythonでFXのトレンドラインを引いてみる
http://www.algo-fx-blog.com/python-fx-trend-line/
単回帰分析を繰り返して徐々に高値(安値)を絞り込んでいく手法を参考にさせていただきました。
ソースコード
1 モジュールインポート
# 一般的なモジュール
import pandas as pd
import numpy as np
import datetime
import seaborn
import matplotlib.pyplot as plt
from scipy.stats import linregress
# 投資分析にのみ必要なモジュール
import mplfinance.original_flavor as mpf
from oandapyV20 import API
import oandapyV20.endpoints.instruments as oandapy
# For suppressing warning
# https://github.com/numpy/numpy/issues/11448
np.seterr(invalid='ignore')
2 データ取得
2(データ取得)は自前で処理を書いて下さい。
一応サンプルとして私の処理も載せます。(が、汚いので参考にならないと思います)
class FXBase():
candles = None
def __init__(self):
cols = ['col1', 'col2']
FXBase.candles = pd.DataFrame(index=[], columns=cols)
class RequestRate(FXBase):
def __init__(self, days=3):
# request用パラメータ設定
num_candles = int(days * 24 * 12) # 24h * 60min / 5分刻み
minutes = num_candles * 5 # 60 = 12 * 5 分
now = datetime.datetime.now() - datetime.timedelta(hours=9) # 標準時に合わせる
start_time = now - datetime.timedelta(minutes=minutes)
start_time = start_time.strftime("%Y-%m-%dT%H:%M:00.000000Z")
params = {
"alignmentTimezone": "Japan",
"from": start_time,
"count": num_candles,
"granularity": "M5" # per 5 Minute
}
access_token = "アクセストークンを書いてね"
api = API(access_token = access_token, environment="practice")
request = oandapy.InstrumentsCandles(
instrument = "USD_JPY",
params = params
)
# request処理
api.request(request)
# request結果データの整形 / クラス外から呼出し可能にする
candle = pd.DataFrame.from_dict([ row['mid'] for row in request.response['candles'] ])
# astype による cast を複数列へ https://qiita.com/driller/items/af1369a5c0fc2ec61af3
candle = candle.astype({'c': 'float64', 'l': 'float64', 'h': 'float64', 'o': 'float64'})
candle.columns = ['close', 'high', 'low', 'open']
candle['time'] = [ row['time'] for row in request.response['candles'] ]
# 冗長な日時データを短縮整形 https://note.nkmk.me/python-pandas-datetime-timestamp/
candle['time'] = pd.to_datetime(candle['time']).astype(str)
FXBase.candles = candle
# 表示可能な最大行数を設定
pd.set_option("display.max_rows", num_candles)
3 取得したデータの確認
if __name__ == '__main__':
requester = RequestRate(days=2)
FXBase.candles['time_id']= FXBase.candles.index + 1
FXBase.candles.head()
こんな感じのデータさえあれば、データの取得方法は問いません。
4 メイン:トレンドライン生成
## チャートを単回帰分析し、得られる単回帰直線よりも上(下)の値だけで再度単回帰分析...
## これを繰り返し、高値(安値)を2~3点に絞り込む
# 高値の始点/支点を取得
def get_highpoint(start, end):
chart = FXBase.candles[start:end+1]
while len(chart)>3:
regression = linregress(
x = chart['time_id'],
y = chart['high'],
)
chart = chart.loc[chart['high'] > regression[0] * chart['time_id'] + regression[1]]
return chart
# 安値の始点/支点を取得
def get_lowpoint(start, end):
chart = FXBase.candles[start:end+1]
while len(chart)>3:
regression = linregress(
x = chart['time_id'],
y = chart['low'],
)
chart = chart.loc[chart['low'] < regression[0] * chart['time_id'] + regression[1]]
return chart
def g_trendlines(span=20, min_interval=3):
trendlines = []
# 高値の下降トレンドラインを生成
for i in FXBase.candles.index[::span/2]:
highpoint = get_highpoint(i, i + span)
# ポイントが2箇所未満だとエラーになるので回避する
if len(highpoint) < 2:
continue
# 始点と支点が近過ぎたらトレンドラインとして引かない
if abs(highpoint.index[0] - highpoint.index[1]) < min_interval:
continue
regression = linregress(
x = highpoint['time_id'],
y = highpoint['high'],
)
print(regression[0] < 0.0, 'reg_high: ', regression[0], ', ', regression[1], )
# 下降してるときだけ
if regression[0] < 0.0:
trendlines.append(regression[0] * FXBase.candles['time_id'][i:i+span*2] + regression[1])
# 安値の上昇トレンドラインを生成
for i in FXBase.candles.index[::span/2]:
lowpoint = get_lowpoint(i, i + span)
# ポイントが2箇所未満だとエラーになるので回避する
if len(lowpoint) < 2:
continue
# 始点と支点が近過ぎたらトレンドラインとして引かない
if abs(lowpoint.index[0] - lowpoint.index[1]) < min_interval:
continue
regression = linregress(
x = lowpoint['time_id'],
y = lowpoint['low'],
)
print(regression[0] > 0.0, 'reg_low: ', regression[0], ', ', regression[1], )
# 上昇してるときだけ
if regression[0] > 0.0:
trendlines.append(regression[0] * FXBase.candles['time_id'][i:i+span*2] + regression[1])
return trendlines
あとは、これをチャートと一緒に描画するだけです
デフォルトでは、ローソク足20本中の高値(安値)を元にトレンドラインを引きます。
g_trendlines関数の引数 span を変更すれば、何本分のローソク足を元にして高値(安値)を見つけるかを変更できます。
5 描画
コードが汚すぎて見せたくねぇ...
ここまでの内容を理解できる人は自分で描画できると思いますが、一応サンプルとして載せます。
(余計な処理が混じってるのでwarningが出ます。おゆるしを。。。)
figure, (axis1, axis2) = plt.subplots(2, 1, figsize=(20,10), dpi=200, gridspec_kw = {'height_ratios':[3, 1]})
# ローソク足
mpf.candlestick2_ohlc(
axis1,
opens = FXBase.candles.open.values,
highs = FXBase.candles.high.values,
lows = FXBase.candles.low.values,
closes = FXBase.candles.close.values,
width=0.6, colorup='#77d879', colordown='#db3f3f'
)
# トレンドラインたちを引く
for i, line in enumerate(g_trendlines()):
axis1.plot(line, label=i)
# X軸の見た目を整える
xticks_number = 12 # 12本刻みに目盛りを書く
xticks_index = range(0, len(FXBase.candles), xticks_number)
xticks_display = [FXBase.candles.time.values[i][11:16] for i in xticks_index] # 時間を切り出すため、先頭12文字目から取る
# axis1を装飾 ( plt.sca(axis): set current axis )
plt.sca(axis1)
plt.xticks( xticks_index, xticks_display )
plt.legend()
plt.show()
# axis2は他の勉強の名残…消したら動かなくなりそうで、怖くて消せてない(´;ω;`)
引くラインの数を結構絞り込んでいるので、見やすくなっています。
ifでかけている制限を取れば、もっとたくさんのトレンドラインが引けるはず。