過去にビットコイン(仮想通貨)のシステムトレードを coincheck API を使って行っていました。
▼システム構築手順はこちらに書きました。
▼成績はこちらに書きました。
ビットコインのチャートは価格がよく動くうえに値幅が大きいのでデイトレに適しており、2017年は仮想通貨市場全体が盛り上がっていたこともあって、良きタイミングで買い注文を入れておけば着実に利益が積み重なっていたんですが、最近ではそんな甘いものではなくなってきました。
上げ相場だけでなく下げ相場にも対応したbotを作ってみたいと、空売りもできる ビットコインFXなるものをやってみることにしました。
今回、使った取引所は bitFlyer(ビットフライヤー)でAPIも提供されています。
ここでは、bitFlyer API、Ruby on Rails、Heroku を使って、ビットコイン(仮想通貨)FXの自動売買を行うシステムトレードプログラムbotを作成する手順をまとめていきます。
目次 [表示]
bitFlyer(ビットフライヤー)に登録
まずは仮想通貨の取引所である bitFlyer(ビットフライヤー)のサイトにアクセスしてアカウント登録します。
▼登録の詳しい手順はこちらに書きました。
bitFlyer(ビットフライヤー)でAPIキーを作成
bitFlyer(ビットフライヤー)のアカウント登録が完了していたら、続いてAPIキーを作成していきます。
まず bitFlyer(ビットフライヤー)にログインして、左メニューにある「bitFlyer Lightning」をクリック。
「bitFlyer Lightning」は、bitFlyer が提供しているビットコインの売買を行うためのプラットフォームです。
「bitFlyer Lightning」の画面が現れたら、左上にあるアイコンをクリック。
するとメニューが開くので、「API」をクリックします。
するとAPIの画面が現れるので、下のほうにある「新しいAPIキーを追加」ボタンをクリック。
するとAPIキーを発行するためのウィンドウが現れます。
ラベルは自分のわかりやすい好きな名前をつけます。APIを何に使うか後からわかるようにしておくと良いでしょう。
権限はAPIを使ってなんの動作を行えるようにするか設定します。今回作るシステムでは入出金や資産は操作する予定がないのでチェックを外し、トレード関連の設定に全てチェックをつけておきました。
最後に一番下の「OK」ボタンをクリックします。
追加したAPIキーが一覧表示され、APIキーとシークレットキーが確認できるようになります。シークレットキーについては「表示」ボタンを押すと表示されます。
それぞれのキーはあとで使うので、とりあえずここでの作業は終わりです。
Rails のアプリケーションを新規作成
ターミナルを開いて Heroku にログイン。
$ heroku login
Rails をインストール。
$ gem install rails --no-ri --no-rdoc
Rails アプリケーションを作成。
$ rails new myapp --database=postgresql
アプリケーションのディレクトリに移動。
$ cd myapp
Gem をインストール。
$ bundle install
ひとまず空のアプリケーションを Heroku へデプロイ
git でアプリケーションを管理させる。
$ git init $ git add . $ git commit -m "init"
Heroku 上でアプリケーションを新しく作成。
$ heroku create
Heroku へデプロイ。
$ git push heroku master
いちおうマイグレーションも実行しておく。
$ heroku run rake db:migrate
ひとまずこれで Heroku に空のアプリケーションがデプロイできました。
bitFlyer(ビットフライヤー)のAPIを使ってビットコインの売買注文を入れてみる
いよいよプログラムでビットコインの売買を行っていきます。
orders タスクを追加。
rails g task orders
すると lib/tasks/orders.rake
というファイルが作成されるので、ここに注文の処理を書いていこうと思います。
買い注文を入れるプログラム
30,000円で0.01BTCの買い注文を入れるソースコードを以下のように書いてみました。
最初に作成したアクセスキーやシークレットキーをこのコード内で使います。
namespace :orders do desc "30,000円で0.01BTCの買い注文を入れる" task :buy => :environment do key = "アクセスキー" secret = "シークレットキー" timestamp = Time.now.to_i.to_s method = "POST" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/sendchildorder" body = '{ "product_code": "FX_BTC_JPY", "child_order_type": "LIMIT", "side": "BUY", "price": 30000, "size": 0.01, "minute_to_expire": 10000, "time_in_force": "GTC" }' text = timestamp + method + uri.request_uri + body sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Post.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, "Content-Type" => "application/json" }); options.body = body https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true response = https.request(options) puts JSON.parse(response.body) end end
成行で0.02BTCの買い注文を入れるソースコードはこちら。body
の中身を変えることで注文方法を変えられます。
namespace :orders do desc "成行で買い注文を入れる" task :buy => :environment do key = "アクセスキー" secret = "シークレットキー" timestamp = Time.now.to_i.to_s method = "POST" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/sendchildorder" body = '{ "product_code": "FX_BTC_JPY", "child_order_type": "MARKET", "side": "BUY", "size": 0.02, "minute_to_expire": 10000, "time_in_force": "GTC" }' text = timestamp + method + uri.request_uri + body sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Post.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, "Content-Type" => "application/json" }); options.body = body https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true response = https.request(options) puts JSON.parse(response.body) end end
売り注文を入れるプログラム
今度は60,000円で0.01BTCの売り注文を入れるソースコードを以下のように書いてみました。
さきほどの買い注文と要領はほとんど同じで、body
の中にある side
を "SELL"
に変えると売り注文になります。
namespace :orders do desc "60,000円で0.01BTCの売り注文を入れる" task :sell => :environment do key = "アクセスキー" secret = "シークレットキー" timestamp = Time.now.to_i.to_s method = "POST" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/sendchildorder" body = '{ "product_code": "FX_BTC_JPY", "child_order_type": "LIMIT", "side": "SELL", "price": 60000, "size": 0.01, "minute_to_expire": 10000, "time_in_force": "GTC" }' text = timestamp + method + uri.request_uri + body sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Post.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, "Content-Type" => "application/json" }); options.body = body https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true response = https.request(options) puts JSON.parse(response.body) end end
注文を確認するプログラム
今度は注文一覧を確認するソースコードを以下のように書いてみました。
namespace :orders do desc "注文一覧を確認する" task :check => :environment do key = "アクセスキー" secret = "シークレットキー" timestamp = Time.now.to_i.to_s method = "GET" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/getchildorders" uri.query = "product_code=FX_BTC_JPY" text = timestamp + method + uri.request_uri sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Get.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, }); https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true response = https.request(options) puts JSON.parse(response.body) end end
実行結果はこのようになります。オーダーIDや注文内容が確認できます。
$ rake orders:check [ { "id": 138398, "child_order_id": "JOR20150707-084555-022523", "product_code": "BTC_JPY", "side": "BUY", "child_order_type": "LIMIT", "price": 30000, "average_price": 30000, "size": 0.1, "child_order_state": "COMPLETED", "expire_date": "2015-07-14T07:25:52", "child_order_date": "2015-07-07T08:45:53", "child_order_acceptance_id": "JRF20150707-084552-031927", "outstanding_size": 0, "cancel_size": 0, "executed_size": 0.1, "total_commission": 0 }, { "id": 138397, "child_order_id": "JOR20150707-084549-022519", "product_code": "BTC_JPY", "side": "SELL", "child_order_type": "LIMIT", "price": 30000, "average_price": 0, "size": 0.1, "child_order_state": "CANCELED", "expire_date": "2015-07-14T07:25:47", "child_order_date": "2015-07-07T08:45:47", "child_order_acceptance_id": "JRF20150707-084547-396699", "outstanding_size": 0, "cancel_size": 0.1, "executed_size": 0, "total_commission": 0 } ]
ちなみに
uri.query = "product_code=FX_BTC_JPY"
のところを
uri.query = "product_code=FX_BTC_JPY&child_order_state=ACTIVE"
のように変えると、オープンな注文のみの一覧を取得できます。
サンプルで作った自動売買システム
以下はサンプルで作った自動売買プログラム。
50,000円で買い注文、60,000円で売り注文を交互に入れるプログラムです。
1時間に1回などの頻度で定期的に実行する想定です。
namespace :orders do desc "実行処理の説明" task :update => :environment do key = "アクセスキー" secret = "シークレットキー" timestamp = Time.now.to_i.to_s # 注文一覧を取得 method = "GET" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/getchildorders" uri.query = "product_code=FX_BTC_JPY&child_order_state=ACTIVE" text = timestamp + method + uri.request_uri sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Get.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, }); https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true response = https.request(options) result = JSON.parse(response.body) # 前の注文が残っている場合は何もせずに終了 if result.count > 0 exit end # 現在のレートを確認 uri = URI.parse("https://api.bitflyer.jp") uri.path = '/v1/ticker' uri.query = 'product_code=FX_BTC_JPY' https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true response = https.get uri.request_uri result = JSON.parse(response.body) last_rate = result['ltp'] if last_rate > 60000 # 現在のレートが60000円を超えたら、50000円で買い注文を入れる method = "POST" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/sendchildorder" body = '{ "product_code": "FX_BTC_JPY", "child_order_type": "LIMIT", "side": "BUY", "price": 50000, "size": 0.01, "minute_to_expire": 10000, "time_in_force": "GTC" }' text = timestamp + method + uri.request_uri + body sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Post.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, "Content-Type" => "application/json" }); options.body = body https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true https.request(options) elsif last_rate < 50000 # 現在のレートが50000円を下回ったら60000円で売り注文を入れる method = "POST" uri = URI.parse("https://api.bitflyer.jp") uri.path = "/v1/me/sendchildorder" body = '{ "product_code": "FX_BTC_JPY", "child_order_type": "LIMIT", "side": "SELL", "price": 60000, "size": 0.01, "minute_to_expire": 10000, "time_in_force": "GTC" }' text = timestamp + method + uri.request_uri + body sign = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text) options = Net::HTTP::Post.new(uri.request_uri, initheader = { "ACCESS-KEY" => key, "ACCESS-TIMESTAMP" => timestamp, "ACCESS-SIGN" => sign, "Content-Type" => "application/json" }); options.body = body https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true https.request(options) end end end
とりあえずAPIを組み合わせてみた例なので、実用で使う場合はもっと複雑なルールを書いていく必要があります。
作成したプログラムを Heroku 上で動かす
作成したプログラムを Heroku にデプロイします。
git push heroku master
次に、ウェブブラウザで Heroku のサイトにログインして、「Heroku Scheduler」アドオンを追加します。
このアドオンを使って、Heroku に反映した自動売買タスクを定期的に実行させることができます。
「Heroku Scheduler」アドオンの設定ページに移動したら、タスクの実行コマンドを入力し、実行間隔を10分ごとに設定して保存します。
Heroku のコマンドで実行されているログを確認できます。
heroku logs -t
まとめ
これで自動売買を行うしくみをひととおり構築することができました。
あとは自分なりの注文条件ルールをプログラムで書いてアレンジしていくだけです。
ここで作成したプログラムは買いと売り注文ひとつずつしか対応していないシンプルなものですが、データベースで注文を管理することでより細かな注文に対応したシステムが構築できると思います。
あとはせっかく Ruby on Rails を使っているので、損益計算も画面で確認できるようにするなど夢が広がりますね!
実際にこのしくみで資産を運用しています
実際にプログラムを使ってビットコインFXの自動売買botを運用し始めたので、また Twitter やブログなどで成績を公開していけたらと思います。
▼Coincheck API を使ってコーディングした例もあります。
▼そのときの運用結果はこちらに書きました。
リアルタイムな売買のようすは Twitter でも公開しているので、よかったらフォローしてくださいな!