見出し画像

Optuna(TPE)を利用したバックテストによるBOTトレードのパラメータ最適化について

バックテストでBOTのパラメータを決める時、みなさんどうしてますか?
地道にトライ&エラー
全網羅で最適組合せ
ボッターの勘!
中には遺伝的アルゴリズムでBOTを進化させてる人もいるでしょう。
このnoteでは機械学習のハイパーパラメータ決定のためのフレームワーク「Optuna」をシステムトレードに応用する方法をご紹介します。

自己紹介

はじめまして。私は仮想通貨でシステムトレード、いわゆるBOTを運用しているさぼりーまんパパ(@akihitot1)と言います。
主に、くもすけさんが公開しているBFS-Xを使用しています。


このBFS-Xにはバックテストプログラムがついています。
私も利用しているのですが、効率よく最適なパラメータを探索するために「Optuna」という機械学習のハイパーパラメータ自動最適化フレームワークを利用しています。
少し前にBFS-XのDiscordサーバー内でバックテストの話題で盛り上がっていたので、今回のnoteを書いてみようと思うに至りました。

Optunaとは

冒頭から出てきている「Optuna」とは、株式会社Preferred Networksが公開するオープンソースの機械学習向けハイパーパラメータ自動最適化フレームワークです。読み方は「オプチュナ」です。機械学習をかじったことのある方はご存じかもしれません。
これまではβ版でしたが、ちょうど、2020年1月14日にメジャーバージョンとなるv1.0が公開されました。プレスリリース 公式サイト
私が使用していたのはβ版ですが、v1.0でも動作確認しています。TPE(Tree-structured Parzen Estimator)というアルゴリズムを利用しており、効率的に最適なパラメータを探索できるようです。ちなみに、私はアルゴリズム自体の話は全く分かりません。。

Optunaの詳細な解説はQiitaなど各所で紹介されています。使い方も簡単ですので、ここでは私が実際にパラメータを決めてみた様子をご紹介します。

試してみた結果

BFS-Xのサンプルロジックの一つについて、付属の 2019/12/14 の約定履歴を使って最適化していきます。
可変にするパラメータは、設定ファイルの上から4つにしました。
上から順に

param1:2~50の範囲の整数
param2:1~50の範囲の整数
param3:0~100の範囲の整数(5刻み)
param4:0~200の範囲の整数(5刻み)

と、なるようにプログラムを書きました。

param1 = trial.suggest_int('param1', 2, 50) 
param2 = trial.suggest_int('param2', 1, 50) 
param3 = int(trial.suggest_discrete_uniform('param3', 0, 100, 5)) 
param4 = int(trial.suggest_discrete_uniform('param4', 0, 200, 5)) 

こんな感じです。
試行回数はとりあえず100回にしましょう。

study.optimize(objective, n_trials=100)

こんな感じです。
実際に実行します。

画像2

見にくいので1行抜粋します。

[I 2020-01-21 04:09:46,164] Finished trial#81 resulted in value: -3057.0. Current best value is -3410.0 with parameters: {'param1': 34, 'param2': 2, 'param3': 55.0, 'param4': 65.0}.

これがOptunaが試行するたびに出力されるログです。
#81が実行番号で、最初は#0からなので82回目の試行です。
-3057.0の部分はここでは詳しく説明しませんが、この試行のスコアです。
「Current best value is」以降は今までのベストのスコアとその時のパラメータです。Optunaはスコアが小さくなるように最適化してくれます。

このような感じで100回バックテストを試行していきます。
今回は単純に最終利益額が最大となるようにプログラムしています。
100回の試行が終わり、最終結果が出たら、現時点で最適なパラメータを取得してバックテストを実行してみましょう。

画像2


なかなかいい感じのパラメータになったのではないでしょうか?
ここまでで、実行時間は準備を含めて10分程度です。

今回は Google Colaboratory でGPUを使って実行しています。
もちろん、Cloud9がのっているVPSでOptunaを実行することもできます。

画像3

こちらも見にくいので1行抜粋します。

[I 2020-01-21 15:21:24,670] Finished trial#0 resulted in value: -648.0. Current best value is -648.0 with parameters: {'param1': 26, 'param2': 14, 'param3': 0.0, 'param4': 145.0}.

1回目の試行ですね。まだまだこれからです。

このように、Google Colaboratory と同じように実行できます。
100回の試行が終わったら、同じように最適なパラメータでバックテストを実行してみます。

画像4

いかがでしょうか?こちらも10分以内でここまでの最適化ができました。
結果がちょっと違いますが、100回だけだとまだ収束しきっていないのかもしれません。ある程度ランダムな部分が出てきます。

それぞれのパラメータの候補の範囲を変えてみたり、試行回数をもっと多くしてみたりするとさらに良いパラメータが見つかるかもしれません。

ここで疑問が一つ

「局所最適解に陥ってるだけじゃないの?」

おっしゃる通り、その可能性はあります。
全網羅してみるともっといいパラメータがあるかもしれません。
ただ、圧倒的に実行時間が違うのと、ある程度良いパラメータができたらそれで良いかな?という思いもあります。

バックテストはあくまでバックテストなので、昨日まで通用しても今日から急に通用しなくなるかもしれません。
ある程度良い成績が得られたら、あとはフォワードテストなり次のフェーズに回していいのでは?と考えています。(諸先輩方にお叱りを受けるかもしれませんが。。。)

以上が今回の「Optuna」の紹介となります。
回数を重ねる毎にパラメータが最適化されていく様子は見ていても楽しいものがあります。
どうでしょう?みなさんの参考になりましたでしょうか?
BFS-X のバックテスト以外でももちろん使えます。オープンソースなのでソースを確認しながら無料で今すぐ利用できます。

今回紹介したのは本当に基本的な使い方だけです。他にも便利な機能がいっぱいあります。興味のある方はドキュメントなど読む事をお勧めします。
私は実際に使う際には、最適化の経過をSQLiteに保存する機能を使っていて、オススメです。

今回、私が書いたPythonのファイルとGoogle Colaboratoryのipynbファイルを、有料部分で公開しています。さらに、おまけとして、もっとOptunaを活用するためのTipsも書きました。よろしければ買っていただけると非常に嬉しいです!(台所事情が非常に厳しいのです…)

さいごに(謝辞)

最後になりましたが、今回ご紹介した「Optuna」をバックテストに取り入れようと思ったのは、ヤス@リアルダル(@yasu_smaholi)さんのGitHubリポジトリに公開されている「Channel Breakout Bot for bitflyer-FX」の「機械学習によるoptimization」の項でTPEを使用されているのを拝見したからです。ここに感謝の意を表します。ありがとうございます。

有料部分について

以降は有料部分として、実際に無料部分のために作成したソースコードと、パラメータ最適化のカスタマイズについてのTipsを公開したいと思います。
ソースコードはBFS-Xのバックテストプログラムを利用する前提の作りになっていますので、BFS-Xをお持ちの方は、すぐ「Optuna」を利用したパラメータの最適化がお試しいただけます。
公開するソースコードは以下の2点です。

・optuna_sample.ipynb 
・optuna_sample.py

※BFS-Xをお持ちでない方は、ご自身でバックテストプログラムをご用意してもらう必要があります。ソースの修正なども必要になります。ご注意ください!
また、予告なく値段の変更をする可能性がある点、ご了承ください。
本noteの内容について、基本的に質問・サポートなどは行いません。
ですが、Twitter(@akihirot1)にDMいただければできる範囲でお答えいたします。

編集履歴

(2020/01/23)
・BFS-Xのバージョンアップにより必要なくなったバックテストプログラムの修正に関する記載を削除
・有料部分のソースコード内の伏字を無くし、関連する記述を削除
・「使い方について」の部分をBFS-XのV4.41を想定した記載に修正
・その他軽微な修正

ここから先は

2,120字 / 1ファイル

¥ 1,800

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