Raspberry piを使って仮想通貨取引自動化してみた

# 目的
[bitfinex](https://www.bitfinex.com/)を通じて仮想通貨の取引をやってます。仮想通貨を投資家に貸して利息をもらうmargin funding(lendingとも)という取引があるのですが、投資家に期限より先に返されてしまうとそれに気づいてまた新しく入札するまでそのお金は使われないままになってしまいます。いちいち仕事中に残高をチェックしたりするのは大変なので、自動化しようと思いつきました。サーバーを立てる手段はいろいろありますが、Raspberry Piが家の倉庫にしまわれていたし、電気代もかからなくてちょうどよかったのでこれをつかって自動取引サーバーをつくることにしました。

bitfinexは素晴らしいことに仮想通貨取引をプログラムで行うためのAPIがオープンソースで公開されています。これを使えば誰でも簡単に取引の自動化ができます。やったね。私はruby版のAPIをつかっています。

https://github.com/bitfinexcom/bitfinex-api-rb

為替取引を自動化してうはうはに儲かる話を期待された方、申し訳ございませんm(_ _)m

すでにpoloniex向けにはbitseederというサービスがローンチされています。
https://bitseeder.net/
やろうとしていることはこれと同じです。あちらは手数料を取るビジネスですが、こちらはraspberry piと少々の電気代があれば実現できます。


# Raspberry Piのセットアップ
基本的にはrubyとインターネット環境があればよいので何使っていただいてもよいですが、私はraspbianを使っています。

https://www.raspberrypi.org/downloads/raspbian/

このイメージをmicroSDカードに書き込むだけでRaspberry Piのセットアップができるので簡単ですね。

https://jyn.jp/raspbian-setup/#SSH

このページなどを参考にsshを有効化しておくと以下の作業はsshでできるので楽です。

# ruby2.3.1を入れる
aptをつかってrubyを入れられますが、こちらのバージョンが1系になっていて、bitfinexのAPIが動きませんでした。従って、ruby2系を手動でインストールする必要があります。。

rubyのinstallはrbenvを使うととても便利です。

```
$ sudo apt-get install rbenv
$ rbenv install 2.3.1
$ rbenv global 2.3.1
```

rubyをrbenvでインストールしたものを使うようにするための環境変数も入れておきましょう。(rbenvを使うときのおきまりです。)

```
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
```

bundlerを後で使うのでinstallしておきます。

```
$ gem install bundler
$ rbenv rehash
```

# gitを入れる
gitはaptで入ります。

```
$ sudo apt-get install git
```

# 自動化プログラムをダウンロードする
こちらで自動貸し出しプログラムを公開しています。よかったらどうぞー。
https://github.com/kackyt/auto_lender

```
$ git clone https://github.com/kackyt/auto_lender.git
```

そして必要なgemをインストールします。
```
$ bundle install
```

# 設定ファイルを用意する
プログラムに必要な設定ファイルを用意します。

## bitfinexのAPI keyを取得する
自動化プログラムを動かすにはAPI keyを作成する必要があります。アカウントから『API』をクリックして、Create New Keyをクリックすると必要なpermissionを設定する画面にいきます。Margin FundingのWriteにチェックを入れて「Generate API Key」を押します。生成されたAPI KeyとAPI Secretをなくさないように保存します。

![クリップボード02.png](https://qiita-image-store.s3.amazonaws.com/0/23392/0795b4c5-33f1-117e-487a-736b9eb318ac.png)


## .env
必要な環境変数は以下の通りです。

```
BFX_API_KEY=""
BFX_API_SECRET=""
```

こちらにbitfinexで取得したAPI_KEYとAPI_SECRETを移します。

## config.yml
通貨ごとにどんな取引をさせたいかを設定します。

```
usd:  // 通貨のticker symbol
  rate: 0.0 // 貸し出すレート(per day) 0を指定すると自動でレートを判断する
  period: 3 // 貸し出す期間(day)
btc:
  rate: 0.1
  end: "2017-08-31" // periodでなくendが指定されていた場合、その日までの期間を自動設定する
```

# 実行する
```
$ bundle exec ruby auto_lender.rb
```
エラーが表示されなければ成功です！

# 自動実行させる
自動実行させるにはいろいろな手法がありますが、現状それほどリアルタイム性を求めていないため、crontabで1分ごとに実行させることにしています。daemon化して常駐させて、プロセス監視させたい方は頑張って下さい^^;

```
HOME=/home/pi
PATH=/home/pi/.rbenv/shims:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/bi
n

* * * * * cd $HOME/auto_lender && bundle exec ruby auto_lender.rb
```

# ソースコード解説
## bitfinexに接続
API secret、API keyをつかってbitfinexに接続します。

```ruby
Bitfinex::Client.configure do |conf|
  conf.secret = ENV['BFX_API_SECRET']
  conf.api_key = ENV['BFX_API_KEY']
end

client = Bitfinex::Client.new
```

## 保有通貨数を取得
APIを使って、貸通貨口座(APIでは'deposit'と表記)にある通貨数と貸し出し可能な通貨数を取得して、statusというhash変数に入れます。

```ruby
client.balances.each do |b|
  if b['type'] == 'deposit'
    if status[b['currency']]
      status[b['currency']]['amount'] = b['amount'].to_f
      status[b['currency']]['available'] = b['available'].to_f
    end
  end
end
```

## 貸出判定

```ruby
status.each do |name, stat|
  if stat['available'] > stat['amount'] * 0.01
    amount = stat['available']
```
貸し出しは貸し出し可能数が、総数の1%を超えた場合に行います。また、貸し出しは可能な数をすべて一括で貸し出します。

## レート自動算出ロジック
```ruby
    if stat['rate'] == 0
      lends = client.lends(name, {limit_lends: 3})
      sum = lends.inject([0, 0]) do |memo, l|
        [memo[0] + l['rate'].to_f * l['amount_used'].to_f,
         memo[1] + l['amount_used'].to_f]
      end

      frr = sum[0] / sum[1]

      book = client.funding_book(name, {limit_bids: 0, limit_asks: 5})
      sum = book['asks'].inject([0, 0]) do |memo, b|
        [memo[0] + b['rate'].to_f * b['amount'].to_f,
         memo[1] + b['amount'].to_f]
      end

      bookrate = sum[0] / sum[1]
      rate = (frr + bookrate) / 2
    else
      book = client.funding_book(name, {limit_bids: 0, limit_asks: 1})
      toprate = book['asks'][0]['rate'].to_f
      rate = [stat['rate'] * 365, toprate].max
    end
```

rateが0の場合は自動でrateを算出します。

- 過去3時間のFRR(flash return rate)の加重平均
- 現在の入札金利の上位5つの加重平均

を算出し、これを1対1で平均をとったものをrateとしています。ただ、まだ正直うまい具合のレートになってくれてなかったりするのでチューニングの余地ありです。。過去の約定履歴とかがほしかったのですが、REST APIでは取得できなかったので断念しました。

rateがゼロ以外の場合は指定の金利が使われますが、それより高い金利しか板に並んでいない場合はそちらの金利を使うことにしています。

## 期間の設定

```ruby
    period = 2
    if stat['period']
      period = stat['period']
    end

    if stat['end']
      today = Datetime.now
      enddate = Datetime.strptime(stat['end'], '%F')
      period = enddate - today
    end

    if period > 30
      period = 30
    end
```

endが指定されていた場合はその日付をparseして今日との差分をperiodとして扱います。periodは30が最大となるため、その処理も入れます。

## 発注
APIを使って発注を行います。

```ruby
   client.new_offer(name, amount, rate, period, 'lend')
```

あとは寝てるだけで金利収入が入ってきますｗ

# コスト試算
Raspberry Pi 2 model Bで行うと想定。出力は5.5Wで、24時間稼働した場合、0.132kWh。
東京電力の従量電灯Bで120kWhをこえ300kWhまで(第2段階料金)とすると、１日あたり0.132×26 = 3.432円
１ヶ月あたり、3.432×30 = 102.96円

比較として、awsにt2.nanoでサーバーを立てた場合、
east USリージョンで0.0059ドル/h １日あたり 0.0059×24×110 = 15.576円
東京リージョンで0.008ドル/h １日あたり 0.008×24×110 = 21.12円