Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

ビットコインが爆上がりした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キーの取得をします。開発者ページ新しいAPIキーを追加を押すと「APIキー」と「API Secret」が生成されます。
こちらを利用することで認証を行えます。APIキー毎に利用できる権限を制御できるので不要な権限はなるべく付けない方がいろいろと便利かと思います。
ここで生成したキーは決して外部に公開しないようにしてください。githubとか要注意。

Rubyで呼び出し部分を作成

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

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をラッピングして板情報や保証金の状態をハッシュで取り扱える形にしました。

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

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

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

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は任意の値を入れるべきです。

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

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

まとめ

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

ちなみに、この記事読んでるときに見つけたこのUdemyのコンテンツを購入するほうがより詳細な情報が高速に集まる気はしますが、テーマを決めた以降に気づいたから仕方ないですね!

それでは、Happy Hacking!

リンク

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away