akiyoko blog

akiyoko の IT技術系ブログです

「fin-pyもくもく会 #9」に参加してきました

主催

fin-py

会場

株式会社インタートレード
東京都中央区新川一丁目17番21号 茅場町ファーストビル3階

Twitter

twitter.com



 

全体の感想など

前回の初参加からおよそ3ヶ月、3回ぶりの参加となりました。


《過去記事》
akiyoko.hatenablog.jp



前回は、Poloniex という仮想通貨取引所の API を使ってロボアドを作ろう、ということで API を初めて触ってみたのですが、その後の成果は全く奮わず。。

今回はそれを一歩進めて、API を使って仮想通貨の売買のテストをしてみることにしました。




最近は「インベスターZ」を読んで投資のノウハウを勉強中のど素人ですが、fin-py 常連の方々に「おっ!」と思ってもらえるような爪痕を残せるようになるまで頑張ってみたいと考えています。




そして、fin-py 主催者からのつぶやき。

爪痕残せた!(違)


実行環境

  • macOS Sierra 10.12.6
  • Python 3.5.2(Anaconda 4.2.0)


 

やったこと

ccxt というライブラリのコードを読みながら、実際に触ってみました。


まず、Exchange クラスは

def load_markets(self, reload=False):
def fetch_markets(self):
def fetch_tickers(self, symbols=None, params={}):
def fetch_order_status(self, id, market=None):
def fetch_order(self, id, symbol=None, params={}):
def fetch_orders(self, symbol=None, params={}):
def fetch_open_orders(self, symbol=None, params={}):
def fetch_closed_orders(self, symbol=None, params={}):

あたりのメソッドが使えそう。

また、取引所ごとに

def fetch_ticker(self, symbol, params={}):
def fetch_trades(self, symbol, params={}):
def create_order(self, symbol, type, side, amount, price=None, params={}):
def cancel_order(self, id, symbol=None, params={}):
def withdraw(self, currency, amount, address, params={}):

が用意されている。

しかしながら create_order() は、直接使うのではなく、指値注文なら

def create_limit_buy_order(self, symbol, *args):
def create_limit_sell_order(self, symbol, *args):

create_limit_xxx_order 系のメソッドを使うっぽい。たぶん。

def create_market_buy_order(self, symbol, amount, params={}):
def create_market_sell_order(self, symbol, amount, params={}):

create_market_xxx_order 系は成行注文かな。
見たところ、対応している取引所は少なそうな雰囲気ではあるが。

# sell one ฿ for market price and receive $ right now
print(exmo.id, exmo.create_market_sell_order('BTC/USD', 1))

# limit buy BTC/EUR, you pay €2500 and receive ฿1  when the order is closed
print(exmo.id, exmo.create_limit_buy_order('BTC/EUR', 1, 2500.00))

こんな感じで使えと。
https://github.com/ccxt/ccxt#python-1


以下、実際に試してみた。


 

fetch_balance

バランスを取得する。


(使用例)

import ccxt
from pprint import pprint

ex = ccxt.bittrex({
    'apiKey': BITTREX_KEY,
    'secret': BITTREX_SECRET,
})

ret = ex.fetch_balance()
pprint(ret)


(出力例)

{'BTC': {'free': 0.33, 'total': 0.33, 'used': 0.0},
 'LTC': {'free': 0.0, 'total': 2.22, 'used': 2.22},
 'XRP': {'free': 1000.0, 'total': 1000.0, 'used': 0.0},
 ...
 'free': {...,
          'BTC': 0.33,
          'LTC': 0.0,
          'XRP': 1000.0,
          ...},
 'info': [...,
          {'Available': 0.33,
           'Balance': 0.33,
           'CryptoAddress': '1Mxxxxxxxx',
           'Currency': 'BTC',
           'Pending': 0.0},
          {'Available': 1000.0,
           'Balance': 1000.0,
           'CryptoAddress': None,
           'Currency': 'XRP',
           'Pending': 0.0},
          ...],
 'total': {...,
           'BTC': 0.33,
           'LTC': 2.22,
           'XRP': 1000.0,
           ...},
 'used': {...,
           'LTC': 2.22,
           ...}}

ルート直下は、

- info: 全通貨の情報(作成済みのアドレスやバランスなどの量)
- free: ポジションフリーになっている量を全通貨分まとめて表示
- total: 保持している総量を全通貨分まとめて表示
- used: ポジションを取っている量を全通貨分まとめて表示

各通貨の下は、

- free: ポジションフリーになっている量
- total: 総量
- used: ポジションを取っている量

という形で出力されている。



 

fetch_order_book

注文板を取得する。
Bittrex でいうところの「ORDER BOOK」の板。


(使用例)

ret = ex.fetch_order_book('LTC/BTC')
pprint(ret)


(出力例)

{'asks': [[0.00724399, 162.062],
          [0.007244, 68.0758],
          [0.00724498, 12.119],
          ...,
          [0.01287905, 0.27054]],
 'bids': [[0.00721213, 4.87597329],
          [0.0072, 112.42175327],
          [0.007194, 54.9071],
          ...,
          [1e-08, 9874677.64]],
 'datetime': '2017-10-28T06:57:05.000Z',
 'timestamp': 1509173824684}

'asks' は売り出し価格、'bids' は買いたい値段。
成立した金額に近いものから順に(すなわち 'asks' は値段の低い順、'bids' は値段の高い順に)並んでいる。

'asks' および 'bids' のそれぞれのリストは、0番目が BTC換算の価格、1番目がそれぞれの売買ボリューム(アルトコインベースで BTC建てではない)。


 

fetch_trades

他人のものを含めて過去に成立した取引を抽出する。
Bittrex で言うところの「MARKET HISTORY」の板。


(使用例)

ret = ex.fetch_trades('LTC/BTC')
pprint(ret)


(出力例)

[{'amount': 3.63704229,
  'datetime': '2017-11-05T14:21:40.000Z',
  'id': '91373876',
  'info': {'FillType': 'PARTIAL_FILL',
           'Id': 91373876,
           'OrderType': 'SELL',
           'Price': 0.00720401,
           'Quantity': 3.63704229,
           'TimeStamp': '2017-11-05T14:21:40.993',
           'Total': 0.02620128},
  'price': 0.00720401,
  'side': 'sell',
  'symbol': 'LTC/BTC',
  'timestamp': 1509891700000,
  'type': 'limit'},
  ...]


 

create_limit_buy_order

指値で買い注文を出す。


(使用例)

ret = ex.create_limit_buy_order('LTC/BTC', 2, 0.0005)
pprint(ret)

の例だと、
「0.00050000 BTC / 1 LTC」の指値で、2 LTC の注文を出している。
第三引数は、合計金額ではなく、アルトコイン1単位あたりの値段なので要注意。


なお Bittrex では、合計金額が 50K satoshi 以下のゴミ注文を出すと「DUST_TRADE_DISALLOWED_MIN_VALUE_50K_SAT」というエラーが出るようなので、これも要注意。*1


(出力例)

{'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
 'info': {'message': '',
          'result': {'uuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f'},
          'success': True}}


 

fetch_order

自分が出したオーダーを抽出する。


オーダー時の 'id' を指定します。
売買成立後のオーダーを見ることも可能。


約定前のオーダーでは、'status' が 'open' になっています。
(部分的に売れている場合はどうなるのか?については要調査。)


(使用例)

ret = ex.fetch_order('d60c914b-9ba1-4e27-b055-deb7c6549f7f', 'LTC/BTC')
pprint(ret)


(出力例)

{'amount': 2.0,
 'average': None,
 'cost': 0.001,
 'datetime': '2017-11-05T14:36:54.000Z',
 'fee': {'cost': 0.0, 'currency': 'BTC'},
 'filled': 0.0,
 'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
 'info': {'AccountId': None,
          'CancelInitiated': False,
          'Closed': None,
          'CommissionPaid': 0.0,
          'CommissionReserveRemaining': 2.5e-06,
          'CommissionReserved': 2.5e-06,
          'Condition': 'NONE',
          'ConditionTarget': None,
          'Exchange': 'BTC-LTC',
          'ImmediateOrCancel': False,
          'IsConditional': False,
          'IsOpen': True,
          'Limit': 0.0005,
          'Opened': '2017-11-05T14:36:54.987',
          'OrderUuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
          'Price': 0.0,
          'PricePerUnit': None,
          'Quantity': 2.0,
          'QuantityRemaining': 2.0,
          'ReserveRemaining': 0.001,
          'Reserved': 0.001,
          'Sentinel': '4f9809dd-a8d5-4225-a7cf-1feebfcea9f6',
          'Type': 'LIMIT_BUY'},
 'price': 0.0005,
 'remaining': 2.0,
 'side': 'buy',
 'status': 'open',
 'symbol': 'LTC/BTC',
 'timestamp': 1509892614000,
 'type': 'limit'}

売買成立後のオーダーを見ると、'status' が 'closed' になっていました。ちなみに、キャンセル済みの場合でも 'status' は 'closed' でした。


 

fetch_open_orders

自分が出している約定前のオーダーの一覧を抽出する。
「OPEN ORDERS」の板。


(使用例)

ret = ex.fetch_open_orders('LTC/BTC')
pprint(ret)


(出力例)

[{'amount': 2.0,
  'average': None,
  'cost': 0.001,
  'datetime': '2017-11-05T14:36:54.000Z',
  'fee': {'cost': 0.0, 'currency': 'BTC'},
  'filled': 0.0,
  'id': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
  'info': {'CancelInitiated': False,
           'Closed': None,
           'CommissionPaid': 0.0,
           'Condition': 'NONE',
           'ConditionTarget': None,
           'Exchange': 'BTC-LTC',
           'ImmediateOrCancel': False,
           'IsConditional': False,
           'Limit': 0.0005,
           'Opened': '2017-11-05T14:36:54.987',
           'OrderType': 'LIMIT_BUY',
           'OrderUuid': 'd60c914b-9ba1-4e27-b055-deb7c6549f7f',
           'Price': 0.0,
           'PricePerUnit': None,
           'Quantity': 2.0,
           'QuantityRemaining': 2.0,
           'Uuid': None},
  'price': 0.0005,
  'remaining': 2.0,
  'side': 'buy',
  'status': 'open',
  'symbol': 'LTC/BTC',
  'timestamp': 1509892614000,
  'type': 'limit'}]

 

cancel_order

約定前のオーダーをキャンセルする。

オーダー時の戻り値から取得した 'id' の値を第一引数に使います。


(使用例)

ret = ex.cancel_order('d60c914b-9ba1-4e27-b055-deb7c6549f7f', 'LTC/BTC')
pprint(ret)


(出力例)

{'message': '', 'result': None, 'success': True}

なお、すでにキャンセル済みのオーダーに cancel_order() すると、

ccxt.base.errors.InvalidOrder: bittrex cancelOrder() error: {"success":false,"message":"ORDER_NOT_OPEN","result":null}

という例外が発生します。


 

fetch_orders

自分の過去の取引履歴を抽出する。

キャンセルを除いた、過去に売買が成立した取引だけが抽出できるはず。
新しい順に出力されます。

(使用例)

ret = ex.fetch_orders('LTC/BTC')
pprint(ret)

(出力例)

[{'amount': 1.1,
  'average': 0.00689999,
  'cost': 0.00758999,
  'datetime': '2017-11-02T11:09:40.000Z',
  'fee': {'cost': 0.00001897, 'currency': 'BTC'},
  'filled': 1.1,
  'id': 'dc7bfda3-d170-4e30-8461-771d8f690c73',
  'info': {'Closed': '2017-11-02T11:09:41.203',
           'Commission': 0.00001897,
           'Condition': 'NONE',
           'ConditionTarget': None,
           'Exchange': 'BTC-LTC',
           'ImmediateOrCancel': False,
           'IsConditional': False,
           'Limit': 0.0069,
           'OrderType': 'LIMIT_SELL',
           'OrderUuid': 'dc7bfda3-d170-4e30-8461-771d8f690c73',
           'Price': 0.00758999,
           'PricePerUnit': 0.00689999,
           'Quantity': 1.1,
           'QuantityRemaining': 0.0,
           'TimeStamp': '2017-11-02T11:09:40.91'},
  'price': 0.0069,
  'remaining': 0.0,
  'side': 'sell',
  'status': 'closed',
  'symbol': 'LTC/BTC',
  'timestamp': 1509620980000,
  'type': 'limit'},
...]