BitMexのBotをVisual Studio+Pythonで開発する その1 - 環境構築 -
BitMexのBotをVisual Studio+Pythonで開発する その2 - ccxtのAPI -
前回はBitMex等の取引所と通信する為のライブラリ、ccxtの基本的な使い方を勉強しました。
取引はできるようになりましたが、どのタイミングでポジションを取っていつロスカット/利確するか?
という判断をする為にはやはりテクニカル指標が必要です。
ccxtはテクニカル指標を計算するライブラリではない為、テクニカル指標を計算するライブラリを別途インストールします。
PythonだとTA-Libというライブラリが有名ですがVisual Studioだとpipで簡単にインストール出来なかった為、今回はpytiという別のテクニカル指標計算ライブラリを使い、メジャーな指標であるEMA・MACD・RSI・RCIについて算出してみます。
また、計算した結果をグラフ化して取引所のチャートと比較し、正しいかを判断したいと思います。
グラフ化にはPythonでよく使われるmatplotlibを使います。
なお、検索すればたくさん出てくるので今回は各指標の詳しい意味は説明しません。
目次
pyti(指標計算ライブラリ)のインストール
環境構築でccxtをインストールしたようにVisual StudioのPython環境に移動し、検索バーにpytiと入力してインストールします。
matplotlib(グラフ描画ライブラリ)のインストール
pytiと同様に検索バーにmatplotibと入力し、インストールします。
BitMexから過去の取引データを取得
指標を計算するにはまず元となる過去の取引データを取得します。
ccxtのfetch_ohlcvを使います。
取得したデータは配列で以下の順に並んでいます。
- タイムスタンプ(UTC)
- Open price (始値)
- Highest price (高値)
- Lowest price (低値)
- Closing price (終値)
- Volume (出来高)
基本的に指標には終値を使用する為、終値だけを抽出しておきます。
from datetime import datetime import calendar import ccxt import matplotlib.pyplot as plt #グラフ用 #bitmex用のccxt変数を用意 bitmex = ccxt.bitmex({ "apiKey": "APIキー", "secret": "秘密鍵", }) #テストネットで動作 bitmex.urls["api"] = bitmex.urls["test"] #現在時刻(UTC)取得 now = datetime.utcnow() #UTC→Unix時間に変換 unixTime = calendar.timegm(now.utctimetuple()) #xx分前の時間(ms)を算出 minute = 150 since = (unixTime - 60 * minute) * 1000 #過去の取引情報(1分足)を取得 limit = 500 ohlcvList = bitmex.fetch_ohlcv("BTC/USD", "1m", since, limit) #終値(close)情報だけを抽出 closeList = list() for ohlcv in ohlcvList: closeList.append(ohlcv[4])
EMA(指数平滑移動平均線)の計算
EMAは過去の一定期間における終値の移動平均線で、単純な移動平均では無く直近のデータに重みを持たせて算出したものです。
EMAは1本だけで無く、2本もしくは3本を同時に算出して他の指標と併用するのが一般的なようです。
先程取得した終値のデータとpyti.exponential_moving_averageを利用します。
関数はファイルの上部で別名をつけておくと分かりやすく、使いやすくなります。
from pyti.exponential_moving_average import exponential_moving_average as ema #emaという名前でexponential_moving_average関数を使用
前述の終値(closeList)を算出した前提でコードを書くと以下のようになります。
関数emaの引数はema(終値, 期間)となっているので、終値の配列closeListを左側に渡し、期間は9と26でそれぞれ算出します。
#ema計算 ema9 = ema(closeList, 9) ema26 = ema(closeList, 26) #グラフにデータをプロット plt.plot(ema9) plt.plot(ema26) #グラフ描画 plt.show()
取引所のグラフと比較すると形が近似している事が分かると思います。
また、期間分のデータが集まるまでは算出されないので、対象期間分の最初のデータはグラフに表示されていません。
※テストネットだと実際の取引所のグラフとは異なるので注意してください。
RSIの算出
RSIは一定期間での買われすぎ/売られすぎを判断する指標です。
これもMACDなど他の指標と合わせて使う事が多いです。
70~80%を超えると買われすぎ、20~30%を下回ると売られすぎと判断し、逆張りをするような使い方です。
RSIは過去データと、pyti.relative_strength_indexを使います。
先程同様、別名をつけておくと使いやすくなります。
from pyti.relative_strength_index import relative_strength_index as rsi
引数はEMAは同様、終値と期間を渡してやります。
#RSI算出 rsi = rsi(closeList, 14) plt.plot(rsi) plt.show()
グラフはこのような感じです。
MACDの算出
MACDは移動平均線を基準とした2本のラインの乖離を表示する指標です。
ここでは9(期間A)、12(期間B)、26(期間C)の3つの期間のEMAを使ってMACDとシグナルの2ラインを算出します。
- MACD = EMA(期間B) - EMA(期間C)
- シグナル = MACDのEMA(期間A)
- MACDヒストグラム = MACD - シグナル
MACDの算出にはpyti.moving_average_convergence_divergenceを使います。
from pyti.moving_average_convergence_divergence import moving_average_convergence_divergence as macd
関数macdの引数には終値、期間B、期間Cを渡します。
また、シグナルとヒストグラムは上記の式で算出します。
ヒストグラムは棒グラフで表示するのが一般的なのでplt.barで棒グラフとしてプロットしています。
この際、x軸の値として項目数を入れる必要がある為、ヒストグラムの産出時にxの値を同時に格納しています。
グラフ描画をしない場合はこの処理は不要です。
macd = macd(closeList, 12, 26) #MACD macdSignal = ema(macd, 9) #シグナル macdHistogram = list() #ヒストグラム格納用 x = list() #グラフのx軸用の値(項目数)の格納用 #MACDヒストグラム算出 for i, macdOrigin in enumerate(macd): #enumerateで項目数をiに入れる macdHistogram.append(macdOrigin - macdSignal[i]) x.append(i) plt.plot(macd) plt.plot(macdSignal) plt.bar(x, macdHistogram) #ヒストグラムを棒グラフでプロット plt.show()
RCIの算出
RCIは時間と価格にそれぞれ順位を付け、どれだけの相関関係があるかを計算し、相場のトレンドと過熱感を判断します。
RCIの範囲は-100~100%です。
RCIはpytiに計算する関数が無かった為、以下の計算式を実装して自力で計算する事にします。
RCI[%] = ( 1 - 6 * d / (n * (n ^ 2 -1))) * 100
- d:時間の順位と価格の差を2乗し、合計した数値
- n:期間
これをコードに落とすと以下のようになります。
なお、順位が同じ場合は平均順位を取ります。
2位と3位が同じ値なら2.5(2 + 3 / 2)、5~7位が同じ値なら6(5 + 6 + 7 / 3)となります。
※Trading Viewに用意されているRCIは平均順位ではなく1~3位が同じ値なら全部1のような順位付けをしているようで、RCIの範囲は-100%を超えています。以下のコードでコメントアウトされているpriceRankの式を使えばTrading Viewと同じグラフになります。
import numpy import pandas #RCI取得関数 #close:終値の配列 #period:期間 def getRci(close, period): result = [None] * (period - 1) #初期値(計算不可の部分をNoneとする) for end in range(period - 1, len(close)): start = end - period + 1 target = close[start:end + 1] #対象範囲 targetSorted = sorted(target, reverse = True) #対象範囲を高い順にソート #dの計算 i = 0 d = 0 while i < period: timeRank = period - i sameRankNum = targetSorted.count(target[i]) #同じ値の個数 priceRank = targetSorted.index(target[i]) + 1 + 0.5 * (sameRankNum - 1) #同じ値がある場合は平均順位 #priceRank = targetSorted.index(target[i]) + 1 #平均順位にしない場合 d = d + (timeRank - priceRank) ** 2 i += 1 rci = (1 - 6 * d / (period * (period ** 2 - 1))) * 100 result.append(rci) return result
これを別ファイルで保存して自分のプログラムで使う場合はimportし、以下のようになります。
RCIは3本使うのが一般的で、Trading Viewでは区間がそれぞれ9、36、52なのでその値で算出します。
import rci #終値の取得は省略 #RCIの算出 RCI9 = rci.getRci(closeList, 9) RCI36 = rci.getRci(closeList, 36) RCI52 = rci.getRci(closeList, 52) plt.plot(RCI9) plt.plot(RCI36) plt.plot(RCI52) plt.show()
平均順位の場合のグラフです。-100~+100%の範囲で推移しています。
同じ値で平均順位にしなかった場合はこのようになります。botに組み込む時は注意しましょう。
まとめ
テクニカル指標は他にも色々ありますが、pytiライブラリを使えば比較的簡単に算出出来ます。
ただ、MACDのシグナルやRCIのように自力で計算が必要な指標もあるので、そこは色々検索して頑張るしかありません。
また、グラフとしては算出できましたが、botに組み込む時はこれらの数値の何を見てポジションを取るかの判断をアルゴリズムとして実装する必要があります。
人間は目で見てだいたいここらへんのポイントというのを判断できますが、bot内部ではグラフもただの数値の羅列でしかありません。
この部分は非常にコツがいりそうです。
次回はテクニカル指標をどのように使ってポジションを取るか考えていきたいと思います。