LoginSignup
28
34

More than 1 year has passed since last update.

[python3]FXチャートにトレンドラインを引く

Last updated at Posted at 2018-12-16

この記事の想定読者

  • pythonを使って、自力で為替データを取得することができる
  • 為替レートにトレンドラインを引きたい、けど引けない
  • トレードで儲けたお金を、慈善事業に寄付したりして誰かを助けたい!(MUST)(`・ω・´)

全部に該当する人だけ読んでね(^ワ^*)←

完成図!

2018-12-16_16h48_58.png

pointは、一定期間内のレートだけを対象にトレンドラインを引いているところ。
期間の範囲指定も可能。

参考にさせていただいた記事

PythonでFXのトレンドラインを引いてみる

http://www.algo-fx-blog.com/python-fx-trend-line/

単回帰分析を繰り返して徐々に高値(安値)を絞り込んでいく手法を参考にさせていただきました。

ソースコード

1 モジュールインポート

jupyter_notebook
# 一般的なモジュール
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(データ取得)は自前で処理を書いて下さい。
一応サンプルとして私の処理も載せます。(が、汚いので参考にならないと思います)

jupyter_notebook
class FXBase():
    candles = None
    def __init__(self):
        cols = ['col1', 'col2']
        FXBase.candles = pd.DataFrame(index=[], columns=cols)
jupyter_notebook
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 取得したデータの確認

jupyter_notebook
if __name__ == '__main__':
    requester = RequestRate(days=2)
    FXBase.candles['time_id']= FXBase.candles.index + 1

FXBase.candles.head()

2018-12-16_17h21_16.png

こんな感じのデータさえあれば、データの取得方法は問いません。

4 メイン:トレンドライン生成

jupyter_notebook

## チャートを単回帰分析し、得られる単回帰直線よりも上(下)の値だけで再度単回帰分析...
## これを繰り返し、高値(安値)を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が出ます。おゆるしを。。。)

jupyter_notebook
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は他の勉強の名残…消したら動かなくなりそうで、怖くて消せてない(´;ω;`)

2018-12-16_16h48_58.png
こんな感じになるはずだょ☆彡(再掲)

引くラインの数を結構絞り込んでいるので、見やすくなっています。
ifでかけている制限を取れば、もっとたくさんのトレンドラインが引けるはず。

28
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
34