今回は仮想通貨市場において有名なテクニカル指標であるRSIは有効なのかどうかを検証していきたいと思います。使用する言語はPythonです。
・使用するデータ
2013年~2018年までの約1900日分のビットコインの日足価格です。高頻度データで分析したかったのですが、たくさん高頻度データを取得する方法が分からなかったのでパス。(知っている方がいましたらコメントとかで教えてください笑)
トレードのルール
今回はRSIを使ったトレードリターンのバックテストを行っていきます。トレードに使用するRSIの計算期間は14日間で加重平均ではなく単純平均です。
ルールはRSIの一般的な使い方である「RSIが30以下なら売られ過ぎということで買い、70以上なら売られ過ぎということで売り」という戦略です。
ビットコインの価格を取得する
ビットコインやイーサリアムなどのアルトコインの価格を取得方法は以下の記事で解説しています。
まずは必要なライブラリをインストール、これを入れておかないと下のコードは動きません。
##ライブラリーのインストール## import pandas as pd import time import matplotlib.pyplot as plt import datetime import requests import json %matplotlib inline
そしてビットコインの価格を取得していきます。
##ビットコインの価格を取得し、変化率を計算する## def get_bitcoinprice(): ##ビットコインの価格を取得する## url=('https://api.coingecko.com/api/v3/coins/')+str('bitcoin')+('/market_chart?vs_currency=jpy&days=max') r=requests.get(url) r=json.loads(r.text) bitcoin=r['prices'] ##二重配列のデータをデータフレームに整形する## data=[] date=[] for i in bitcoin: data.append(i[1]) date.append(i[0]) bitcoin=pd.DataFrame({"date":date,"price":data}) price=bitcoin['price'] ##そこに変化率を計算して加える## a=price.pct_change() bitcoin=pd.DataFrame({"date":date,"price":data,"change":a}) return bitcoin
実行すると以下のようなデータが返ってくるはずです。
RSIを計算する
次はRSIを計算します。RSIなどのテクニカル指標の計算方法は以下の記事で説明しています。
##RSIを計算する## def rsi(data): data=data.diff() ##値上がり幅、値下がり幅をシリーズへ切り分け up, down = data.copy(), data.copy() up[up < 0] = 0 down[down > 0] = 0 ##値上がり幅/値下がり幅の単純移動平均(14)を処理## up_sma_14 = up.rolling(window=14, center=False).mean() down_sma_14 = down.abs().rolling(window=14, center=False).mean() ##値上がり幅/値下がり幅の単純移動平均(14)を処理## up_sma_14 = up.rolling(window=14, center=False).mean() down_sma_14 = down.abs().rolling(window=14, center=False).mean() # RSIの計算 RS = up_sma_14 / down_sma_14 RSI = 100.0 - (100.0 / (1.0 + RS)) return RSI
実行すると以下のような結果になります。
バックテストをする
さてデータの取得と指標の計算が終わったところで次は実際にトレードのバックテストを行っていきます。こういう系でバックテストを行う簡単な方法は指標に合わせて買いなら1、売りなら-1と返す判断結果と変化率を掛け合わせ、それを累積変化率の換えて処理するという方法です。
このための必要な処理がpandasだと関数1つでできるのでトレード系の分析をするのでもpandasは欠かせないライブラリですね。
##RSIのシグナルの作成## RSIsignal=[] for i in b: if i<=30: RSIsignal.append(1) elif i>=70: RSIsignal.append(-1) else : RSIsignal.append(0) ##トレードの利益を計算する def trade_return(change,signal): a=len(change) returns=((change[1:]*signal[:a-1])+1).cumprod() return returns*10000
まずはシグナルの説明ですが、今回のトレード戦略は「RSIが30以下なら売られ過ぎということで買い、70以上なら売られ過ぎということで売り」ということなので、先ほど計算したRSIの数値が30以下なら買い(1)、70以下なら売り(-1)という数値を返すシグナルのリストを作ります。
for文の中はRSIが30以下なら1、そうでなくRSIが70以上であれば-1、どちらにも当てはまらない数値またはNAN/欠損値の場合は0を返すという処理です。
次のトレード損益を計算する関数はシグナル(1、-1、0でできたpandas.Series)と変化率のデータ(データ型はpandas.Series)を掛け合わせます。そのまま掛け合わせると意味がないので、signalとchangeをずらします。RSIのシグナルが出たら買いまたは売りを実行し、次の日に売り、買いを実行するというトレードシュミレーションになります。そしてその結果をcumprod()というpandasの関数で累積変化率にして計算しています。
最後に10000をかけているのは10000円スタートの場合最終的に何円になったのか視覚的に分かりやすくしているだけです。
バックテストの結果
bitcoin=get_bitcoinprice() RSI=rsi(btcoin['price']) ##RSIのシグナル RSIsignal=[] for i in RSI: if i<=30: RSIsignal.append(1) elif i>=70: RSIsignal.append(-1) else : RSIsignal.append(0) trade=trade_return(bitcoin["change"],RSIsignal) ##結果をプロットする## trade.plot()
すると結果は以下のようになりました。
・・・・・・・なんも言えねぇ。。。
ちなみに何円になったのかというと、元手10000円からスタートして1929日後には、>>trade[1929]でみれば分かりますが、 61.281030円になっています笑
結論
仮想通貨取引で従来のRSIの使い方をすると多分やばいくらい負けると思うので、使わないか使い方を変えた方がいいという結論になりました。
コメント