裁定取引bot R2の実験(2020年2月~7月)

裁定取引bot R2の実験(2020年2月~7月)

はじめに

 ビットコインの裁定取引(アービトラージ)をご存知ですか。ビットコインが安くなっている取引所で買って、高くなっている取引所で売る、良く知られた取引の方法です。

この記事では、フリーで利用できる裁定取引bot(プログラム)を半年くらい運用し、結果を他の取引方法と比べました(2020年2月6日~2020年7月24日)。

結果をすぐに見たい方は、このページの最後の"まとめ"を見てください。
有料部分を購入しなくても、結果は見えるように書きました。有料部分は、毎日の損益データと苦労した点をまとめています。

本ページは仮想通貨の投資を勧めるものではありません(Not financial advice)。

追記 2020年11月に止めてしまいました。

 

裁定取引botの説明(R2 Bitcoin Arbitrager)

取引botはGithubで公開されている"R2 Bitcoin Arbitrager"を使わせてもらいます。この"R2"は、2017~2018年に開発されたものです。

https://qiita.com/bitrinjani/items/3ed756da9baf7d171306
https://github.com/bitrinjani/r2

ネットオークションで"R2"が出品されていますが、開発者の方はもちろん私も関係無いです。
"R2"の説明ページプログラムを見て
「よく判らない、面倒だな」と思った方は手を出さない方が良いと思います。

"R2"のおおまかな動作について説明します。
あらかじめ、2つの取引所にビットコインと現金を同じ分量だけ用意しておきます。
API経由で取引所の板情報をチェックして、一番安い買値と一番高い売値を取得します(スプレッド逆転の判定)。
買値が売値より安い場合、売りと買いの注文を指値で2つの取引所に出します(taker注文)。
注文の約定後にスプレッドの逆転が解消したら、最初の注文と反対の売買を行い利益を確定します。利益は日本円です。
最初の2つの注文が約定しなかった場合は、反対売買を行います。この時はある程度損失が出てしまいます。

対応している取引所は、日本国内の取引所です。

  • bitFlyer
  • Quoine (Liquid)
  • Coincheck
  • bitbank
  • BTCBOX

このプログラムが開発された2017年は、Zaifも有力な取引所でしたが対応されていません。開発者の方に考えがあっての非対応のようです。

https://github.com/bitrinjani/r2/issues/113

 

裁定取引botの準備

インストール

古いノートパソコンにLinuxをインストールしてから"R2"をインストールしました。

  • PC: Inspiron Mini 10(CPU: Atom N270 1.6GHz、Memory: 1GB、Storage: SSD 64GB)
  • OS: Linux(Ubuntu 18.04)
  • Node.js: v11.9.0(v12以降では動作しませんでした)

"R2"は開発から時間が経っているのでAPIエンドポイント等の記述に修正が必要でした。

https://github.com/bitrinjani/r2/pull/152
https://github.com/bitrinjani/r2/issues/149

 

設定ファイルの変更(config.json)

設定ファイルは下のように設定します。

  • 取引所:Coincheck, Liquid (Quoine)
  • 1回の注文量:0.01BTC
  • ビットコインの量:0.1BTC(1/26に購入)
  • 最低限の目標収益:0.03%
  • 利益確定の閾値:80%
  • 動作間隔:1分
  • LINE通知:bot停止時、注文未約定時
  • デモモード:無効

2つの取引所を選んだ理由は、ビットコイン現物の取引手数料が無料だからです。bitFlyerも加えた方が利益が増えるような気がしますが、今回は取引量が少なく手数料が高いままなので断念しました。
また当たり前かもしれませんが、デモモードを無効にしないとbotが取引しません。この設定を忘れて何日か無駄にしてしまいました。

 

運用の結果(2020年2月6日~2020年7月24日)

期間全体の利益は8,886円でした。0.1BTC+現金が元手なので妥当な金額だと思います。
ただしビットコインの量や1回の注文量をあまりにも大きく増やすと取引の機会が減ってしまい、今回の結果よりも利益が低下すると思います。

ここで月末毎の利益をグラフにしてみます。

3月の飛びぬけた利益は、価格の乱高下が原因でしょう。4~7月にかけては徐々に利益が下がっています。国内のビットコイン売買が衰退していると言われているので、この先も利益が下がるかもしれません。

 

他の方法と比べる1(円建て利益)

ここからは"R2"と一般的な取引方法を、円建ての利益で比べます。

  • R2 Bitcoin Arbitrager (R2 Arb.)
  • ドルコスト平均法 (DCA):1日おきに1,008円ずつ買う
  • 1/26に買ってそのまま (HODL)

ビットコインを買う日本円は"R2"と同額にします。また"R2"以外の方法はコインチェックの終値から損益を計算しました。
3つの方法の円建て利益率をグラフにします。

ドルコスト平均法が一番高く利益11%増、他の方法は利益9%増程度でした。調べた期間内では"毎日コツコツ買い増し"が正解だったようです。
なるべく少ない日本円でビットコインを手に入れる為には、ドルコスト平均法が良さそうですね。

蛇足ですが、価格変動を避けるためにビットコインと同量のShortポジションを持つと、維持手数料で利益が吹き飛びます。手数料0.04%の場合0.1BTCを180日維持すると6,700円もかかります(TaotaoZaifGMODMMLiquid)。

 

他の方法と比べる2(BTC数量)

今度はビットコイン数量に注目して比べます。

  • R2 Bitcoin Arbitrager (R2 Arb.)+月末に利益でBTCを買う
  • ドルコスト平均法 (DCA):1日おきに1,008円ずつ買う
  • 1/26に購入した0.1BTCでFunding rate受け取り (Funding)

"Funding"は、かつて日本人が利用できたBitMEXでレバレッジ1倍等でShortすると市場の状況によって手数料が受け取る方法ですね。

元の0.1BTCに対して、"R2"が11%増、他は±1%程度でした。国内レンディングサービスの利息は1年で3%なので、それほど悪く無い結果だと思います(bitbank暗号資産を貸して増やすGMOコイン貸暗号資産)。

裁定取引がメリットが見えてきましたが、ここで裁定取引や裁定取引botのデメリットをまとめておきます。

  • 取引所間の価格に歪みが無い場合は、利益が上げられない
  • 資金の投入量に対して利益が比例しないおそれがある
  • ビットコイン以外に売買に使う現金が必要(他の方法に比べて資金が2倍以上必要)
  • 短い時間に多数の売買が行われ、コインの損益が確定してしまう(計算方法によっては納税申告が手間)
  • コインを取引所に預け放しにしないといけない
  • botが止まる、ビットコインが不足・過剰等の異常状態では手動で対応が必要(けっこう起こりました)

 

まとめ

  • "R2 Bitcoin Arbitrager"を約6ヶ月間、0.1BTCで運用し8,886円の運用益でした
  • ただし、より簡単なドルコスト平均法の方が成績が良かったです
  • "R2 Bitcoin Arbitrager"の利益は日本円で残さず、利益でビットコインを買う方が良いかもしれません

さて今年はDefiが流行しているようです。Defiと言えばETHなので、1月末からETH買って放置した場合の円建て利益率のグラフをご覧ください。

ETH HODLの圧勝でしたw
ここまでお付き合いありがとうございました。

おまけ

R2 Bitcoin Arbitragerセットアップ手順 (Ubuntu 18.04)

## node.js (typescript)

$ sudo apt update

$ sudo apt install -y nodejs npm

$ sudo npm cache clean

$ sudo npm install n -g

$ sudo n v11.9.0

$ sudo ln -sf /usr/local/bin/node /usr/bin/node

$ node -v

$ sudo apt purge -y nodejs npm

## r2

$ git clone https://github.com/bitrinjani/r2.git

$ cd r2-master

$ npm install #<- install前に後述のソース修正が必要

 

R2 Bitcoin Arbitragerソース修正例

r2-master/src/Bitflyer/BrokerApi.ts(20行)

修正前:  private readonly baseUrl = 'https://api.bitflyer.jp';

修正後:  private readonly baseUrl = 'https://api.bitflyer.com';

r2-master/src/Quoine/BrokerApi.ts(19行)

修正前:  private readonly baseUrl = 'https://api.quoine.com';

修正後:  private readonly baseUrl = 'https://api.liquid.com';

r2-master/src/Quoine/types.ts(82~83行)

修正前:

  @cast trailing_stop_type: boolean;  @cast trailing_stop_value: boolean;

修正後:

  @cast trailing_stop_type: any;  @cast trailing_stop_value: any;

 

R2 Bitcoin Arbitragerトラブル例

  • "ERROR HTTP request failed. Response from https://api.liquid.com/orders/. Status Code: 422 (Unprocessable Entity) Content: {"message":"Please go to our Trading site (https://app.liquid.com) to review Terms, Conditions and Trading Rules before continuing."}
    Liquid (Quoine)の交付書面改正に未同意の場合のエラー。Liquidのサイトで交付書面改正に同意する
  • Error: EFBIG: file too large, write
    r2-master/logs/debug.logが2GBに達したエラー。debug.logを削除するか、/dev/nullへのシンボリックリンクとする
  • INFO Net exposure is larger than max net exposure.
    手持ちのコインが"maxNetExposure"を超えたメッセージ。これになると発注されない。"maxNetExposure"を十分大きくする
  • ERROR request to https://api.liquid.com/accounts/balance failed, reason: getaddrinfo EAI_AGAIN api.liquid.com:443
    プログラムの動作間隔が短すぎるエラー。"iterationInterval"を大きな値に変更する
  • WARN [PairTrader] HTTP request failed. Response from https://api.liquid.com/orders/987654321. Status Code: 401 (Unauthorized) Content: {"message":"Your nonce 123456789 is smaller than or equal last nonce 123456789"}
    CoincheckのAPIを他のプログラムでも使用した場合のエラー。"R2"専用のAPIを用意する
  • INFO [SingleLegHandler] >>The order was not filled within TTL 10000 ms. Cancelling the order.
    取引に失敗した場合のメッセージ。ビットコイン数量が大きく増減している場合は、速やかに手動売買で修正する

 

R2 Bitcoin Arbitrager設定ファイル例

{
  "language": "en",
  "demoMode": true,
  "_demoMode": false,
  "symbol": "BTC/JPY",
  "priceMergeSize": 100,
  "maxSize": 0.01,
  "minSize": 0.01,
  "minTargetProfitPercent": 0.03,
  "exitNetProfitRatio": 80,
  "maxTargetVolumePercent": 50.0,
  "iterationInterval": 60000,
  "positionRefreshInterval": 5000,
  "sleepAfterSend": 5000,
  "maxNetExposure": 0.2,
  "maxRetryCount": 10,
  "orderStatusCheckInterval": 3000,
  "stabilityTracker": {
    "threshold": 9,
    "recoveryInterval": 300000
  },
  "onSingleLeg": {
    "action": "Reverse",
    "actionOnExit": "Reverse",
    "options": {
      "limitMovePercent": 0.2,
      "ttl": 10000
    }
  },
  "analytics": {
    "enabled": false,
    "plugin": "SimpleSpreadStatHandler.js",
    "initialHistory": { "minutes": 30 }
  },
  "webGateway": {
    "enabled": false,
    "host": "127.0.0.1",
    "openBrowser": true
  },
  "brokers": [
    {
      "broker": "Coincheck",
      "enabled": true,
      "key": "xxxxxx",
      "secret": "xxxxxx",
      "maxLongPosition": 0.1,
      "maxShortPosition": 0,
      "cashMarginType": "Cash",
      "commissionPercent": 0
    },
    {
      "broker": "Bitflyer",
      "enabled": false,
      "key": "xxxxxx",
      "secret": "xxxxxx",
      "maxLongPosition": 0.1,
      "maxShortPosition": 0,
      "cashMarginType": "Cash",
      "commissionPercent": 0.15,
      "noTradePeriods": [["03:58", "04:15"], ["11:58", "12:08"]]
    },
    {
      "broker": "Quoine",
      "enabled": true,
      "key": "xxxxxx",
      "secret": "xxxxxx",
      "maxLongPosition": 0.1,
      "maxShortPosition": 0,
      "cashMarginType": "Cash",
      "leverageLevel": 10,
      "commissionPercent": 0,
      "noTradePeriods": [["06:53", "07:08"]]
    },
    {
      "broker": "Bitbankcc",
      "npmPath": "@bitr/bitbankcc",
      "enabled": false,
      "key": "xxxxxx",
      "secret": "xxxxxxx",
      "maxLongPosition": 0.03,
      "maxShortPosition": 0,
      "cashMarginType": "Cash",
      "commissionPercent": 0.12
    },
    {
      "broker": "Btcbox",
      "npmPath": "@bitr/btcbox",
      "enabled": false,
      "key": "xxxxxx",
      "secret": "xxxxxxx",
      "maxLongPosition": 0.03,
      "maxShortPosition": 0,
      "cashMarginType": "Cash",
      "commissionPercent": 0.05
    }
  ],
  "logging": {
    "slack": {
      "enabled": false,
      "url": "https://hooks.slack.com/services/xxxxxx",
      "channel": "#ch1",
      "username": "abc",
      "keywords": ["error", "profit"]
    },
    "line": {
      "enabled": true,
      "token": "xxxxxxx",
      "keywords": ["within", "Stopped"]
    }
  }
}

ありがとうございました。とりあえずパソコンが壊れるまで、"R2"は動かそうと思ってます。


有料部分は、毎日の損益データ等です。

Remaining : 63 characters / 0 images
100

Sign up / Continue after login

Campaign

Related stories

Writer

The Shiba Inu (柴犬) is a most popular dog in Japan.

Share

Popular stories

RaspberryPi小ネタ(OS起動でLED点滅、シャットダウンスイッチ、Lチカ)備忘録

5013

RaspberryPiでダッシュボードを作る(Grafana InfluxDB)備忘録

2377

太陽電池でビットコインをマイニング3 ~RaspberryPi採用で効率アップ~

1076