bitFlyerのAPIの使い方と注意事項
公開日:
:
APIの仮想通貨自動売買 ビットコイン, 自動売買, アービトラージ
目次/もくじ
APIを使ってbitFlyerからレートを取得したり、残高を確認したり、オーダーを出す方法まとめです。基本的に関数化しているので、コピペしてちょっといじれば動くと思います。
取引所にこだわらない場合は、コインチェックのAPIが一番変な癖がなくtて使いやすいです。また、初心者向けに一番詳しく解説しています。
注:また、このページはもともとばらばらだった記事をひとまとめにしたので、話の流れがぶつ切りになっている箇所があります。
Public(パブリック)API
WEB APIは各取引所によって、微妙に仕様が異なります。
コインチェックの場合、phpのfile_get_contentsで取得できましたが、bitFlyerはfile_get_contentでは上手くいきません。(PUBLIC APIは問題ありません。)
原因は”謎”です。
というよりも、そもそもfile_get_contentでうまくいくことの方が昨今めずらしいです。
この周辺のワードで検索するとそういった記事が比較的でてきます。
bitFlyerのレート取得
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php FUNCTION GetTickBF() { global $BF; global $bf_ordertype; if( $bf_ordertype == "leverage" ) $URL_b = "https://api.bitflyer.jp/v1/getticker"."?product_code=FX_BTC_JPY"; else if( $bf_ordertype == "spot" ) $URL_b = "https://api.bitflyer.jp/v1/getticker"."?product_code=BTC_JPY"; //$file = file_get_contents($Url); $file = CURL_BF("GET",$Pass_b,$URL_b,$Body_b,$arrQuery_b); $file = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); $BF = json_decode($file,true); $BF["ask"] = $BF["best_ask"]; $BF["bid"] = $BF["best_bid"]; } ?> |
bitFlyerのサーバーステータス取得
2017年ごろはあまりにもアクセスが多すぎたのでサーバーの状態を測るメソッドが出現しました。現在でもbusy状態でないときにトレードした方が良いと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php FUNCTION GetServerStatusBF() { $URL_b = "https://api.bitflyer.jp/v1/gethealth"; //$file = file_get_contents($Url); $file = CURL_BF("GET",$Pass_b,$URL_b,$Body_b,$arrQuery_b); $file = mb_convert_encoding($file, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); $BF_status_ = json_decode($file,true); $BF_status = $BF_status_["status"]; return($BF_status); }?> |
Private(プライベート)API
PHPのバージョンにもよるのですが、今回はCURLというものを使います。CURLというのはPHPから細かくWEBリクエストするための割と新しい関数群みたいなものです。
現在利用しているPHPのバージョンは5.3ですが、(古い)CURLは問題なく利用できます。
CURLの基本的な使い方に関しては、詳しく書いているブログがたくさんありますので、そちらを参照してください。
bitFlyerは、ハッシュ化の際に
(タイムスタンプ)+(POSTかGET)+アクセスするパス+HTMLボディ
を連結させます。
ドキュメントを見ると、エンドポイントURLがhttps://api.bitflyer.jp/v1/で、各メソッドのパスが/v1/me/getbalanceのようになっていますが、
最終的なアクセス先は
https://api.bitflyer.jp/v1/v1/me/getbalanceではなく、
https://api.bitflyer.jp/v1/me/getbalanceです。
(当たり前と言えば当たり前ですが、変数に代入すると、ここら辺の表記が分かりにくくなるので…)
ハッシュ方式はコインチェックと同じsha256なので、関数はそのまま使えます。
CURLの関数化
CURLはプライベートメソッドでAPIをたたくときに何度も使うので先に関数化してしまった方が便利です。よく分からない場合、他の関数を呼び出すときに必要になるのではっつけておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<?php FUNCTION CURL_BF($postorget,$Pass_b,$URL_b,$Body_b,$arrQuery_b) { global $AccessKey_b; global $AccessSecret_b; global $proxy; global $currentproxy; //for($i=0 ;$i<5;$i++) //{ $TimeStamp_b = time();//round(microtime(true) * 1000); $curl_b = curl_init(); curl_setopt($curl_b, CURLOPT_RETURNTRANSFER,true); if( $postorget == "GET" ) { $Message_b = $TimeStamp_b."GET".$Pass_b.$Body_b; $Signature_b = hash_hmac("sha256", $Message_b, $AccessSecret_b); $options_b = array( CURLOPT_HTTPHEADER => array( "ACCESS-KEY:$AccessKey_b\r\n". "ACCESS-TIMESTAMP:$TimeStamp_b\r\n". "ACCESS-SIGN:$Signature_b\r\n". "Content-Type:application/json" ), CURLOPT_GET => true, CURLOPT_BODY => $Body_b ); curl_setopt($curl_b, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($curl_b, CURLOPT_GETFIELDS, $arrQuery_b); } else if( $postorget == "POST" ) { $Message_b = $TimeStamp_b."POST".$Pass_b.$Body_b; $Signature_b = hash_hmac("sha256", $Message_b, $AccessSecret_b); $options_b = array( CURLOPT_HTTPHEADER => array( "ACCESS-KEY: $AccessKey_b\r\n". "ACCESS-TIMESTAMP: $TimeStamp_b\r\n". "ACCESS-SIGN: $Signature_b", "Content-Type:" => "application/json", "Content-Length:" => strlen($Body_b), ), CURLOPT_POST => true, CURLOPT_BODY => $Body_b ); curl_setopt($curl_b, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($curl_b, CURLOPT_POSTFIELDS, $Body_b); } curl_setopt($curl_b, CURLOPT_URL, $URL_b); //curl_setopt($curl_b, CURLOPT_PROXY, $proxy[$i]); //curl_setopt($curl_b, CURLOPT_TIMEOUT, 10); curl_setopt_array($curl_b, $options_b); $file = curl_exec($curl_b); curl_close($curl_b); return($file); } ?> |
残高確認
APIキーなどはCURLの関数で指定しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php FUNCTION EquityBF() { $Domain_b = "https://api.bitflyer.jp"; $Pass_b = "/v1/me/getbalance"; $URL_b = $Domain_b.$Pass_b; $arrQuery_b = array("hoge" => "foo"); $Body_b = NULL;//http_build_query($arrQuery_b); $res_b = CURL_BF("GET",$Pass_b,$URL_b,$Body_b,$arrQuery_b); return $res_b; } ?> |
取引注文(現物、信用共通)
TradeBF(“spot”(現物取引)か”leverage”(信用取引)、”buy”か”sell”, 取引ロット);
で使用できます。
$AccessKey_bと$AccessSecret_bはどこか先頭とかで宣言して、APIキーを入れておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php FUNCTION TradeBF($bf_ordertype,$ordertype,$orderlot) { global $AccessKey_b; global $AccessSecret_b; global $bf_ordertype; global $proxy; global $currentproxy; if( $ordertype == "buy" ) $ordertype = "BUY"; else if( $ordertype == "sell" ) $ordertype = "SELL"; if( $bf_ordertype == "spot" ) $productcode = "BTC_JPY"; else if( $bf_ordertype == "leverage") $productcode = "FX_BTC_JPY"; $Domain_b = "https://api.bitflyer.jp"; $Pass_b = "/v1/me/sendchildorder"; $URL_b = $Domain_b.$Pass_b; $arrQuery_b = array("product_code" => $productcode, "child_order_type" => "MARKET", "side" => $ordertype, "price" => "0", "size" => $orderlot ); $Body_b = http_build_query($arrQuery_b); $res_b = CURL_BF("POST",$Pass_b,$URL_b,$Body_b,$arrQuery_b); if( strstr($res_b,"Order is not accepted") ) $res_b = $res_b."約定拒否されました。"; if( strstr($res_b,"Market state is closed.") ) $res_b = $res_b."約定拒否されました。"; if( $res_b == "" ) $res_b = $res_b."約定拒否されました。"; $res_b = "bitFlyer:".$res_b; return $res_b; } ?> |
ポジション情報取得
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php FUNCTION GetPositionDataBF() { $Domain_b = "https://api.bitflyer.jp"; $query = "?product_code=FX_BTC_JPY"; $Pass_b = "/v1/me/getpositions".$query; $URL_b = $Domain_b.$Pass_b; $arrQuery_b = NULL; $Body_b = NULL; $res_b = CURL_BF("GET",$Pass_b,$URL_b,$Body_b,$arrQuery_b); return $res_b; } ?> |
決済注文
bitFlyerには決済メソッドがありません。信用取引のポジションの決済は反対売買によって行います。つまり、
ポジション情報を取得
↓
そのポジションと同じロットだけ反対向きに新規注文
↓
決済
という扱いです。
板情報で取引する
面倒臭がって今まで見て見ぬふりをしてきたのですが、
APIで板情報が取れるんですよね。
API:https://lightning.bitflyer.jp/docs?lang=en#order-book
板情報はpublicなので、ヘッダやハッシュ認証はスルーできます。
リクエスト先:https://api.bitflyer.jp/v1/getboard
リクエストするとこんなデータが返ってきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{"mid_price":815490.0, "bids":[{"price":800639.0,"size":0.003}, {"price":800555.0,"size":0.02}, {"price":800518.0,"size":0.01}, {"price":800512.0,"size":0.03}, {"price":800506.0,"size":0.5}], "asks":[{"price":815898.0,"size":0.42}, {"price":815899.0,"size":0.78028098}, {"price":815900.0,"size":0.01}, {"price":815974.0,"size":0.675}, {"price":816179.0,"size":3.60000075}, {"price":816180.0,"size":0.91}, {"price":816999.0,"size":0.62288934}, {"price":817000.0,"size":2.04406616}, {"price":817500.0,"size":0.04}, {"price":817745.0,"size":0.05}, {"price":818000.0,"size":1.175}]} |
形式は単純なので、json_decodeで分解して、いつも通り連想配列に入れれば各値を取得できます。
1 2 3 4 5 6 |
$Url = "https://api.bitflyer.jp/v1/getboard"; $file = file_get_contents($Url); $Board = json_decode($file,true); $CurrentRate = $Board["mid_price"]; $Ask[0] = $Board["asks"][0]["price"]; $Bid[0] = $Board["bids"][0]["price"]; |
※例によってfile_get_contentsではなく、CURLを使った方が良いです。
自動売買のロジックですが、今回は
「大量の指値注文があったら、その少し上に指値を入れる(買いの場合)」
で行きます。
これは株取引で使う手法で、機関投資家レベルの大きな指値が入ると
そのレートよりも不利な方向には動きにくくなるので、
自分の約定レートが不利な方向に動くリスクを抑えるものです。
株の場合は、それを逆手にとって見せ板や仕手のような心理戦になるのですが、
ビットコインの場合、そこまでの領域にまだ来ていないと思います。
どちらかというと、
「大きな注文を入れるけど分割もしないし、仕手もしない」
という大雑把な仮想通貨トレーダーが多いのではないかと思います。
板を観察していると、たいていは0.1以下の注文で、
5BTC程度の注文が入ると比較的大きな指値に見えますが、
その指値に差し掛かると比較的かんたんに相殺されてしまいます。
とりあえず、今回はある特定のレートに合計で20BTC以上の巨大な指値が入ったら、
その少し上に指値を入れるという戦略をとります。
先ほどのコードをループ文にします。
1 2 3 4 5 6 7 8 9 10 11 |
for($i=0;$i<300;$i++) { if( $Board["asks"][$i]["size"] > 20 ) { $TargetAskPrice = $Board["asks"][$i]["price"]; break; } if( $Board["bids"][$i]["size"] > 20 ) { $TargetBidPrice = $Board["asks"][$i]["price"]; break; } } |
これで20BTC以上の指値注文が$TargetAskPrice,$TargetBidPriceにそのレートが格納されます。
しかし、レスポンスを見ると気づくと思いますが、現在レートからかけ離れた古いレートがそのまま残っています。
その古いレートに20BTC以上の指値があると常にそのレートを参照していまう可能性があるので、
現在レートから遠すぎるレートは除外します。
1 2 3 4 5 6 7 8 |
$CurrentRate = $Board["mid_price"]; for($i=0;$i<300;$i++) { if( $Board["asks"][$i]["size"] > 20 && abs($Board["asks"][$i]["price"]-$CurrentRate) < 50000 ) { $TargetAskPrice = $Board["asks"][$i]["price"]; break; } if( $Board["bids"][$i]["size"] > 20 && abs($Board["bids"][$i]["price"]-$CurrentRate) < 50000) { $TargetBidPrice = $Board["asks"][$i]["price"]; break; } } |
とりあえず現在レートから5万円以上離れているレートは除外しました。
必要に応じてこの値は変えた方が良いかもしれません。
あとはこの取得したレート±最小値幅で指値注文を出すだけです。
bitFlyer,CoinCheckは1円刻みですが、ZAIFは5円刻みだったと思います。
オーダーの送信は過去にやり方を記載しているので、問題ないと思います。
bitFlyer x 信用取引 x 成行注文での取引所のバグ
前々から気になっていたのですが、 bitFlyerは信用取引時に変な挙動をすることが多々ありました。 その挙動を掘り下げてみました。
症状が発生するのは、 APIを使って、信用取引で、成行注文のとき です。
どんな症状かというと、 「成行注文のオーダーをリクエストして、 そのオーダーのレスポンスが正常に返ってきても その後にそのポジションを参照するリクエストを送ると、 ポジションが反映されていないときがたまにある」 症状です。
これは自動売買しようとすると比較的深刻なバグで、 ポジション管理するときにポジション管理が不可能になります。 私が観測したところ、エントリーから1分近くの間 ポジションが反映されないことがあります。
これは特に深夜帯で起こりやすいようです。 サーバー状況、板状況に関係なく発生します。
どんな優秀なプログラマでもこの症状に対してはどうしようもないので、 bitFlyerに直接問い合わせたところ、
「担当部署へ確認いたしましたところ、ご申告いただいたような事象が発生することがあり、発注APIはご注文を受け付けた時点でレスポンスを返すため、処理完了までにタイムラグ発生する場合がございます。 誠に恐縮ながら現在のところ明確な改善案等をご案内することができません。 本件につきましては、サービス改善の検討事項とさせていただきます。」
とのことでした。 この事象自体は認めているということになります。
今回のこの仕様は取引所由来なので、 巷のビットコイン自動売買システムはすべからくこの影響を受けていることになります。
いったいどういう対応をしているのか気になるところです。 (そもそも気づいているのかな…)
ZAIFが問い合わせから返答までに50日以上かかったのに bitFlyerは1週間程度で返信が返ってきました。 もう取引所のレスポンスが遅いのがデフォになって 感覚がおかしくなってます。
bitFlyerもAPI仕様変更…(2019/4/12)
最近各取引所からAPIの仕様変更のお知らせが多くなったように感じます。いつかは上限を厳しくしていくだろうとは予想していましたが、2017年のあのときから考えると、だいぶ遅い方だと思います。 以下、bitFlyerの仕様変更案内です。
API によるお取引を提供しておりますが、この度、HTTP API(以下、API)の制限内容を 2019 年 4 月 24 日(水)午後 6 時頃に変更することを決定いたしました。新たな制限内容は以下の通りです。 Private API の呼出は 5 分間で 500 回を上限とします。
上限に達すると呼出を一定時間ブロックします。また、ブロックの解除後も呼出の上限を一定時間引き下げます。 同一 IP アドレスからの API の呼出は 5 分間で 500 回を上限とします。
上限に達すると呼出を一定時間ブロックします。また、ブロックの解除後も呼出の上限を一定時間引き下げます。 0.1 以下の数量の注文は、すべての板の合計で 1 分間で 100 回を上限とします。上限に達するとその後 1 時間は 1 分間で 10 回まで注文を制限します。
システムに負荷をかける目的で注文を繰り返していると当社が判断した場合は、API の使用を制限することがあります。ご了承ください。
現在の API 制限内容やその他の API の仕様については API ドキュメントをご参照ください。
https://lightning.bitflyer.com/docs?lang=ja#http-api
また、同時刻以降、サービス画面、アプリ、API 経由での注文問わず、各板ごとに同時に保持できる注文数の上限を特殊注文は 10、それ以外の注文は 200 とします。既存の注文は引き続き保持いただけますが、上限に達すると新規の注文を出せなくなります…
”Private API の呼出は 5 分間で 500 回を上限とします。” なぜ1分ベースではなく5分ベースなのかはちょっと気になるところではありますが、制限というにはかなり緩い部類だと思います。
本当に悪質な攻撃的なアクセスだけを省く、といったメッセージに感じます。ただ、VPS上で複数のソフトを起動したりすると、引っ掛かる可能性はありますね。
VPSの中にはIPアドレスをケチって、ポートで振り分けているのも多いので、同じグローバルIPアドレスを利用している他のユーザーが同じようなことをしていたら、ちょっと厄介ですね。
関連記事
-
コインチェックのAPIの使い方[PHP]
公開:2017/6/21 PHPプログラマと言っても、いろいろな分野の人がいるわけで、WEB系だか
-
仮想通貨の自動売買API開発 使用言語と方向性
公開:2017/6/21 今ならAPIの仕様の改良により、 CoinCheck、ZAIF、bit
-
[API]ビットコインスキャルピングの自動売買システムの作り方(Poloniex)
「アービトラージあるからいいじゃん」ってずっと思ってたのですが、(今でも思ってる)スキャルピングに関
-
仮想通貨アービトラージシステムを作る[Binance vs Poloniex]
この記事ではポロニエックスとバイナンスでAPIを使ったアービトラージシステムを作る具体的な方法を解説
-
APIビットコインアービトラージシステム
ここまで業者間アービトラージシステムのプログラミングの考察?をしてきましたが、 中には「中身がどう