bifFlyerの自動売買Bitflyerのメンテナンス時間中はBOTの稼働を停止させたい場合Bitflyerでは毎日午前4時00分~午前4時10分にかけて定期メンテナンスが実施されます。このメンテナンスの時間中は新規の注文ができないだけでなく、事前に受け付けられた注文も約定しないまま消滅します。問題1時間足を基準にトレードするBOTの場合、午前4時ちょうどにエントリーや決済のシグナルが出ることもあります。このときBOTの新規注文が拒否されれば通常の例外処理で対応できますが、ギリギリで注文が通ってしまった場合、サーバー側ではそのまま約定することなく消滅するため、BOT側は永遠に約定を待つことになり、トラブルの原因になります。そのため、この記事ではメンテナンス時間中にBOTを停止する方法を解説します。以下のようなコードをメインのwhile文の中の先頭の部分に追加しましょう。nt<et:print("メンテナンス時間中のため待機しています")time.sleep(wait)continue現在の時刻が、メンテナンスの開始時刻(maintenance_start)と終了時刻(maintenance_end)の間に入っていれば、if文の中身が実行されます。while文の先頭に戻る、という指示です。このコード例では周期を60秒(wait=60)にしていますが、ここは各BOTに合わせて調整してください。1件のコメントBitflyerFXの成行注文のスリッページのコストの影響を測定しようBOTの運用を成行注文で行っている場合、バックテスト上の成績と実際の成績が乖離する原因の1つにスリッページがあります。成行注文や逆指値注文は、必ずしも理想の価格で約定するわけではありません。バックテスト上では「100万円で買いエントリーして98万円で損切りした」はずでも、成行注文が1%不利な価格で約定した場合、実際の運用は「101万円で買って97万円で売却する」ことになります。この場合、1回の取引の損失は-2%(バックテスト)から-約4%(実際の運用)まで悪化します。実際にどのくらいのスリッページが発生するかは、おそらく売買ロジックやボラティリティ、成行注文の数量によって異なるので、一概に何%と言うことはできません。この記事では、測定方法などを解説しますが、実際の数値は参考程度にしてください。実際のスリッページの影響は、自分のロジックでBOTを一定の期間や回数動かしてみて、シグナル価格と約定価格の乖離を記録するしかないと思います。以下は実際にログから過去300回程度の取引を抽出して、シグナル価格と約定価格の乖離をまとめたものの一部です。こちらの記事の方法を参考に、普段からBOTでシグナル価格や約定価格をログファイルに出力しておけば、簡単に集計できます。「滑り」の欄でプラスの数値になっているのは、想定していた価格よりも不利な価格で約定したときの乖離率(スリッページ)です。マイナスの数値になっているものは、想定していた価格よりも有利な価格で約定したときの乖離率です。売買ロジックにもよると思いますが、実際に集計してみると「予想よりも有利な価格」で約定するケースも結構あります。後ほど、このヒストグラムを紹介します。1)スリッページの計算式この記事では、スリッページの定義を「シグナル価格に対して何%不利な価格で約定したか?」のコストを表す数値とします。そのままバックテストで使えるようにするためです。計算式は以下になります。スリッページの計算式では、注文がエントリーなのか手仕舞いなのかを区別する必要はありません。買い注文は想定より高く約定したら不利で、売り注文は想定より安く約定したら不利です。このことは常に成り立ちます。2)ログから欲しい数値を集計する方法ログなどのテキストファイルから、欲しい数値(ここではシグナル価格と約定価格)を抜き出す方法を紹介します。どのようなログを出力するかは人によって違うので、ここでは具体的なコードというより、考え方だけ紹介しておきます。このテキストから抽出したい情報を以下の2つとします。いうものを使うと便利です。以下のようなコードを作成すれば、ログファイルを1行ずつ読み込んで、欲しい数字だけを抽出することができます。関数の箇所が「正規表現」です。正規表現とは、毎回、出現する文字や数字の内容が違っている場合でも、その出現パターンさえ同じであれば、()で括られた箇所だけを抜き出すことができる便利な記述ルールです。以下の記事で、詳しい正規表現のルールが記述されているので参考にしてください。実際のログファイルには、BOTの停止や手動での決済が混じってる場合も多く、欲しい情報を正しくセットで抜き出すためには、もう少し複雑なコードを考える必要があります。基本的には上記の方法の組み合わせで実現できます。欲しい数字を全て抽出したら、以前の記事で紹介したようにpandasでデータフレームに変換して、csvなどの形式で出力すれば準備完了です。全ての取引のスリッページ(シグナル価格と約定価格との乖離率)をcsvにまとめることができたら、次にそれを分析してみましょう。今回は以下のような分析結果を作る方法を紹介します。私の運用BOTの場合は上記のような集計結果になりました。全取引のうち、およそ6割が不利な価格で約定し、約3割が有利な価格で約定しています。順張りのロジックのため、明らかにエントリー時に偏って約定価格の滑りが発生しています。複数回に分けてエントリーする場合、後半になるほどバックテストで想定するより不利な価格で約定しています。損切りや利確時にはほとんど滑りは発生していませんでした。0.1%程度の滑りを考慮すれば足りそうだとわかりました。±3%前後で大きく滑っていますが、異常値は必ずしも不利な方向に発生するわけではないようです。最初に示したようなフォーマットのcsvファイルを無事に作成できたと仮定して、話を進めましょう。具体的な分析のコードが以下です。csvファイルを読み込んで、pandasを使って集計しています。pandasの使い方はこちらの記事で解説しているので参考にしてください。matplotlibのhist()関数では、縦軸の目盛りを確率にすることが難しいようだったので、numpyでヒストグラムにしました。スリッページの影響スリッページコストが最終的な成績にどの程度の影響を及ぼすかは、BOTの売買頻度によって異なります。期待リターン2%の取引を年間200回するBOTと、期待リターン0.2%の取引を年間2000回するBOTでは、理論上の期待リターンは同じです。ここに0.1%のスリッページコストを考慮すると、前者の利回りは年間380%である一方、後者は期待リターンが100%になり、最終成績は4倍近い差となります。コメントを残すBitflyerFXでCCXTを使って成行注文を出しその執行価格を取得する方法Bitflyerの自動売買BOTで成行注文を出す場合、その執行価格を把握しておきたい場面があると思います。この記事では成行注文の執行価格を表示するpythonコードを紹介しておきます。・CCXTライブラリを使うCCXT経由でBitflyerに成行注文を出す方法は、以前にこちらの記事で解説しているので参考にしてください。",e)print("20秒待機してやり直します")time.sleep(20)コードの解説まずは以下のコードでBitflyerから約定履歴の一覧を取得しています。」で自分の約定履歴の一覧を取得することができます。取得した約定履歴の一覧からは、[size]で数量、[price]で執行価格を取得することができます。基本的な流れ成行注文の場合、注文がいくつかに分割されて異なる価格で執行されることも多いです。そのため、上記の関数では以下の2つの情報を必要としています。成行注文は、分割されて約定しても全て同一の注文ID(order_acceptance_id)で記録されます。以下のような感じです。0.01}]そのため、成行注文を出したときに注文ID(order_acceptance_id)を覚えておいて、その注文IDで約定履歴を検索すれば、分割されて執行されたすべての注文を捕捉することができます。1.注文がすべて執行されたことを確認する成行注文を送った後に、20秒ごとに約定履歴をAPIで取得して、注文IDが一致している注文の「価格」と「数量」を取得します。それが以下の部分です。)そして「数量」の合計が、最初に送った注文数量と一致すれば、すべて約定したと判断します。一致しなければ、一致するまで20秒ごとに確認を繰り返します。ここでwhileループの先頭に戻る一致したらすべての注文が執行されたものとして次に進みます。2.執行価格の平均を計算するすべての注文数量が約定したことを確認できたら、執行価格を計算します。これは以下の式で計算できます。Bこれをpythonで1行で書くと以下のようになります。sum(size))3.注文サイズの計算方法の注意点もう1つだけ注意点があります。それが小数点の計算です。pythonでは2進法で小数を計算するため、成行注文が細かく割れてしまった場合には、注文サイズが送ったものと一致しなくなることがあります。0.21BTCを成行注文で出した場合を仮定してください。注文が以下のように割れて約定したとします。0.21BTCになります。それではpythonで同じ計算をしてみましょう。そこでround()を使って、注文したときと同じ桁数に小数点を丸める必要があります。それが以下の箇所です。lot:これを最初私はよくわかっていなかったのですが、note読者の方に症状を教えていただき発見できました。いつも計算が一致しないわけではなく、細かい単位で注文が割れた場合の一部のケースでこの症状がおこるようです。成行注文のコードと組み合わせる最後に成行注文を出すコードと組み合わせたパターンも書いておきます。以下のコードで成行注文を出せば、約定後にその執行価格を返すところまでセットで実行できます。損益やスリッページの計算、建値の計算、損切価格ラインの決定などに使ってください。コメントを残すBitflyerFXで注文が消えたり、約定拒否や二重注文になる場合の対策コードPythonでBOTを作ってBitflyerFXで運用していると、以下のようなトラブルにときどき遭遇します。いずれも「対策をしないと気付かないうちに意図しない建玉が残る」という種類のトラブルです。「約定拒否」というのが何かよくわからず、個人的には「注文が消える」と類似の問題と理解しているのですが、もし違ったら教えてください。問題点これらの共通の問題は、通信エラーが判定条件にならないことです。通信エラーが出てくれれば、単に例外処理をすればいいだけですが、通信エラーが出ていないのに注文が反映されない場合(または通信エラーが出たのに注文が執行された場合)、BOTの挙動がおかしくなる原因になります。注文の遅延とは、正常に指値注文のリクエストが受理されたのに、「注文一覧」か「建玉一覧」に注文が反映されない状態です。これはもし「信じて待っていればいつか必ず反映される」という前提であれば、ただひたすら待てばいいことになります。場合は実際それで問題ありません。基本的な遅延の対策コードは以下に紹介しています。参考:Bitflyerで自動売買の試作BOTを作ろう!消えた場合の対策しかしごく稀に「消えてしまう」という厄介なケースがあります。この場合、信じて待っていると永久に「反映待ち」の状態が続きます。そのため、少し気持ち悪いですが、一定の間隔でカウンターを回してどこかで諦めて「消えた」と判定しなければなりません。以下のような感じです。flag通常は多くても5~10行、遅延が続いたあとに注文一覧に反映されます。4月後半に注文が消えるという問題が何度か出たことがあったと思います。記事にしようと思いつつ時間が経ってしまい、少し前のテストなのでうろ覚えですが、たしかこのテストのときは注文が消えたと思います。「注文が消える」ケースはそう頻繁に再現できないので、なかなか対策の方法が難しいです。二重注文は、タイムアウトやサーバーエラーなどの通信エラーが出たにも関わらず、実際には注文が正常に受理されていたパターンです。それに気づかずに、例外処理をして注文を再送すると、ダブルで約定してしまいます。これは注文を連打せずに、ある程度、しっかり間隔をあけて間にポジションチェックを入れれば回避できる気もします。前述のように、遅延が酷いときは1~2分待ったくらいでは確信を持って判断できないときもあります。サーバーが混雑していないときまで毎回1~2分待つのも非効率です。タイムアウトエラーの対策1つの対策としては、接続のタイムアウトの判定時間を長めに設定しておくという方法があります。CCXTライブラリ経由でBitflyerに注文を出す場合、初期設定でのタイムアウトの判定は10秒に設定されています。10秒待って応答がなければエラーとして扱われるわけですが、以下のように記述することで、その待機時間を伸ばすことができます。上記の例では、タイムアウトエラーの判定時間を30秒にしています。抜本的な解決方法ではありませんが、個人的には、上記の設定でかなりエラー頻度が減ったように思います。定期的に建玉をチェックする結局のところ、あまりスマートではないですが、定期的に「意図しない建玉」が残っていないかをチェックするしかないかもしれません。現在の建玉を取得する関数の作り方は以下を参考にしてください。参考:BitflyerFXの平均建値とサイズを取得する例えば、以下のような関数を全体ループの中に入れることを考えます。このような処理をする場合は、今度は逆に「成行注文で決済したはずなのに遅延で建玉が残っている場合」に騙されないように注意しなければなりません。そのため、成行注文を出したときに、確実にすべて執行されたところまで見届けることが重要です。すべての成行注文が執行されたとしても、決済後も「建玉一覧」にポジションが解消されたことへの反映が遅延する可能性もあるため、上記のコードでは5回ほどカウンターを回して確認しています。良い方法も模索中です。コメントを残すCCXT経由でBitflyerFXの現在のポジションの平均建値とサイズを取得するBitflyerFXからAPIで現在のポジションの建値やサイズを取得する方法を解説します。具体的な使い道として以下のような場面を想定しています。前提CCXTライブラリを使います。check_bf_positions()保有中の建玉の価格とサイズ、エントリーの方向の3つをセットで返す関数です。複数のポジションを保有している場合は、平均建値と合計サイズを計算して返します。BitflyerFXでは両建てはできないので、方向(BUYかSELLか)は、複数ポジションのうち1つを参照すれば大丈夫です。そのため、最後に取得したポジションの方向を参照しています。これらのいずれかを使えば、外部から以下のように「ポジション無し」を判定できます。/v1/me/getpositions」を、CCXTライブラリ経由で使用しています。・BitflyerAPIの公式ページこのAPIを使用すると、建玉の情報が配列で返ってきます。そのため、以下のような形式で情報にアクセスできます。ポジションのサイズいくつポジションを保有しているかわからない場合は、for文で回して全ての情報を取得します。合計サイズは、APIで取得した各建玉のサイズの合計値を計算しています。pythonは足し算などの演算を2進法で計算するため、四捨五入しないと最終的な値がおかしくなることがあります。