Bot

仮想通貨botの開発を本格的に始めてみる#21(2023/9/28)

前回の内容に引き続き、今回も仮想通貨botの開発状況をまとめていきます。

今回はこちらの記事を参考に「バックテストでbotの勝率・平均リターン・総利益を算出する」ことがテーマです。

今回使用するコードは大変長いため、つまずいた部分や深掘りした部分のみ取り上げています。

バックテストとは

バックテストとは「過去のデータを使って検証を行うこと」です。

今回はCryptowatchの過去データを使って、三兵の売買ロジックの検証をします。

コードの一部を書き換えて出力される結果を確認するという流れになります。

出力された結果がこちら。↓全然勝てていません。

BUYとSELL入れ替えてバックテストを行なった結果がこちら。↓こちらも全然勝てていません。

どちらのテストでも「トレード回数」「勝率」「平均リターン」「総利益」を算出しています。

さらに、それらの結果を合わせて「総利益」「手数料合計」を算出しています。

この結果をプラスに持っていくために、コードの一部を変更しながら勝てるパラメータを探していくことになります。

たとえば、上記の結果を受けて「手仕舞いの条件に問題がある」という仮定を立ててみます。

その場合の対策は「4本目の足は手仕舞いの条件判定から除外する」ことが挙げられます。

そこで、コードの先頭部分にあるclose_conditionを0から1に変更して、バックテストを実行してみます。

その結果がこちら。↓損失は減りましたが、それでもまだ損益はマイナスです。

この戦略では、根本的に問題がありそうです。

バックテストの注意点

バックテストを行うときに気をつけることは「カーブフィッティング(過剰最適化)」です。

これは、バックテストで良い結果を出すためにパラメータの設定を不用意にいじることで生じる問題です。

現実的にはあり得ない数値で条件設定をしてバックテストの出力結果を良いものにしてしまっても意味がありません。

過去のデータを使って検証するときは「理由に基づいたテスト」を行う必要があります。

「なんだかよく分からないけれどこの数値を設定したら良い結果が得られた」という恣意的な条件設定は避けるべきです。

「恣意的な数字を用いることはできる限り少なくする」ということを頭に入れておけば、過去データにおける良い成績を作ることに気を取られずに済みます。

成績管理のための変数

今回はflag変数の中に「トレードの成績を記録する関数」を組み込んでいます。

最終的に出力したい情報から逆算してflag変数を定義しています。

ここはバックテストにおけるコードの根幹となる部分です。

flag = {
	"buy_signal":0,
	"sell_signal":0,
	"order":{
		"exist" : False,
		"side" : "",
		"price" : 0,
		"count" : 0
	},
	"position":{
		"exist" : False,
		"side" : "",
		"price": 0,
		"count":0
	},
	"records":{
		"buy-count": 0,
		"buy-winning" : 0,
		"buy-return":[],
		"buy-profit": [],
		
		"sell-count": 0,
		"sell-winning" : 0,
		"sell-return":[],
		"sell-profit":[],
		
		"slippage":[],
		"log":[]
	}
}

具体的には、「手仕舞いの関数が呼び出されるたびにflagをデータを更新して、各トレードの成績をflag変数に記録しなさい」という指示を出しています。

指示の内容は「トレード回の数」「勝ったか負けたか」「利益額」「リターン率」の4点です。

また、買いと売りを区別して記録しています。

その理由は、短い期間でのトレードはトレンドの影響を強く受けるためです。

「買いエントリーと売りエントリーのどちらが有効だったか」を検証するためには、その場面が上昇局面か下降局面かも併せて考える必要があるのです。

買いと売りを分けて検証すると、ロジック自体の有効性が検証しやすくなるのです。

成績を記録するための関数

ここでは取引手数料とスリッページを考慮して、トレードの最終的な損益を計算しています。

また、出力先をlog出力にすることでコンソール画面に余計な情報が出力されることを防いでいます。

botを開発する上で「確認したい情報のみ出力する」ようにコードが書かれています。

またifとappendを組み合わせることで要素の追加を簡単に行うことができます。

appendについては便利な使い方が数多くあるため、実用可能なケースを取り入れていきたいです。

最終的に集計するための関数

集計用の関数ではnumpy(ナムパイ)ライブラリを使って集計データを出しています。

numpyは合計値や平均値などを1行で算出してくれる便利なライブラリです。

ヘタな数式を組むよりも確実にデータの集計を行う工夫です。

またround関数を使って四捨五入をしています。

「数値の丸めかた」については、別の記事も参考にしました。

まとめ

今回はかなり盛りだくさんな内容だったため、意味しらべに時間がかかりました。

正直、現時点でもはっきりと理解できていない部分もあります。

しかし、バックテストに必要な要素を分解してそれらを検証するための道具がコードであることはなんとなく理解できました。

自分が求めているものをはっきりさせれば、あとはそれを算出する方法をコードで実行していくだけです。

必要なものを一つずつ自分で組み上げていくことも大事ですが、すでに先人が作り上げたものを触ってみて理解を深めることも大事なのだと感じました。

今回は、関連記事をかなりたくさん読み漁ったので、これをベースにバックテストの実践を積んでいきます。

-Bot