class Ubea::Exchange::KrakenBase

Constants

BadResponseError
RateError

Public Instance Methods

balance() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 38
def balance
  balance = post_private("Balance")

  OpenStruct.new(
    fiat: Money.new(balance["Z#{fiat_currency}"], fiat_currency),
    xbt: BigDecimal.new(balance["XXBT"]),
  ).freeze
end
exchange_settings() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 20
def exchange_settings
  raise NotImplementedError
end
fiat_currency() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 16
def fiat_currency
  raise NotImplementedError
end
name() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 12
def name
  "Kraken (#{fiat_currency})"
end
open_orders() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 81
def open_orders
  post_private("OpenOrders")["open"]
end
open_orders?() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 85
def open_orders?
  !open_orders.empty?
end
refresh_order_book!() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 28
def refresh_order_book!
  json = get_json("https://api.kraken.com/0/public/Depth?pair=XBT#{fiat_currency}") or return

  asks = format_asks_bids(json["result"]["XXBTZ#{fiat_currency}"]["asks"])
  bids = format_asks_bids(json["result"]["XXBTZ#{fiat_currency}"]["bids"])

  mark_as_refreshed
  @order_book = OrderBook.new(asks: asks, bids: bids)
end
trade!(args, simulate: false) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 47
def trade!(args, simulate: false)
  params = {
    pair: "XXBTZ#{fiat_currency}",
    type: args.fetch(:type),
    volume: args.fetch(:volume),
  }

  ordertype = args.fetch(:ordertype, "limit")

  case ordertype
  when "market"
    params.merge!(
      ordertype: "market",
    )
  when "limit"
    params.merge!(
      price: args.fetch(:price),
      ordertype: "limit",
    )
  else
    raise "Unknown ordertype"
  end

  if simulate
    params.merge!(
      validate: true
    )
  end

  Log.debug params
  trade = post_private("AddOrder", params)
  Log.info trade
end
trade_fee() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 24
def trade_fee
  BigDecimal.new("0.0035").freeze # 0.35%
end

Private Instance Methods

encode_params(params) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 165
def encode_params(params)
  uri = Addressable::URI.new
  uri.query_values = params
  uri.query
end
format_asks_bids(json) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 91
def format_asks_bids(json)
  json.map do |price, volume|
    Offer.new(
      price: Money.new(price, fiat_currency),
      volume: volume
    ).freeze
  end
end
generate_hmac(key, message) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 161
def generate_hmac(key, message)
  Base64.strict_encode64(OpenSSL::HMAC.digest('sha512', key, message))
end
generate_message(method, params) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 156
def generate_message(method, params)
  digest = OpenSSL::Digest.new('sha256', params['nonce'] + encode_params(params)).digest
  url_path(method) + digest
end
generate_signature(method, params) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 150
def generate_signature(method, params)
  key = Base64.decode64 exchange_settings[:api_secret]
  message = generate_message(method, params)
  generate_hmac(key, message)
end
nonce() click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 135
def nonce
  now = Time.now.to_f

  @delay ||= 1
  if (@nonce || 0) + @delay > now.to_i
    Log.warn "Throttling API call for #{@delay}s to #{self}"
    sleep @delay
    now = Time.now.to_f
  end

  @nonce = now.to_i

  sprintf("%.6f", now).sub(".", "")
end
post_private(method, params = {}) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 100
def post_private(method, params = {})
  params['nonce'] = nonce

  response = retryable_http_request do
    http_adapter("https://api.kraken.com").post(url_path(method), params) do |request|
      request.headers['API-Key'] = exchange_settings[:api_key]
      request.headers['API-Sign'] = generate_signature(method, params)
    end
  end

  json = JSON.parse(response.body)
  unless json["error"].empty?
    raise BadResponseError if json["error"] == ["EAPI:Invalid nonce"]
    raise RateError if json["error"] == ["EAPI:Rate limit exceeded"]

    p json
    raise "OOPS"
  end

  @delay = 1

  json["result"]

rescue JSON::ParserError
  retry

rescue BadResponseError
  Log.warn "BadResponseError for #{self}, retrying..."
  retry

rescue RateError
  @delay == 1 ? @delay = 10 : @delay += 10
  retry
end
url_path(method) click to toggle source
# File lib/ubea/exchanges/kraken_base.rb, line 171
def url_path(method)
  '/0/private/' + method
end