class Bitfinex::WSv2

Implements version 2 of the Bitfinex WebSocket API, taking an evented approach. Incoming packets trigger event broadcasts with names relevant to the individual packets. Provides order manipulation methods that support callback blocks, which are called when the relevant confirmation notifications are received

Constants

FLAG_CHECKSUM
FLAG_DEC_S
FLAG_SEQ_ALL
FLAG_TIMESTAMP
FLAG_TIME_S
INFO_MAINTENANCE_END
INFO_MAINTENANCE_START
INFO_SERVER_RESTART

Public Class Methods

new(params = {}) click to toggle source

Creates a new instance of the class

@param [Hash] params @param [string] params.url - connection URL @param [string] params.aff_code - optional affiliate code to be applied to all orders @param [string] params.api_key @param [string] params.api_secret @param [boolean] params.manage_order_books - if true, order books are persisted internally, allowing for automatic checksum verification @param [boolean] params.transform - if true, full models are returned in place of array data @param [boolean] params.seq_audit - enables automatic seq number verification @param [boolean] params.checksum_audit - enables automatic OB checksum verification (requires manage_order_books)

# File lib/ws/ws2.rb, line 63
def initialize (params = {})
  @l = Logger.new(STDOUT)
  @l.progname = 'ws2'

  @url = params[:url] || 'wss://api.bitfinex.com/ws/2'
  @aff_code = params[:aff_code]
  @api_key = params[:api_key]
  @api_secret = params[:api_secret]
  @manage_obs = params[:manage_order_books]
  @transform = !!params[:transform]
  @seq_audit = !!params[:seq_audit]
  @checksum_audit = !!params[:checksum_audit]

  @enabled_flags = 0
  @is_open = false
  @is_authenticated = false
  @channel_map = {}
  @order_books = {}
  @pending_blocks = {}
  @last_pub_seq = nil
  @last_auth_seq = nil
end

Public Instance Methods

auth!(calc = 0, dms = 0) click to toggle source

Authenticates the socket connection

@param [number] calc @param [number] dms - dead man switch, active 4

# File lib/ws/ws2.rb, line 627
def auth! (calc = 0, dms = 0)
  if @is_authenticated
    raise Exception, 'already authenticated'
  end

  auth_nonce = new_nonce
  auth_payload = "AUTH#{auth_nonce}#{auth_nonce}"
  sig = sign(auth_payload)

  @ws.send(JSON.generate({
    :event => 'auth',
    :apiKey => @api_key,
    :authSig => sig,
    :authPayload => auth_payload,
    :authNonce => auth_nonce,
    :dms => dms,
    :calc => calc
  }))
end
cancel_order(order, &cb) click to toggle source

Cancel an order by ID

@param [Hash|Array|Order|number] order - must contain or be ID @param [Block] cb - triggered upon receipt of confirmation notification

# File lib/ws/ws2.rb, line 686
def cancel_order (order, &cb)
  return if !@is_authenticated

  if order.is_a?(Numeric)
    id = order
  elsif order.is_a?(Array)
    id = order[0]
  elsif order.instance_of?(Models::Order)
    id = order.id
  elsif order.kind_of?(Hash)
    id = order[:id] || order['id']
  else
    raise Exception, 'tried to cancel order with invalid ID'
  end

  @ws.send(JSON.generate([0, 'oc', nil, { :id => id }]))

  if !cb.nil?
    @pending_blocks["order-cancel-#{id}"] = cb
  end
end
close!() click to toggle source

Closes the websocket client

# File lib/ws/ws2.rb, line 138
def close!
  @ws.close
end
enable_flag(flag) click to toggle source

Enable an individual flag (see FLAG_* constants)

@param [number] flag

# File lib/ws/ws2.rb, line 581
def enable_flag (flag)
  return unless @is_open

  @ws.send(JSON.generate({
    :event => 'conf',
    :flags => @enabled_flags | flag
  }))
end
enable_ob_checksums(audit = true) click to toggle source

Sets the flag to activate order book checksums. Managed order books are required for automatic checksum audits.

@param [boolean] audit - if true (default), incoming checksums will be compared to local checksums

# File lib/ws/ws2.rb, line 616
def enable_ob_checksums (audit = true)
  @checksum_audit = audit
  enable_flag(FLAG_CHECKSUM)
end
enable_sequencing(audit = true) click to toggle source

Sets the flag to activate sequence numbers on incoming packets

@param [boolean] audit - if true (default), incoming seq numbers will be checked for consistency

# File lib/ws/ws2.rb, line 605
def enable_sequencing (audit = true)
  @seq_audit = audit
  enable_flag(FLAG_SEQ_ALL)
end
is_flag_enabled(flag) click to toggle source

Checks if an individual flag is enabled (see FLAG_* constants)

@param [number] flag @return [boolean] enabled

# File lib/ws/ws2.rb, line 596
def is_flag_enabled (flag)
  (@enabled_flags & flag) == flag
end
open!() click to toggle source

Opens the websocket client inside an eventmachine run block

# File lib/ws/ws2.rb, line 113
def open!
  if @is_open
    raise Exception, 'already open'
  end

  EM.run {
    @ws = Faye::WebSocket::Client.new(@url)

    @ws.on(:open) do |e|
      on_open(e)
    end

    @ws.on(:message) do |e|
      on_message(e)
    end

    @ws.on(:close) do |e|
      on_close(e)
    end
  }
end
request_calc(prefixes) click to toggle source

Requests a calculation to be performed @see docs.bitfinex.com/v2/reference#ws-input-calc

@param [Array] prefixes - i.e. ['margin_base']

# File lib/ws/ws2.rb, line 661
def request_calc (prefixes)
  @ws.send(JSON.generate([0, 'calc', nil, prefixes.map { |p| [p] }]))
end
submit_order(order, &cb) click to toggle source

Submit a new order

@param [Hash|Array|Order] order @param [Block] cb - triggered upon receipt of confirmation notification

# File lib/ws/ws2.rb, line 714
def submit_order (order, &cb)
  return if !@is_authenticated

  if order.kind_of?(Array)
    packet = order
  elsif order.instance_of?(Models::Order)
    packet = order.to_new_order_packet
  elsif order.kind_of?(Hash)
    packet = Models::Order.new(order).to_new_order_packet
  else
    raise Exception, 'tried to submit order of unkown type'
  end

  if !@aff_code.nil?
    unless packet[:meta]
      packet[:meta] = {}
    end

    packet[:meta][:aff_code] = @aff_code
  end

  @ws.send(JSON.generate([0, 'on', nil, packet]))

  if packet.has_key?(:cid) && !cb.nil?
    @pending_blocks["order-new-#{packet[:cid]}"] = cb
  end
end
subscribe(channel, params = {}) click to toggle source

Subscribes to the specified channel; params dictate the channel filter

@param [string] channel - i.e. 'trades', 'candles', etc @param [Hash] params @param [string?] params.symbol @param [string?] params.prec - for order book channels @param [string?] params.len - for order book channels @param [string?] params.key - for candle channels

# File lib/ws/ws2.rb, line 442
def subscribe (channel, params = {})
  @l.info 'subscribing to channel %s [%s]' % [channel, params]
  @ws.send(JSON.generate(params.merge({
    :event => 'subscribe',
    :channel => channel,
  })))
end
subscribe_candles(key) click to toggle source

Subscribes to a candle channel by key

@param [string] key - i.e. trade:1m:tBTCUSD

# File lib/ws/ws2.rb, line 473
def subscribe_candles (key)
  subscribe('candles', { :key => key })
end
subscribe_order_book(sym, prec, len) click to toggle source

Subscribes to an order book channel

@param [string] sym - i.e. tBTCUSD @param [string] prec - i.e. R0, P0, etc @param [string] len - i.e. 25, 100, etc

# File lib/ws/ws2.rb, line 484
def subscribe_order_book (sym, prec, len)
  subscribe('book', {
    :symbol => sym,
    :prec => prec,
    :len => len
  })
end
subscribe_ticker(sym) click to toggle source

Subscribes to a ticker channel by symbol

@param [string] sym - i.e. tBTCUSD

# File lib/ws/ws2.rb, line 455
def subscribe_ticker (sym)
  subscribe('ticker', { :symbol => sym })
end
subscribe_trades(sym) click to toggle source

Subscribes to a trades channel by symbol

@param [string] sym - i.e. tBTCUSD

# File lib/ws/ws2.rb, line 464
def subscribe_trades (sym)
  subscribe('trades', { :symbol => sym })
end
update_order(changes, &cb) click to toggle source

Update an order with a changeset by ID

@param [Hash] changes - must contain ID @param [Block] cb - triggered upon receipt of confirmation notification

# File lib/ws/ws2.rb, line 671
def update_order (changes, &cb)
  id = changes[:id] || changes['id']
  @ws.send(JSON.generate([0, 'ou', nil, changes]))

  if !cb.nil?
    @pending_blocks["order-update-#{id}"] = cb
  end
end