class Trader::BitfinexBackend

Constants

BASE_CUR
CUR_EQUIV
MAIN_MARKET
QUOTE_CUR

Attributes

session[R]

Public Class Methods

new() click to toggle source
Calls superclass method Trader::BaseBackend::new
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 41
def initialize
  super :bitfinex
end

Public Instance Methods

cancel_order(_session, _id) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 108
def cancel_order(_session, _id)
  order = wrap_order auth_post(_session, 'order/cancel', { order_id: _id })
  order = fetch_order(_session, _id) while order.status == AccountOrder::OPEN
  order
end
create_order(_session, _pair, _volume, _price, _type) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 85
def create_order(_session, _pair, _volume, _price, _type)
  params = {
    exchange: "bitfinex",
    symbol: "BTCUSD",
    side: _type == Order::BID ? 'buy' : 'sell',
    amount: _volume.to_s('F')
  }

  if _price.nil?
    params[:price] = _type == Order::BID ? '1.0' : '1000000.0' # some safe values just in case
    params[:type] = 'exchange market'
  else
    params[:price] = _price.to_s('F')
    params[:type] = 'exchange limit'
  end

  wrap_order auth_post(_session, 'order/new', params)
end
fetch_order(_session, _id) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 104
def fetch_order(_session, _id)
  wrap_order auth_post(_session, 'order/status', { order_id: _id })
end
fill_book(_book) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 49
def fill_book(_book)
  # TODO: consider book pair

  _book.prepare Time.now

  ob = public_get('book/BTCUSD')
  ob['bids'].each { |o| _book.add_bid(o['price'], o['amount']) }
  ob['asks'].each { |o| _book.add_ask(o['price'], o['amount']) }

  tx = public_get('trades/BTCUSD', { timestamp: one_hour_ago })
  tx.each do |t|
    _book.add_transaction t['price'], t['amount'], Time.at(t['timestamp'])
  end
end
get_available_markets() click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 45
def get_available_markets
  [MAIN_MARKET]
end
get_balance(_session, _currency) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 69
def get_balance(_session, _currency)
  raw = auth_post(_session, 'balances')
  wrap_balance raw, _currency
end
get_orders(_session, _pair) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 79
def get_orders(_session, _pair)
  raw = auth_post(_session, 'orders')
  raw = raw.select { |o| o['type'].include? 'limit' }
  raw.map { |o| wrap_order o }
end
get_session(_cred) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 64
def get_session(_cred)
  raise AssertError, 'missing credentials' if !_cred.key?(:api_key) || !_cred.key?(:secret)
  _cred
end
listen_transactions(_pair, &_block) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 114
def listen_transactions(_pair, &_block)
  WebSocket::Client::Simple.connect('wss://api2.bitfinex.com:3000/ws') do |ws|
    ws.on :open do |event|
      ws.send(JSON.dump({ event: 'subscribe', channel: 'trades', pair: 'BTCUSD' }))
    end

    ws.on :message do |event|
      message = JSON.load(event.data)
      next if message.is_a? Hash

      if message[1] == 'te'
        _block.call(
          pair: _pair,
          ts: Time.at(message[3]),
          direction: message[5] < 0 ? Transaction::SELL : Transaction::BUY,
          price: message[4],
          volume: message[5].abs
        )
      end
    end
  end
end
withdraw_to_endpoint(_session, _currency, _amount, _endpoint) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 74
def withdraw_to_endpoint(_session, _currency, _amount, _endpoint)
  not_supported "usd withdrawals" if _currency == QUOTE_CUR
  execute_btc_withdraw(_session, _amount, _endpoint)
end

Private Instance Methods

auth_post(_creds, _url, _data = {}) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 146
def auth_post(_creds, _url, _data = {})
  payload = build_payload("/v1/#{_url}", _data)
  headers = {
    'Content-Type' => 'application/json',
    'Accept' => 'application/json',
    'X-BFX-PAYLOAD' => payload,
    'X-BFX-SIGNATURE' => sign_payload(_creds, payload),
    'X-BFX-APIKEY' => _creds[:api_key],
  }

  resp = RestClient.post "https://api.bitfinex.com/v1/#{_url}/", nil, headers
  JSON.parse resp
end
build_payload(_url, _params = {}) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 160
def build_payload(_url, _params = {})
  payload = {}
  payload['nonce'] = (Time.now.to_f * 10_000).to_i.to_s
  payload['request'] = _url
  payload.merge!(_params) if _params
  Base64.strict_encode64(payload.to_json)
end
execute_btc_withdraw(_session, _amount, _endpoint) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 186
def execute_btc_withdraw(_session, _amount, _endpoint)
  case _endpoint
  when BitcoinAddress
    auth_post(_session, 'withdraw', {
      withdraw_type: 'bitcoin',
      walletselected: 'exchange',
      amount: _amount.to_s('F'),
      address: _endpoint.address
    })
  else
    not_supported "endpoint not supported"
  end
end
one_hour_ago() click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 172
def one_hour_ago
  Time.now.to_i - 3600
end
process_withdraw(_raw) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 200
def process_withdraw(_raw)
  error _raw['message'] if _raw['status'] == 'error'
end
public_get(_url, _query = {}) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 141
def public_get(_url, _query = {})
  resp = RestClient.get "https://api.bitfinex.com/v1/#{_url}/", params: _query
  JSON.parse resp
end
sign_payload(_creds, _payload) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 168
def sign_payload(_creds, _payload)
  OpenSSL::HMAC.hexdigest('sha384', _creds[:secret], _payload)
end
wrap_balance(_raw, _currency) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 176
def wrap_balance(_raw, _currency)
  _raw = _raw.find { |b| b["type"] == "exchange" && CUR_EQUIV[b["currency"]] == _currency }
  _raw = { "amount"=> "0.0", "available" => "0.0" } if _raw.nil?
  BalanceAdaptor.new _raw
end
wrap_order(_raw) click to toggle source
# File lib/trade-o-matic/adapters/bitfinex_backend.rb, line 182
def wrap_order(_raw)
  OrderAdaptor.new _raw
end