見出し画像

[バックテスト]CCI順張り戦略を使って、ビットコインFXで稼げるのか、過去データで検証(4時間足、2018~2019)

CCIを使ったBTCのFXトレードで勝てるのか、
過去データを使ったバックテストで検証したいと思います。

<CCI(商品チャンネル指数)>

CCIとは、Commodity Chanel Indexの略で、日本語では商品チャンネル指数と訳されます。

ストキャスティクスやRSIのように、売られすぎ、買われすぎを判断する、オシレーター系のテクニカル指標のひとつです。

株式市場などでは、CCIが-100を下回ったら売られ過ぎ、+100を上回ったら買われすぎ、というように判断して逆張りに使われます。

ただし仮想通貨市場では、-100を下回ったら下降トレンド、
+100を上回ったら上昇トレンド、というように順張りで使われます。

計算式は、

基準値 = (高値+安値+終値)/3
CCI=(基準値-基準値の移動平均値) / (0.015×基準値の平均絶対偏差)

で表されます。


<CCI(40)順張り戦略>

ろうそく足は4h足とします。

取引ルールは、

仕掛け(買い) :「40期間CCIが+100ラインを上に抜けたら、次の足の始値で、1BTCを買う。」
手仕舞い(売り):「40期間CCIが+100ラインを下に抜けたら、次の足の始値で売り決済する。」

仕掛け(売り) :「40期間CCIが-100ラインを下に抜けたら、次の足の始値で、1BTCを売る。」
手仕舞い(買い):「40期間CCIが-100ラインを上に抜けたら、となったら、次の足の始値で買い決済する。」

通常では20期間が使われますが、ここでは40期間を使います。

1回の売買で取引量の0.1%の取引コストがかかるとして、シミュレーションします。
テスト期間は2018年1月~2019年12月の2年間とします。
binanceのろうそく足(4h)データを使います。


<結果>

CCI順張り戦略に従ってBTCをFX取引した際の、損益グラフがこちら↓

画像1

青:損益(簿価)、オレンジ:損益(時価)、緑:BTC/USDT価格
そこそこ右肩上がりに資産が増えています。CCI順張り戦略は機能しているといえそうです。

総損益: 7970ドル
最大ドローダウン: 3870ドル
勝率:0.380
PF: 1.719
取引回数: 142


<検証コード>

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

使ったコード↓

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import csv
# csv読み込み、ファイル名を指定
csv_file = open("../pastdata_binance/binance_btc_usdt_4h_2018-2019.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] = float(row[1])
   row[2] = float(row[2])
   row[3] = float(row[3])
   row[4] = float(row[4])
   row[5] = float(row[5])
candles = pd.DataFrame(data)

# CCIの期間
span = 40

# 中値
tp = (candles[2]+candles[3]+candles[4])/3
# 平均中値
mtp = tp.rolling(window=span).mean()
# 平均絶対偏差
mad = (tp-mtp).abs().rolling(window=span).mean()
# CCI(コモディティ・チャネル・インデックス)
cci = (tp-mtp)/(0.015*mad)

qty = 0
price = 0
cost_fee = 0.1*0.01
asset = 0
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(20,len(candles)-1):
   close = candles[4][i]
   signal_buy_entry = 100<cci[i] and cci[i-1]<100
   signal_sell_entry =  cci[i]<-100 and -100<cci[i-1]
   signal_buy_exit = cci[i]>-100
   signal_sell_exit = cci[i]<100
   timestamp = candles[0][i]
   openprice = candles[1][i+1]
   if qty>0 and signal_sell_exit or qty<0 and signal_buy_exit:
       val = qty*(openprice-price) - np.abs(qty)*cost_fee*(openprice+price)
       if val>0:
           num_win +=1
           win.append(val)
       else:
           num_loss+=1
           lose.append(val)
       profit += qty*(openprice-price) - np.abs(qty)*cost_fee*close
       qty = 0
   if qty == 0:
       if signal_buy_entry:
           qty = 1
           price = openprice
           profit += -price*qty*cost_fee
       if signal_sell_entry:
           qty = -1
           price = openprice
           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)):
   try:
       # 日付と時刻に分割
       date, time  = timestamps[i].split()
       # ラベル作成
   except Exception as e:
       print(e)
       date = timestamps[i]
   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/usdt')
ax.set_ylabel("USDT")
ax.set_xlabel("date")
ax.legend()
ax.grid(True)
# ラベルを飛び飛びにする、90度回転
plt.xticks(x[::1000], date_label[::1000], rotation=90)
# グラフが枠に納まるようにする
plt.tight_layout()
# 損益グラフ保存
plt.savefig('test_cci_1h.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('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))
この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
ありがとうございます!
1
ビットコインFXで勝つための、戦略メモを公開しています。
コメントを投稿するには、 ログイン または 会員登録 をする必要があります。