bitFlyer APIを使ってビットコインのFX取引をしてみる

ビットコインが爆上がりした1年でしたね。まさか100万円を超えたことにも驚きましたが瞬く間に200万円を突破してしまいました。
1年前に戻ってまだ手放すな！　と言ってやりたい...

まあ、それはさておきビットコインの面白いところはその出自からしてFinTech的なキーワードを持ってるのでエンジニアフレンドリー、つまりAPIを持ってる取引所が多いことも特徴かと思います。
なので、MetaTraderみたいなの使わなくても好きな言語でbotなりツールが書けるのも魅力的なところ。

というわけで今回はbitFlyerのAPIを使ってビットコインのFX取引をしてみます。
私はIFD取引をすることが多いのですが、bitFlyerはIFDがUI的に結構やりづらいので自分向けのカスタムUIを作るところを目指します。

bitFlyer APIでできること
-----------------

bitFlyer APIでは以下のことが出来ます。

- 板情報(最終売買価格とか)などの公開情報の取得
- 売買(BTC/JPY,BTC-FX/JPY,ETH/BTCなど)
- リアルタイムAPI(PubNub)による情報の随時取得

まずはAPIキーの取得
-----------------

まずはAPIキーの取得をします。[開発者ページ](https://lightning.bitflyer.jp/developer)で`新しいAPIキーを追加`を押すと「APIキー」と「API Secret」が生成されます。
こちらを利用することで認証を行えます。APIキー毎に利用できる権限を制御できるので不要な権限はなるべく付けない方がいろいろと便利かと思います。
ここで生成したキーは決して外部に公開しないようにしてください。githubとか要注意。

Rubyで呼び出し部分を作成
-----------------

[PlayGround](https://lightning.bitflyer.jp/docs/playground)を利用することで、APIの振る舞いの確認が簡単にできます。
ただし、ここで実行されるprivate系の処理は実処理なので売買すると実際にも売買されるのでそこだけ注意してください。
PlayGroundでは各種の言語での実装も記載されるのでそれを参考に簡易のAPIラッパーを以下のように作ります。

```ruby
class BitFlyerAPI
  require "net/http"
  require "uri"
  require "openssl"
  require 'json'
  
  def initialize key, secret
    @key = key
    @secret = secret
  end

  def call_api(key, secret, method, uri, body="")
    timestamp = Time.now.to_i.to_s

    text = timestamp + method + uri.request_uri + body
    sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text)

    options = if method == "GET"
      Net::HTTP::Get.new(uri.request_uri, initheader = {
        "ACCESS-KEY" => key,
        "ACCESS-TIMESTAMP" => timestamp,
        "ACCESS-SIGN" => sign,
      });
    else
      Net::HTTP::Post.new(uri.request_uri, initheader = {
        "ACCESS-KEY" => key,
        "ACCESS-TIMESTAMP" => timestamp,
        "ACCESS-SIGN" => sign,
        "Content-Type" => "application/json"
      });
    end
    options.body = body if body != ""

    https = Net::HTTP.new(uri.host, uri.port)
    https.use_ssl = true
    response = https.request(options)
    
    JSON.parse(response.body)
  end

  def collatera
    uri = URI.parse("https://api.bitflyer.jp")
    uri.path = "/v1/me/getcollateral"

    call_api(@key, @secret, "GET", uri)
  end

  def positions(product_code)
    uri = URI.parse("https://api.bitflyer.jp")
    uri.path = "/v1/me/getpositions"
    uri.query = "product_code=" + product_code

    call_api(@key, @secret, "GET", uri)
  end
  
  def executions(product_code)
    uri = URI.parse("https://api.bitflyer.jp")
    uri.path = '/v1/executions'
    uri.query = 'product_code=FX_BTC_JPY'
    
    call_api(@key, @secret, "GET", uri)   
  end
  
def sendparentorder size, buy_price, sell_price, trigger_price
    uri = URI.parse("https://api.bitflyer.jp")
    uri.path = "/v1/me/sendparentorder"
    params = {
      "order_method"=>"IFD", 
      "minute_to_expire"=>10000, 
      "time_in_force"=>"GTC", 
      "parameters"=>[
        {
          "product_code"=>"FX_BTC_JPY", 
          "condition_type"=>"LIMIT", 
          "side"=>"BUY", 
          "price"=>buy_price, 
          "size"=>size
        }, 
        {
          "product_code"=>"FX_BTC_JPY", 
          "condition_type"=>"STOP_LIMIT", 
          "side"=>"SELL", 
          "price"=>sell_price, 
          "trigger_price"=>trigger_price, 
          "size"=>size
        }
      ]
    }

    body = JSON.generate(params)
    call_api(@key, @secret, "POST", uri, body)
  end
end
```

下記のように利用します。
生のRESTをラッピングして板情報や保証金の状態をハッシュで取り扱える形にしました。

```ruby
api = BitFlyerAPI.new "APIキー", "秘密鍵"
api.collatera
> {"collateral"=>3088.0, "open_position_pnl"=>0.0, "require_collateral"=>0.0, "keep_rate"=>0.0}
```

任意の含み益を目標に取引
---------------

私が売買する時は大体IDFでどのくらいの含み益を見込んで、許容する損失はどのくらいか？を考えて購入します。
なんで、買いの時の算出式は以下の感じ。これで、何枚のコインをどのくらいで買ってどのくらいで売るかを算出できます。

```ruby
r = api.collatera

collateral = r["collateral"]
pnl_limit = -500 # 許容損失
target_profit = 10 # 目標利益(円)
size = 0.001 # 購入コイン数
buy_coinprice = api.executions("FX_BTC_JPY").first["price"] # 現在の1ビットコインあたりの買い価格。
buy_price = buy_coinprice * size 
sell_price = buy_price + target_profit # 
sell_coinprice = (sell_price / size).to_i # 目標利益を出すための1ビットコインあたりの売り価格
trigger_price = buy_price + pnl_limit 
trigger_coinprice = (trigger_price / size).to_i # 許容損失に抑えるための売り価格
leverage = 3 #レバレッジ
require_collateral = buy_price / leverage # 必要書庫金
```

上記で計算した値をハッシュに詰め込んで、以下のようにsendparentorderメソッドでIDFでのLIMIT:BUY, LIMIT-STOP:SELLが注文されます。
この例だと現在の最新の売買価格をつっこんでるので指値だけど成行っぽい振る舞いになります。本来はbuy_coinpriceは任意の値を入れるべきです。

```ruby
api.sendparentorder data[:size], data[:buy_coinprice], data[:sell_coinprice], data[:trigger_coinprice]
```

これを実行すると実際にbitFlyer Lightningで注文が出てるのが分かります。簡単ですね！

まとめ
-----

とりあえず完全に「触ってみた」レベルの内容ですが、思っていた以上に簡単にAPIを叩くことが出来ました。
今後は取り急ぎWebUIを付けるのと、BOTなんかを使った自動売買を作っていきたいと思います。

ちなみに、この記事読んでるときに見つけた[このUdemyのコンテンツ](https://www.udemy.com/ruby-bitcoin/)を購入するほうがより詳細な情報が高速に集まる気はしますが、テーマを決めた以降に気づいたから仕方ないですね！

それでは、Happy Hacking!


リンク
----

- [Official API Documentation](https://lightning.bitflyer.jp/docs/api)
- [bitFlyerなど仮想通貨の取引所や販売所のAPIで、ゴニョゴニョのリンク集](https://qiita.com/yamazaki/items/ca831434d21db652472f)