見出し画像

2本の指数移動平均線のクロスだけでビットコインFXで勝てるか?(日足)2017/07/01~2020/06/30

ビットコインFX取引のバックテストをしたいと思います。

指数移動平均線(EMA)のクロス戦術とは、

短期の指数移動平均線が長期の指数移動平均線を下から上に抜いたら買い
短期の指数移動平均線が長期の指数移動平均線を上から下に抜いたら売り

というシンプルなものです。
これはトレンド方向に仕掛ける順張り戦略のひとつです。

この戦術で、BTC取引を行ったら利益がでるのか検証したいと思います。

取引ルールは、

「短期EMA>長期EMAとなったら、売りポジションを決済し、1BTC買う」
「短期EMA<長期EMAとなったら、買いポジションを決済し、1BTC売る」

つまり、手仕舞いしたら反対方向のポジションを持つ、ドテン方式です。
損切、利食い目標が無いため、トレンドが続く限りポジションを持ち続けます。パラメータはEMAの期間である短期と長期の2つの値のみです。

今回の検証では、ろうそく足は日足を使います。

期間は2017年7月~2020年6月の3年間とします。

価格データはbitflyerのBTC/JPYペアを使います。
取引手数料は1回の取引で0.1%かかるとしました。

<結果:短期3長期8>

総損益:3419643円
最大ドローダウン:507599円
勝率:0.354
取引回数:110

短期と長期のパラメタを色々試した結果、
短期3日間と長期8日間の指数移動平均が大きな利益になりました。

資産推移(オレンジ実線)も大体右肩上がり?になっています。

画像1

オレンジの線が含み益、青の線が確定利益で、緑の点線が1BTCの価格です。

順張り(トレンドフォロー)戦略なので、トレンドが長く続いたときに大きく利益を伸ばします。

3年間で約342万円のプラス。
ビットコインの最高値は220万円程度なので、
それだけの資金をはじめから用意してたとしても、
3年間で資金が2.5倍程度に増える計算になります。
シンプルな戦略にしては上出来ではないでしょうか?

<その他のパラメタでの結果>

画像2

ほとんどの検証でPF(プロフィットファクター)が2以上になりました。

PFとは、勝ちトレードの利益の合計を負けトレードの損失の合計で割ったもので、1より大きいとトータルでの損益はプラスになります。PFが2というのはかなり大きい値です。そのかわりに、勝率は3割~4割と低いです。一般的に順張り戦略はPFが高いが勝率が低くなります。


<検証コード>

バックテストはpythonを使いました。実行するにはろうそく足データのCSVファイルが必要です。データは↓のサイトから取ってこれます。


ろうそく足データの読み込み、バックテストを行って、損益グラフの出力まで行います。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import csv
# csv読み込み
# 時刻,始値,高値,安値,終値,出来高
#...
csv_file = open("../pastdata./btcjpy1d20170701-20200630.csv", "r", encoding="ms932", errors="", newline="" )
reader = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
# listに変換
data = [ e for e in reader ]
# 文字列を数値に変換
for row in data:
   row[1] = int(row[1])
   row[2] = int(row[2])
   row[3] = int(row[3])
   row[4] = int(row[4])
   row[5] = float(row[5])
candles = pd.DataFrame(data)

# パラメタ
span_s = int(input('Please input parameter : span_s> '))
span_l = int(input('Please input parameter : span_l> '))

# 指数移動平均を計算
ema_s = candles[4].ewm(span=span_s).mean()
ema_l = candles[4].ewm(span=span_l).mean()

qty = 0
price = 0
cost_fee = 0.1*0.01
profit = 0
unrealized_profits = list()
realized_profits = list()
timestamps = list()
closelists = list()
win = list()
lose = list()
num_win = 0
num_loss = 0
for i in range(span_l,len(candles)):
   signal_buy = ema_s[i]>ema_l[i] and ema_s[i-1]<ema_l[i-1]
   signal_sell = ema_s[i]<ema_l[i] and ema_s[i-1]>ema_l[i-1]
   close = candles[4][i]
   timestamp = candles[0][i]
   if qty !=0 and (signal_buy or signal_sell):
       val = qty*(close-price) - np.abs(qty)*cost_fee*(close+price)
       if val>0:
           num_win +=1
           win.append(val)
       else:
           num_loss+=1
           lose.append(val)
       profit += qty*(close-price) - np.abs(qty)*cost_fee*close
       qty = 0
   if qty == 0:
       if signal_buy:
           qty = 1
           price = close
           profit += -price*qty*cost_fee
       if signal_sell:
           qty = -1
           price = close
           profit += price*qty*cost_fee
   unrealized_profits.append(profit+qty*(close-price))
   realized_profits.append(profit)
   timestamps.append(timestamp)
   closelists.append(close)
date_label = list()
price = list()

# 結果をグラフに
for i in range(0,len(timestamps)):
   # 日付と時刻に分割
   date, time  = timestamps[i].split()
   # ラベル作成
   date_label.append(date)
x = np.arange(len(date_label))
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x,realized_profits,label='realized_profit')
ax.plot(x,unrealized_profits,label='unrealized_profit')
ax.plot(x,closelists,linestyle='dotted',label='btc/jpy')
ax.set_ylabel("yen")
ax.set_xlabel("date")
ax.legend()
ax.grid(True)
# ラベルを飛び飛びにする、90度回転
plt.xticks(x[::90], date_label[::90], rotation=90)
# グラフが枠に納まるようにする
plt.tight_layout()
# 損益グラフ保存
plt.savefig('test_2ema_'+str(span_s)+'_'+str(span_l)+'.png')
# 損益グラフ表示
plt.show()

drawdown = 0
drawdown_max = 0
assets_max=0
for i in range(0,len(unrealized_profits)):
   assets_max = max(assets_max,unrealized_profits[i])
   drawdown = assets_max - unrealized_profits[i]
   drawdown_max = max(drawdown_max,drawdown)
print('(',span_s,',',span_l,')')
print('tradenum',num_win+num_loss)
print('profit',profit)
print('drawdown_max',drawdown_max)
print('winrate',num_win/(num_win+num_loss))
print('PF',-sum(win)/sum(lose))


この記事が気に入ったらサポートをしてみませんか?