ccxtを使って裁定取引botを作ってみたらなぜか虚しくなった件

数か月前から裁定取引botを作って運用しているのですが、今は各取引所のAPIごとのライブラリを利用しています。

bot製作者なら分かると思いますが、取引所ごとにAPIの仕様ってけっこう違っているので、複数のライブラリを使うのってけっこう大変です。

ccxtというライブラリが複数の取引所に対応しているらしく、さっそく使ってみたいと思います。

公式ページは以下
https://github.com/ccxt/ccxt

ccxtはJavascriptとPHPも対応しているとのことですが、この記事ではPythonを利用してます。

まずはインストール

```
pip install ccxt
```

問題なくインストールできました。

とりあえず取引所一覧を取得してみます。

```ccxt_test.py
import ccxt
print(ccxt.exchanges) # print a list of all available exchange classes
```

```
['_1broker', '_1btcxe', 'acx', 'allcoin', 'anxpro', 'bibox', 'binance', 'bit2c', 'bitbay', 'bitcoincoid', 'bitfinex', 'bitfinex2', 'bitflyer', 'bithumb', 'bitlish', 'bitmarket', 'bitmex', 'bitso', 'bitstamp', 'bitstamp1', 'bittrex', 'bitz', 'bl3p', 'bleutrade', 'braziliex', 'btcbox', 'btcchina', 'btcexchange', 'btcmarkets', 'btctradeua', 'btcturk', 'btcx', 'bxinth', 'ccex', 'cex', 'chbtc', 'chilebit', 'cobinhood', 'coincheck', 'coinexchange', 'coinfloor', 'coingi', 'coinmarketcap', 'coinmate', 'coinsecure', 'coinspot', 'cryptopia', 'dsx', 'exmo', 'flowbtc', 'foxbit', 'fybse', 'fybsg', 'gatecoin', 'gateio', 'gdax', 'gemini', 'getbtc', 'hitbtc', 'hitbtc2', 'huobi', 'huobicny', 'huobipro', 'independentreserve', 'itbit', 'jubi', 'kraken', 'kucoin', 'kuna', 'lakebtc', 'liqui', 'livecoin', 'luno', 'lykke', 'mercado', 'mixcoins', 'nova', 'okcoincny', 'okcoinusd', 'okex', 'paymium', 'poloniex', 'qryptos', 'quadrigacx', 'quoinex', 'southxchange', 'surbitcoin', 'therock', 'tidex', 'urdubit', 'vaultoro', 'vbtc', 'virwox', 'wex', 'xbtce', 'yobit', 'yunbi', 'zaif', 'zb']
```

わずか2行で取得。簡単でいいですね。
日本の取引所であるbitflyer, zaif, coincheck, quoinexなどもあって良い感じですね！

試しにbitflyerのaskとbitを取得してみます。

```ccxt_test.py
import ccxt
bitflyer = ccxt.bitflyer()
orderbook = bitflyer.fetch_order_book ('BTC/JPY')
bid = orderbook['bids'][0][0] if len (orderbook['bids']) > 0 else None
ask = orderbook['asks'][0][0] if len (orderbook['asks']) > 0 else None
spread = (ask - bid) if (bid and ask) else None
print (bitflyer.id, 'market price', { 'bid': bid, 'ask': ask, 'spread': spread })
```

```
bitflyer market price {'bid': 1148500.0, 'ask': 1148993.0, 'spread': 493.0}
```

たった7行で取れてしまいました。すごい。
続いて他の取引所分もまとめて取得してみます。

```ccxt_test.py
import ccxt

exchange_list = ['bitflyer', 'coincheck', 'quoinex', 'zaif']

for exchange in exchange_list:
    exchange = eval('ccxt.' + exchange + '()')
    orderbook = exchange.fetch_order_book ('BTC/JPY')
    bid = orderbook['bids'][0][0] if len (orderbook['bids']) > 0 else None
    ask = orderbook['asks'][0][0] if len (orderbook['asks']) > 0 else None
    spread = (ask - bid) if (bid and ask) else None
    print (exchange.id, 'market price', { 'bid': bid, 'ask': ask, 'spread': spread })
```

```
bitflyer market price {'bid': 1146231.0, 'ask': 1146235.0, 'spread': 4.0}
coincheck market price {'bid': 1107165.0, 'ask': 1108202.0, 'spread': 1037.0}
quoinex market price {'bid': 1145830.15, 'ask': 1146314.03, 'spread': 483.8800000001211}
zaif market price {'bid': 1145380.0, 'ask': 1145465.0, 'spread': 85.0}
```

なにこれすごい。。。
今まで取引所ごとのライブラリ使ってコツコツ書いていたあの時間は何だったのだろうと思うともはや虚しさを感じますね。

ではaskとbitが取れたので今後はそれを比較して裁定取引可能かどうかの判断と最適な取引所の判定をしてみます。

```ccxt_test.py
import ccxt

exchange_list = ['bitflyer', 'coincheck', 'quoinex', 'zaif']
ask_exchange = ''
ask_price = 99999999
bid_exchange = ''
bid_price = 0

for exchange_id in exchange_list:
    exchange = eval('ccxt.' + exchange_id + '()')
    orderbook = exchange.fetch_order_book ('BTC/JPY')
    bid = orderbook['bids'][0][0] if len (orderbook['bids']) > 0 else None
    ask = orderbook['asks'][0][0] if len (orderbook['asks']) > 0 else None
    if ask < ask_price:
        ask_exchange = exchange_id
        ask_price = ask
    if bid > bid_price:
        bid_exchange = exchange_id
        bid_price = bid


print (ask_exchange, 'で', ask_price, '円で買って')
print (bid_exchange, 'で', bid_price, '円で売れば')
print (bid_price - ask_price, '円の利益！')
```

```
coincheck で 1106620.0 円で買って
quoinex で 1142330.0 円で売れば
35710.0 円の利益！
```

これもすごく簡単にできて感動です！

ではいよいよ実際に裁定取引をしてみます。
ただしcoincheckは現在送金ができないので今回は除外しておきます。

```ccxt_test.py
import ccxt

exchanges = {
    "bitflyer": {
        "apiKey": "",
        "secret": ""
    },
    "quoinex": {
        "apiKey": "",
        "secret": ""
    },
    "zaif": {
        "apiKey": "",
        "secret": ""
    }
}

amount = 0.001
ask_exchange = ''
ask_price = 99999999
bid_exchange = ''
bid_price = 0

# 各取引所のaskとbidを取得
for exchange_id in exchanges:
    exchange = eval('ccxt.' + exchange_id + '()')

    orderbook = exchange.fetch_order_book('BTC/JPY')
    bid = orderbook['bids'][0][0] if len(orderbook['bids']) > 0 else None
    ask = orderbook['asks'][0][0] if len(orderbook['asks']) > 0 else None
    if ask < ask_price:
        ask_exchange = exchange_id
        ask_price = ask
    if bid > bid_price:
        bid_exchange = exchange_id
        bid_price = bid

# 裁定取引を行う
#買い
ask_price = int(ask_price/5)*5
exchange = eval('ccxt.' + ask_exchange + '()')
exchange.apiKey = exchanges[ask_exchange]["apiKey"]
exchange.secret = exchanges[ask_exchange]["secret"]
exchange.create_limit_buy_order ('BTC/JPY', amount, ask_price)

#売り
bid_price = int(bid_price*5)/5
exchange = eval('ccxt.' + bid_exchange + '()')
exchange.apiKey = exchanges[bid_exchange]["apiKey"]
exchange.secret = exchanges[bid_exchange]["secret"]
exchange.create_limit_sell_order ('BTC/JPY', amount, bid_price)

print(ask_exchange, 'で', ask_price, '円で', amount, '買って')
print(bid_exchange, 'で', bid_price, '円で', amount, '売ったので')
print((bid_price - ask_price)*amount, '円の利益！')
```

```
zaif で 1147995.0 円で 0.001 買って
quoinex で 1149238.4 円で 0.001 売ったので
1.2433999999999068 円の利益！
```

簡単に裁定取引ができてしまいました！
今はあまり取引所間の差異がないようで1円しか稼げませんでしたがｗ

ちなみに以下の部分はzaifだと ~~10円単位~~ （2018/03/02追記：10円単位ではなく5円単位でした。@tk1024 さんありがとうございます。）にしないとエラーになるのでその対応となります。

```
int(ask_price/5)*5
```

あと本当は成行注文がしたかったのですが、zaifは指値注文しか対応していないようなので指値注文にしました。
もし成行注文にする場合は以下のように書けばOKです。

```
exchange.create_market_sell_order ('BTC/JPY', 0.001)
```

この他にもccxtではポジション照会や注文照会なども簡単にできるようです。
というかAPIでできることは多分全部できます。

簡単すぎて逆に虚しくなってしまいましたが、今後はccxtを利用していこうと思います。
ほんとに今まで各取引所ごとのライブラリを使っていた時間はなんだったのだろう。。

みなさんもぜひ利用してみてください。