class CoinSync::Importers::BinanceAPI

Constants

BASE_COINS
BASE_URL

Public Class Methods

new(config, params = {}) click to toggle source
Calls superclass method CoinSync::Importers::Base::new
# File lib/coinsync/importers/binance_api.rb, line 52
def initialize(config, params = {})
  super

  # only "Read Info" permission is required for the key
  @api_key = params['api_key']
  @secret_key = params['secret_key']
  @traded_pairs = params['traded_pairs']
end

Public Instance Methods

can_import?(type) click to toggle source
# File lib/coinsync/importers/binance_api.rb, line 61
def can_import?(type)
  @api_key && @secret_key && [:balances, :transactions].include?(type)
end
find_all_pairs() click to toggle source
# File lib/coinsync/importers/binance_api.rb, line 128
def find_all_pairs
  info_response = make_request('/v1/exchangeInfo', {}, false)

  if !info_response.is_a?(Net::HTTPSuccess)
    raise "Binance importer: Bad response: #{info_response.body}"
  end

  info_json = JSON.parse(info_response.body)

  found = []

  info_json['symbols'].each do |data|
    symbol = data['symbol']
    trades_response = make_request('/v3/myTrades', limit: 1, symbol: symbol)

    case trades_response
    when Net::HTTPSuccess
      trades_json = JSON.parse(trades_response.body)

      if trades_json.length > 0
        print '*'
        found << symbol
      else
        print '.'
      end
    else
      raise "Binance importer: Bad response: #{trades_response.body}"
    end
  end

  puts
  puts "Trading pairs found:"
  puts found.sort
end
import_balances() click to toggle source
# File lib/coinsync/importers/binance_api.rb, line 101
def import_balances
  response = make_request('/v3/account')

  case response
  when Net::HTTPSuccess
    json = JSON.parse(response.body)

    if json['code'] || !json['balances']
      raise "Binance importer: Invalid response: #{response.body}"
    end

    return json['balances'].select { |b|
      b['free'].to_f > 0 || b['locked'].to_f > 0
    }.map { |b|
      Balance.new(
        CryptoCurrency.new(b['asset']),
        available: BigDecimal.new(b['free']),
        locked: BigDecimal.new(b['locked'])
      )
    }
  when Net::HTTPBadRequest
    raise "Binance importer: Bad request: #{response}"
  else
    raise "Binance importer: Bad response: #{response}"
  end
end
import_transactions(filename) click to toggle source
# File lib/coinsync/importers/binance_api.rb, line 65
def import_transactions(filename)
  @traded_pairs or raise "Please add a traded_pairs parameter"

  transactions = []

  @traded_pairs.uniq.each do |pair|
    lastId = 0

    loop do
      response = make_request('/v3/myTrades', limit: 500, fromId: lastId + 1, symbol: pair)

      case response
      when Net::HTTPSuccess
        json = JSON.parse(response.body)

        if !json.is_a?(Array)
          raise "Binance importer: Invalid response: #{response.body}"
        elsif json.empty?
          break
        else
          json.each { |tx| tx['symbol'] = pair }
          lastId = json.map { |j| j['id'] }.sort.last

          transactions.concat(json)
        end
      when Net::HTTPBadRequest
        raise "Binance importer: Bad request: #{response} (#{response.body})"
      else
        raise "Binance importer: Bad response: #{response}"
      end
    end
  end

  File.write(filename, JSON.pretty_generate(transactions.sort_by { |tx| [tx['time'], tx['id']] }))
end
read_transaction_list(source) click to toggle source
# File lib/coinsync/importers/binance_api.rb, line 163
def read_transaction_list(source)
  json = JSON.parse(source.read)
  transactions = []

  json.each do |hash|
    entry = HistoryEntry.new(hash)

    if entry.buyer
      transactions << Transaction.new(
        exchange: 'Binance',
        time: entry.time,
        bought_amount: entry.quantity - entry.commission,
        bought_currency: entry.asset,
        sold_amount: entry.price * entry.quantity,
        sold_currency: entry.currency
      )
    else
      transactions << Transaction.new(
        exchange: 'Binance',
        time: entry.time,
        bought_amount: entry.price * entry.quantity - entry.commission,
        bought_currency: entry.currency,
        sold_amount: entry.quantity,
        sold_currency: entry.asset
      )
    end
  end

  transactions
end

Private Instance Methods

make_request(path, params = {}, signed = true) click to toggle source
# File lib/coinsync/importers/binance_api.rb, line 196
def make_request(path, params = {}, signed = true)
  print '.'

  if signed
    (@api_key && @secret_key) or raise "Public and secret API keys must be provided"

    params['timestamp'] = (Time.now.to_f * 1000).to_i
  end

  url = URI(BASE_URL + path)
  url.query = URI.encode_www_form(params)

  if signed
    hmac = OpenSSL::HMAC.hexdigest('sha256', @secret_key, url.query)
    url.query += "&signature=#{hmac}"
  end

  Request.get(url) do |request|
    request['X-MBX-APIKEY'] = @api_key
  end
end