class Deribit::WS

Constants

AVAILABLE_EVENTS

Attributes

handler[R]
ids_stack[R]
response[R]
socket[R]
subscribed_instruments[R]
test_server[R]

Public Class Methods

new(key, secret, handler: Handler, test_server: nil) click to toggle source
# File lib/deribit/ws.rb, line 8
def initialize(key, secret, handler: Handler, test_server: nil)
  @test_server = test_server || ENV["DERIBIT_TEST_SERVER"]
  @request     = Request.new(key, secret, test_server: test_server)
  @socket      = connect
  @handler     = handler.instance_of?(Class) ? handler.new : handler
  @ids_stack  = []

  # the structure of subscribed_instruments: {'event_name' => ['instrument1', 'instrument2']]}
  @subscribed_instruments = {}

  start_handle
end

Public Instance Methods

account() click to toggle source
# File lib/deribit/ws.rb, line 157
def account
  send(path: '/api/v1/private/account')
end
add_subscribed_instruments(instruments: , events: ) click to toggle source
# File lib/deribit/ws.rb, line 21
def add_subscribed_instruments(instruments: , events: )
  instruments = [instruments] unless instruments.is_a?(Array)

  events.each do |event|
    _event = event.to_sym
    @subscribed_instruments[_event] = if sub_instr = @subscribed_instruments[_event]
                                        (sub_instr + instruments).uniq
                                      else
                                        instruments.uniq
                                      end
  end
end
buy(instrument, quantity, price, type: "limit", stopPx: nil, execInst: "mark_price", post_only: nil, label: nil, max_show: nil, adv: nil) click to toggle source

| Name | Type | Decription | |————–|————|———————————————————————————–| | `instrument` | `string` | Required, instrument name | | `quantity` | `integer` | Required, quantity, in contracts ($10 per contract for futures, ฿1 — for options) | | `price` | `float` | Required, USD for futures, BTC for options | | `type` | `string` | Required, “limit”, “market” or for futures only: “stop_limit” | | `stopPx` | `string` | Required, needed for stop_limit order, defines stop price | | `post_only` | `boolean` | Optional, if true then the order will be POST ONLY | | `label` | `string` | Optional, user defined maximum 32-char label for the order | | `max_show` | `string` | Optional, optional parameter, if “0” then the order will be hidden | | `adv` | `string` | Optional, can be “implv”, “usd”, or absent (advanced order type) |

# File lib/deribit/ws.rb, line 116
def buy(instrument, quantity, price, type: "limit", stopPx: nil, execInst: "mark_price", post_only: nil, label: nil, max_show: nil, adv: nil)
  params = {
      instrument: instrument,
      quantity:   quantity
  }
  params[:price] = price if price

  %i(type stopPx post_only label max_show adv execInst).each do |var|
    variable = eval(var.to_s)
    params[var] = variable if variable
  end

  send(path: '/api/v1/private/buy', arguments: params)
end
cancel(order_id) click to toggle source
# File lib/deribit/ws.rb, line 182
def cancel(order_id)
  params = {
    "orderId": order_id
  }

  send(path: '/api/v1/private/cancel', arguments: params)
end
cancel_all(type = "all") click to toggle source
# File lib/deribit/ws.rb, line 190
def cancel_all(type = "all")
  params = {
    "type": type
  }

  send(path: '/api/v1/private/cancelall', arguments: params)
end
close() click to toggle source
# File lib/deribit/ws.rb, line 56
def close
  @socket.close
end
connect() click to toggle source
# File lib/deribit/ws.rb, line 34
def connect
  url = test_server ? WS_TEST_URL : WS_SERVER_URL
  puts "Connecting to #{url}"
  WebSocket::Client::Simple.connect(url)
end
currencies() click to toggle source
# File lib/deribit/ws.rb, line 165
def currencies
  send(path: '/api/v1/public/getcurrencies')
end
handle_notifications(notifications) click to toggle source
# File lib/deribit/ws.rb, line 206
def handle_notifications(notifications)
  return if notifications.empty?
  notification, *tail = notifications
  handler.send(notification[:message], notification[:result])

  handle_notifications(tail)
end
instruments(expired: false) click to toggle source
# File lib/deribit/ws.rb, line 161
def instruments(expired: false)
  send(path: '/api/v1/public/getinstruments', arguments: {expired: expired})
end
openorders(instrument: "BTC-PERPETUAL", order_id: nil, type: nil) click to toggle source
# File lib/deribit/ws.rb, line 173
def openorders(instrument: "BTC-PERPETUAL", order_id: nil, type: nil)
  params = {}
  params[:instrument] = instrument if instrument
  params[:orderId]    = order_id if order_id
  params[:type]       = type if type

  send(path: '/api/v1/private/getopenorders', arguments: params)
end
ping() click to toggle source
# File lib/deribit/ws.rb, line 60
def ping
  message = {action: "/api/v1/public/ping"}
  @socket.send(message.to_json)
end
reconnect!() click to toggle source
# File lib/deribit/ws.rb, line 40
def reconnect!
  @socket = connect
  start_handle
  sleep 3
  resubscribe!
end
resubscribe!() click to toggle source
# File lib/deribit/ws.rb, line 47
def resubscribe!
  if subscribed_instruments.any?
    subscribed_instruments.each do |event, instruments|
      p "Reconnecting to event: #{event} at instrument: #{instruments}"
      subscribe(instruments, events: event.to_s)
    end
  end
end
sell(instrument, quantity, price, type: "limit", stopPx: nil, execInst: "mark_price", post_only: nil, label: nil, max_show: nil, adv: nil) click to toggle source

| Name | Type | Decription | |————–|————|———————————————————————————–| | `instrument` | `string` | Required, instrument name | | `quantity` | `integer` | Required, quantity, in contracts ($10 per contract for futures, ฿1 — for options) | | `price` | `float` | Required, USD for futures, BTC for options | | `post_only` | `boolean` | Optional, if true then the order will be POST ONLY | | `label` | `string` | Optional, user defined maximum 32-char label for the order | | `max_show` | `string` | Optional, optional parameter, if “0” then the order will be hidden | | `adv` | `string` | Optional, can be “implv”, “usd”, or absent (advanced order type) |

# File lib/deribit/ws.rb, line 142
def sell(instrument, quantity, price, type: "limit", stopPx: nil, execInst: "mark_price", post_only: nil, label: nil, max_show: nil, adv: nil)
  params = {
      instrument: instrument,
      quantity:   quantity
  }
  params[:price] = price if price

  %i(type stopPx post_only label max_show adv execInst).each do |var|
    variable = eval(var.to_s)
    params[var] = variable if variable
  end

  send(path: '/api/v1/private/sell', arguments: params)
end
set_heartbeat(interval = "60") click to toggle source
# File lib/deribit/ws.rb, line 198
def set_heartbeat(interval = "60")
  params = {
    "interval": interval.to_s
  }

  send(path: '/api/v1/public/setheartbeat', arguments: params)
end
subscribe(instruments = ['BTC-PERPETUAL'] , events: ["user_order"], arguments: {}) click to toggle source

events to be reported, possible events: “order_book” – order book change “trade” – trade notification “announcements” – announcements (list of new announcements titles is send) “user_order” – change of user orders (openning, cancelling, filling) “my_trade” – filtered trade notification, only trades of the subscribed user are reported with trade direction “buy”/“sell” from the subscribed user point of view (“I sell …”, “I buy …”), see below. Note, for “index” - events are ignored and can be []

# File lib/deribit/ws.rb, line 79
def subscribe(instruments = ['BTC-PERPETUAL'] , events: ["user_order"], arguments: {})
  instruments = [instruments]  unless instruments.is_a?(Array)
  events = [events]  unless events.is_a?(Array)

  raise "Events must include only #{AVAILABLE_EVENTS.join(", ")} actions" if events.map{|e| AVAILABLE_EVENTS.include?(e.to_sym)}.index(false) or events.empty?
  raise "instruments are required" if instruments.empty?

  arguments = arguments.merge(instrument: instruments, event: events)
  send(path: '/api/v1/private/subscribe', arguments: arguments)
end
summary(instrument = 'BTC-PERPETUAL') click to toggle source
# File lib/deribit/ws.rb, line 169
def summary(instrument = 'BTC-PERPETUAL')
  send(path: '/api/v1/public/getsummary', arguments: { instrument: instrument })
end
test() click to toggle source
# File lib/deribit/ws.rb, line 65
def test
  message = {action: "/api/v1/public/test"}
  @socket.send(message.to_json)
end
unsubscribe(instruments=[]) click to toggle source

unsubscribe for all notifications if instruments is empty

# File lib/deribit/ws.rb, line 91
def unsubscribe(instruments=[])
  instruments = [instruments] unless instruments.is_a?(Array)
  send(path: '/api/v1/private/unsubscribe')
  sleep(0.2)
  if instruments.any?
    @subscribed_instruments.each do |event, _instruments|
      @subscribed_instruments[event] = _instruments - instruments
      subscribe(@subscribed_instruments[event], events: [event])
      sleep(0.2)
    end
  end
end

Private Instance Methods

pop_id(id) click to toggle source
# File lib/deribit/ws.rb, line 282
def pop_id(id)
  @ids_stack.delete(id)
end
put_id(id, action) click to toggle source
# File lib/deribit/ws.rb, line 278
def put_id(id, action)
  @ids_stack << {id => action}
end
send(path: , arguments: {}) click to toggle source
# File lib/deribit/ws.rb, line 263
def send(path: , arguments: {})
  return unless path
  params = {action: path, arguments: arguments}
  sig = @request.generate_signature(path, arguments)
  params[:sig] = sig
  params[:id] = Time.now.to_i

  action = path[/\/api.*\/([^\/]+)$/, 1]
  put_id(params[:id], [action, params])

  p params
  @socket.send(params.to_json)
end
start_handle() click to toggle source
# File lib/deribit/ws.rb, line 216
def start_handle
  instance = self
  @socket.on :message do |msg|
    # puts "msg = #{msg.inspect}"
    begin
      if msg.type == :text
        json = JSON.parse(msg.data, symbolize_names: true)
        puts "Subscribed!" if json[:message] == "subscribed"
        # puts "Got json: #{json}"

        if json[:message] == "test_request"
          # puts "Got test request: #{json.inspect}" # DEBUG
          instance.test
        elsif json[:id] and stack_id = instance.ids_stack.find{|i| i[json[:id]]}
          method  = stack_id[json[:id]][0]
          #pass the method to handler
          params = instance.ids_stack.delete(stack_id)

          #save subscribed_instruments for resubscribe in unsubscribe action
          if method == 'subscribe'
            params = params[json[:id]][1][:arguments]
            instance.add_subscribed_instruments(instruments: params[:instrument], events: params[:event])
          end

          instance.handler.send(method, json)
        elsif json[:notifications]
          instance.handle_notifications(json[:notifications])
        else
          instance.handler.send(:notice, json)
        end

        # puts "Want to update timestamp for handler for event: #{json.inspect}"
        instance.handler.update_timestamp!
      elsif msg.type == :close
        puts "trying to reconnect = got close event, msg: #{msg.inspect}"
        instance.reconnect!
      end
    rescue StandardError => e 
      instance.handler.handle_error(json, e)
    end
  end

  @socket.on :error do |e|
    puts e
  end
end