そのため、Profit列が0以上の行の数を数えて、それを全体の行数で割れば、全体の勝率が計算できます。行だけに限定して行えば、買いトレードの勝率を計算できます。書くことで新しい列を作成できます。総損益とは、要するに利益の累積和のことなので、Profit列のcumsum()を計算します。)cummax()で累積最大値を調べることができます。累積最大値とはその行までの最大値のことです。Gross列の2行目までの累積最大値は42264、3行目までの累積最大値は75676になります。n行目の総利益を差し引いたもの」なので、上記の式で各行の最大ドローダウンを計算できます。引き算には、subtract()を使います。1件のコメントPandasの練習問題ーBTCFXのドンチャンブレイクアウトBOTの月別成績を集計する前回の記事「Pandasを使ってBTCFXの自動売買BOTの月別の成績を集計しよう!」の練習問題の回答コードです。今回のコードではPandasの集計方法を使って以下のような指標も加えておきました。・最終的な損失合計これらも自動売買BOTの成績を評価する際に参考にしてみてください。以下が1時間足でシンプルな30期間のドンチャンブレイクBOTを、2017年8月~2018年4月にかけて運用した場合の成績です。月別の成績で見ても、すべての月でプラスの成績が出ています。これはなかなか悪くない結果ですね。こちらの月別の成績は、あくまで「ポジションを手仕舞った日時」を基準に区切っている点に注意してください。2月の成績はプラスになっていますが、これは1月から持ち越したポジションで大きな利益が出ているからです。2月からBOTの稼働を開始していたら、2月の損益はマイナスになります。基本的には、前回の記事「Pandasを使って自動売買BOTの成績を月別に集計しよう!」で、例として解説したコードをそのまま使っています。難しいところは無かったのではないでしょうか。以下のところだけ、前回の記事には登場していなかった書き方なので、追加で解説しておきます。最大ドローダウン率とは、ある行の最大ドローダウンの金額を、その行までの最大資産額で割った数字です。特定の行までの最大値は、cummax()で取得できます。そのため、以下のような式になります。100,1)ただし実際に最大ドローダウン率を表示するときには注意が必要です。ドローダウン率の中から最大値を選ぶだけだと、最大ドローダウンの金額と時期が一致するとは限らないからです。「最大ドローダウン率でみると序盤の2月の30%が最大だけど、金額ベースでみると4月の300万円が最大ドローダウンだ」ということもあり得ます。このとき私たちが知りたいのは、最大ドローダウン率ではなく、「最大ドローダウン金額が最大だったときのドローダウン率」であるはずです。そのため、以下のように記述します。最大ドローダウンと同じ行のドローダウン率を取得records.DrawdownRate.loc[records.Drawdown.idxmax()]これで最大ドローダウンと同じ時期のドローダウン率を取得することができました。))pandasの表データを1行ずつループ処理したい場合、以下のように書くことができます。(インデックス)というのは、表データから特定の「行」を検索するときの「索引」のことです。0,1,2,3,4,5.....などの行番号が割り振られていますが、それだと検索するときに不便です。Gross/Rate/Drawdownなど)があるのと同じように、行にも名前を付けることができます。「2017/08」「2017/09」「2017/10」などのDate型のデータが指定されています。コメントを残すpythonで資産曲線を作って自動売買BOTの成績を視覚的に評価しよう!自動売買BOTの世界では、長期的に使える強いトレードシステムのことを「堅牢性(ロバスト性)がある」と表現します。わかりやすい言葉でいうと「環境の変化に強く安定したシステム」のことです。「堅牢性がある」とは、単に期待リターンが高いというだけではありません。以下のような特徴を備えた売買ロジックのことをいいます。1.期待リターンに対してリスクが低い2.毎月の期待リターンのバラツキ具合が小さい3.最大ドローダウンが小さい4.最適化された固定値のパラメーターが少ない前回の記事では、自動売買BOTの勝率・期待リターンなどを計算する方法を勉強しましたが、それだけではシステムの堅牢性は評価できません。この記事では、ドンチャン・ブレイクアウトBOTの堅牢性を評価するために資産推移のグラフを描写して、さらに最大ドローダウンを計算する方法を解説していきます。先にpythonでグラフを描画する方法だけ解説しておきましょう。練習としてBTCの日々の終値の価格グラフを作成してみましょう。以下のように書くだけです。いうライブラリを使います。これはAnacondaを使ってpythonをインストールした方であれば、最初から入っていますので、以下の1行を先頭に書くだけで使用できます。pltコードの解説まずX軸とY軸にそれぞれ描画したいデータを配列として用意します。それぞれの要素の数が一致していないといけないので、注意してください。今回は、日付データ(date_list)と価格データ(price_list)にそれぞれ14個ずつのデータを用意しました。次に、日付データを「テキスト型」から「日付型」に変換します。日付型に変換するのかというと、テキスト型のままだと以下のようなデータがすべてX軸に等間隔で並んでしまうからです。["1/1","1/2","3/2","3/4","4/2"]テキスト型のままだとこの5個のデータは、同じ目盛り上に等しい間隔で並んでしまいます。1/1~1/2と、1/2~3/2が、同じ間隔で並んでしまうと、後ほど資産推移の曲線などを描画するときに困りますね。これを避けるために、以下のコードで日付型に変換しておきます。pd.to_datetime(date_list)ここでは変換にpandasというライブラリを使用しています。こちらもAnacondaでPythonをインストールした方であれば、最初からインストールされています。ない方はpipを使ってください。当サイトと同じ方法で(Anacondaで)Pythonをインストールしている方なら、すでにSpyderという実行環境がインストールされています。そのため、上記のコードを実行すると、自動的に以下のようなウィンドウが立ち上がり、グラフの描画が実行されます。グラフの描画の説明はこれだけです!2)資産曲線を描くまずは資産カーブを描くために、ポジションを手仕舞うたびにその時点での損益(資産推移)を記録するコードを作っておきましょう。やり方は前回までの記事と全く同じです。資産推移のグラフを描くために必要なデータは以下の2つです。1)各ポジションを手仕舞った時点での資産額2)各ポジションを手仕舞った時点の日付(時間)まずは資産額と日付を記録するために、flag変数に以下を追加しておきましょう。追加"slippage":[],"log":[]}総損益を記録するための配列データには、初期値として0を入れておきます。以下のように書けばいいですね。records)で、ポジションを手仕舞ったときの日付データを記録しておきます。これはローソク足のデータを記録する変数(data)にある日時情報(data[“close_time_dt”])を代入するだけです。総損益を記録する変数(gross-profit)の前回の値([-1])を取り出し、そこに今回の最新の損益(buy_profit/sell_profit)を足した数字を、appendで配列の末尾に追加します。これで準備は完了です。backtest)の中で資産カーブを描画するためのコードを追加します。X軸の目盛りを50度回転plt.show()最初の例と全く同じですね。[0]で先頭の0円を削除しています。pd.to_datetime()で、日付のテキストデータを日付型に変換しています。期間、6000足分のローソク足データを使って検証した結果です。資産カーブ右肩上がりといえば右肩上がりですが、何度か大きなドローダウン(利益が大きく削られる局面)を経験していることがわかりますね。この売買システムの最大ドローダウンはどのくらいの大きさなのでしょうか?3)最大ドローダウンを計算するまずpythonで最大ドローダウンの計算を実装するにあたって、ドローダウンとは何なのか?を明確に定義しておきましょう。自動売買BOTを自作でプログラミングする最大のメリットは、あらゆるテクニカル指標・売買ロジック・バックテストの指標などをコーディングする過程で、正確にその意味を理解できるようになることです。私もそうですが、文系で何となく投資本を読んでいるだけだと、ドローダウンの意味1つとっても、「何となくこういうものだろう」というイメージだけで理解してしまいがちです。自分でコーディングするようになると、どんな指標・ロジックでも明確な定義を考える習慣がつきます。定義を考える習慣がつくようになると、単に概念を本で学んで覚えているだけの人に比べて、その指標の活用方法や弱点に気づきやすくなります。基本的にはドローダウンは、「ある時点での資産額と、それ以前の資産の最大額との落差のこと」と定義できます。以下のように資産が推移したと過程しましょう。210万円この場合、大きなドローダウンは2つ存在します。1つ目は、3月のピーク200万円から5月の150万円までのドローダウン(-50万円)です。1つは、7月のピーク(220万円)から10月の170万円までのドローダウン(-50万円)です。この場合、最大ドローダウンは-50万円、ということになります。約22.7%のドローダウンです。2.Pythonコードで実装するではこれを実装していきましょう。手始めに、とりあえず、いつものように記録用の変数を追加します。以下のような変数を追加しておきましょう。0,次にポジションを閉じるたびに呼ばれる「各トレードの成績を記録する関数」に、以下の3行を追加しましょう。drawdownポジションを閉じるたびに、その時点における過去の資産の最大額をmax(flag[records][gross-profit])で探します。そこから、現時点での資産額(flag[records][gross-profit][-1])を引いて現在のドローダウンを計算します。代入して値を更新します。これにより、最終的に「最大ドローダウン」だけが残ります。最後に「バックテスト集計用の関数」に以下を追記します。))ここで最大ドローダウンの金額を表示するとともに、そのパーセンテージも計算して表示しています。これを実行してみましょう。以下のようになりました。過去の半年間に1時間足で30期間のドンチャンブレイクアウトを採用していたら、この部分の最大ドローダウンが約48万円(-23%)だったということですね。これを最後に検証して、今回の記事を終えておきましょう。以下のコードの部分を変更するだけです。・UNIX時間変換ツールこれを実行すると、以下のようになります。資産カーブ1枚のBTCを売買したとすると、開始早々-20万円のドローダウンに見舞われることになります。その後、+20万円まで持ち直しますが、そこから-約50万円のドローダウンを食らいます。長期的には期待値プラスの売買ロジックでも、このように開始早々、大きなマイナスを食らったり、数カ月連続してプラス転換しない場合もあります。このようなときに、長期的な期待値を信じて我慢できるかどうか、あるいは「相場が変わったからもうこのシステムは通用しないんだ...」と諦めるべきかは、判断が難しいところです。パラメーターの過剰最適化がされていない、バックテストのデータ数が十分である、など、堅牢性の高いシステムであればあるほど、このような局面でも期待値を信じて我慢することが可能になります。この章のはじめで、サンプル数の重要性などを説明したのはそのためです。今回の勉強で使ったコード最後に今回の記事で作ったpythonコードを掲載しておきましょう。2件のコメントBTCFXのドンチャンチャネルブレイクアウトの勝率をバックテストで検証する前回までの記事で、過去チャートのバックテストで自動売買BOTの勝率や平均リターン、総損益を検証する基本的な方法がわかったと思います。今回の記事では、「ドンチャン・ブレイクアウト」というより実践的な売買ロジックを使って、さらに高度な自動売買BOTの評価方法を解説していきたいと思います!ドンチャンブレイクアウトとはブレイクアウト手法とは、狭い値幅での揉み合い(レンジ相場)をブレイクアウトした瞬間を捕まえてエントリーし、その後のトレンドに乗って利益を出す順張り(トレンドフォロー型)の手法のことをいいます。ブレイクアウトを捉えるための手法はさまざまなものが開発されていますが、シストレなどの自動売買BOTの世界では、以下の2つが最も定番です。1.ドンチャン・チャネル・ブレイクアウト過去n期間の最高値・最安値を更新したときに、その方向にエントリーする手法です。過去20期間の最高値を更新したときに「買い」でエントリーします。次に過去20日の最安値を更新したときに決済して手仕舞いますが、このときさらに反対方向にそのままエントリー(ドテン)する場合も多いです。このシンプルな戦略の優位性は、トレーダーの必読本である「タートル流投資の魔術」や、ジョン・ヒルの「究極のトレーディングガイド」などの本に詳しい解説があります。非常に単純な売買ロジックなので、プログラミングしやすく、シストレや自動売買BOTの勉強にも最適です。2.オープニングレンジ・ブレイクアウトオープニングレンジ・ブレイクアウトも同じく「どうやったらブレイクアウトの開始点を、シンプルな数字とロジックで発見できるか?」という視点で開発された手法です。こちらは、過去n期間の値幅の平均値(ATR)を基準値として利用し、ある足が始値から(基準値の)X%以上動いたらその方向にエントリーします。過去3期間の安値–高値の平均値が10万円でXが70%とすると、次の足で始値から7万円上に動いた時点で買いでエントリーします。前の足が陰線か陽線かで場合分けをして、買いと売りとで別々のX%のパラメーターを使用することが多いです。この戦略については、ラリーウィリアムズの「短期売買法」や、先ほどのジョンヒルの「究極のトレーディングガイド」などの本に詳しい解説があります。3.戦略の使い方どちらも多くのトレーダーが知っている手法ですが、実際には、どの時間軸でどういうパラメーターを使うか、どういうトレンド判定の条件やフィルターと組み合わて「騙し」を除去するか、どういう手仕舞いの方法を選択するか、などによって全く違う成績になります。これらの手法は、あくまで売買ロジックを考えるときにベースのアイデアとして使いやすいというだけで、それ自体が必勝法というわけではありません。詳しい戦略のカスタマイズ方法などは、今後、解説していく予定です。今回はバックテストの方法の解説記事なので、まずは一番シンプルな「ドンチャン・ブレイクアウト」のロジックをpythonでコーディングするところから始めます。ブレイクアウトは非常に単純なロジックなので、今まで勉強した知識だけでも、pythonのプログラムコードを書くことができます。やっていきましょう!ドンチャン・ブレイクアウトのpythonコードプログラミング初心者の方は、いきなり複雑なロジックを書こうとしてはいけません。必要最小限のシンプルな骨組みの部分を作り、そこから徐々に条件などを足していくのがお勧めです。買いと売りの両方を考えて混乱するならまずは買いエントリーだけ実装しましょう。エントリーと手仕舞いの両方を考えて混乱するなら、まずは「n足後に無条件で手仕舞う」といったシンプルなロジックで実装しましょう。今回は以下のように定義してみます。1.今回実装するロジック1)過去n期間の最高値を直近の足の高値が上回ったら(その足の終値の指値で)買いエントリーする。過去n期間の最安値を直近の足の安値が下回ったら売りエントリーする。BOT作成編」で勉強した内容を前提としながらコーディングしてみましょう。2.pythonコード以下は、Cryptowatchから過去のローソク足を取得して、20期間のドンチャンブレイクアウトで売買シグナルや手仕舞いのタイミングを確認するためのコードです。1time.sleep(wait)基本的な仕組みは、第4回で作成した練習用のBOTと同じです。いう変数に過去のローソク足のデータを入れて、それを比べることでエントリーシグナルの条件を満たしたどうかを判定しています。1.ドンチャンブレイクアウトのデータ準備ただしドンチャンブレイクアウトでは、過去n足(以下、20期間として説明します)の最高値をブレイクしたかどうかを判定する必要があるため、過去20期間分のローソク足データを保持する変数が必要です。そこでメイン処理のループ文の最初に以下のような処理を入れます。部分で、last_dataに含まれているローソク足データの数が、20足分に達するまで上記の処理を実行するように指示しています。「これより下は実行せずにwhile文の先頭に戻る」という意味です。last_dataという変数に過去20足のローソク足データが保持されるまでは、この先の処理はおこなわず、この部分の処理だけをループで実行します。20足分のデータが溜まった後は、ループのたびに以下の処理を実行します。含まれる先頭のデータを削除しています。末尾に追加しています。いう変数の中身を、常に過去の新しい20期間分のローソク足データにぴったり揃えることができます。"price":0}この関数で、ドンチアン・ブレイクアウトが発生したかどうか、どちらの方向に発生したかを判定しています。ロングの方向にブレイクアウトが発生した場合は「BUY」シグナルを返し、ショートの方向にブレイクアウトが発生した場合は「SELL」シグナルを返します。一緒に、ブレイクアウトされた最高値・最安値の価格を返す(return)ようにしておきます。過去20足の最高値を更新したかどうか、を判定するロジックが以下の部分です。含まれる変数を1個ずつチェックし、["high_price"]だけを取り出した配列を作り、max()でそこから最大値を取得しています。これはリスト内包表記というfor文を1行で書くための書き方ですが、少し難しく感じる方は、今まで勉強した知識を使って以下のように書いても構いません。i["high_price"]また、この最高値(highest)を、現在の最新のローソク足の高値(data["high_price"])と比べ、もし現在の最新のローソク足の高値の方が高ければ、ブレイクアウトの条件を満たしたことになります。ブレイクアウトされていた場合は、その方向と価格をセットで返します。関数を呼び、ドンチャンブレイクアウトが発生しているかどうかを確認します。いう変数で受け取ります。)これで"BUY"が返ってくれば買いでエントリーし、"SELL"が返ってくれば売りでエントリーしています。"SELL"こちらも基本的な手順は同じです。実行して、ドンチャンブレイクアウトのシグナルを確認します。買いポジションを持っている場合は、売り方向にブレイクアウトが発生した場合のみ、ポジションを決済します。0ポジションを手仕舞ったので、flag変数の[exist]をFalseに更新しておきます。そのまま売り方向でのエントリーを試みます。これがドテン注文です。"SELL"ドテンでエントリー注文を出したので、またflag変数の[order][exist]をTrueに更新しておきます。これで、次のwhile文では「注文が通ったかどうか確認する関数」が呼ばれることになります。このドンチャンブレイクアウトのバックテスト(勝率の検証用)のコードを作り、以下の項目を計算してみましょう。コードの書き方は前回の記事で説明したのと全く同じです。上記の練習問題で、こちらのドンチャンブレイクアウトの勝率をバックテストで検証すると、以下のような成績になります。これだけシンプルな売買ロジックでも、成績はそれほど悪くないように見えますね。トレンドフォロー戦略は、一般論として勝率が低いです。トレードの相場の大半がレンジ相場なので、ブレイクアウトの方向に順張りするロジックは「騙し」に引っかかりやすく、勝率が低くなりがちです。その代わり、1度トレンドに乗れれば大きな利益を得られるため、勝率が50%を下回っても期待値は正(プラス)になる、というのが典型的な教科書の考え方です。バックテストの注意点しかしこのような戦略には、特有の弱点もあります。それはドローダウンが大きいことです。平均保有期間が長いため、途中で一時的に大きく資産が目減りする時期があるかもしれません。月別のリターンにかなり大きなバラつきがある可能性もあります。最終的な平均リターンが2%でも、例えば、その範囲がマイナス数十%までバラついている可能性もあります。これらのリスクは、上記の成績表を見ているだけではわかりません。1件のコメント【解答】ドンチャンチャネルブレイクアウトBOTの勝率や平均リターンを検証するコード前回の記事「BTCFXでドンチャンブレイクアウトの勝率をバックテストで検証する」の練習問題の回答コードです。