class CoinQuery

Attributes

list[R]

Public Class Methods

new(autofind: true, dym: true, timeout: 5, filepath: '.', debug: false) click to toggle source
# File lib/coinquery.rb, line 23
def initialize(autofind: true, dym: true, timeout: 5, filepath: '.', 
               debug: false)

  @autofind, @dym, @timeout, @debug = autofind, dym, timeout, debug
  @filepath = filepath

  @url_base = 'https://api.coingecko.com/api/v3/'
  r = ping()

  if r then

    puts ('CoinQuery').highlight + ' (powered by CoinGecko)'
    puts
    puts ('ping response: ' + r.to_a.first.join(' ')).info

    if autofind then

      file = 'coinquery.dat'

      if not File.exists? file then

        puts ('fetching coins list ...').info  
        @list = api_call 'coins/list'
      

        if @dym then

          puts 'loading did_you_mean ...'.info if @debug          

          @dym = DidYouMean::SpellChecker.new(dictionary: @list.flat_map \
                    {|x| [x['symbol'], x['name']]})
        end

      end


      if not File.exists? file then

        File.open(File.join(@filepath, file), 'w+') do |f|  
         Marshal.dump([@list, @dym], f)  
        end 

      else
      
        puts ('loading coins list ...').info  
        File.open(File.join(@filepath, file)) do |f|  
          @list, @dym = Marshal.load(f)  
        end
  
      end

    end
  end
  
  @table = RecordxSqlite.new(File.join(@filepath, 'coinquery.db'), 
    table: {coins: {id: '', cname: '', price: '', date: 0}})
  

end

Public Instance Methods

archive(limit: 250) click to toggle source

archives the cryptocurrency prices in a local sqlite database note: intended for archiving prices on a daily basis

# File lib/coinquery.rb, line 86
def archive(limit: 250)    
      
  puts 'archive: fetching coins ...'.info
  a = coins(limit: limit)
  
  puts 'archive: saving to database ...'.info

  a.each do |coin|
    
    uid = coin['id'] + Date.today.to_time.to_i.to_s
    @table.create id: uid.to_s, cname: coin['name'], 
        price: coin['current_price'].to_s, date: Date.today.to_time.to_i
    
  end
  
  puts 'archive: completed'.info
  
end
coins(limit: 5) click to toggle source

lists the top coins (limited to 5 by default)

# File lib/coinquery.rb, line 107
def coins(limit: 5)
  currency = 'usd'
  api_call "coins/markets?vs_currency=#{currency}&per_page=#{limit}"
end
coins_list() click to toggle source

lists the names and identifiers of all coins

# File lib/coinquery.rb, line 114
def coins_list
  @list
end
find_coin(coin_name) click to toggle source
# File lib/coinquery.rb, line 118
def find_coin(coin_name)

  return coin_name unless @autofind

  s = coin_name.to_s.downcase
  puts 's: ' + s.inspect if @debug
  r = @list.find {|coin| coin['symbol'].downcase == s || coin['name'].downcase == s}
  puts 'r: ' + r.inspect if @debug
  
  if r.nil? then

    if @dym then

      suggestion = @dym.correct coin_name
      raise CoinQueryException, "unknown coin or token name. \n"  \
          + "Did you mean %s?" % [suggestion.first]

    else

      raise CoinQueryException, "unknown coin or token name."

    end

  end

  r

end
find_id(name) click to toggle source
# File lib/coinquery.rb, line 147
def find_id(name)
  r = find_coin(name)
  r['id']
end
find_name(s) click to toggle source
# File lib/coinquery.rb, line 152
def find_name(s)
  r = find_coin s
  r['name']
end
historical_price(coin, rawdate) click to toggle source

returns the price of a coin for a given historical date e.g. historical_price('Bitcoin', '01-05-2021')

# File lib/coinquery.rb, line 160
def historical_price(coin, rawdate)

  uc = Unichron.new(rawdate.to_s, :little_endian)
  raise 'invalid date' unless uc.valid?
  date = uc.to_date.strftime("%d-%m-%Y")

  id = find_id coin
  r = api_call "coins/%s/history?date=%s" % [id, date]
  price = r['market_data']['current_price']['usd']
  price < 1 ? price : price.round(2)

end
Also aliased as: history
history(coin, rawdate)
Alias for: historical_price
ping() click to toggle source
# File lib/coinquery.rb, line 175
def ping
  api_call 'ping'
end
price(coin) click to toggle source

returns the price for a given a coin e.g. price('Litecoin')

# File lib/coinquery.rb, line 182
def price(coin)

  currency = 'usd'
  id = find_id coin
  r = api_call("simple/price?ids=#{id}&vs_currencies=#{currency}")

  if r then
    val = r[id][currency]
    val < 1 ? val : val.round(2)
  end
end
query_archive(coin_name, rawdate) click to toggle source

use the database archive to query the historical price of a coin e.g. query_archive :btc, '1 May 2021'

# File lib/coinquery.rb, line 197
def query_archive(coin_name, rawdate)

  uc = Unichron.new(rawdate.to_s, :little_endian)
  raise 'invalid date' unless uc.valid?
  date = uc.to_date
  
  coin_id = find_id coin_name    
  
  id = coin_id + date.to_time.to_i.to_s
  r = @table.query "select * from coins where id == '#{id}'"
  r.first if r
  
end

Private Instance Methods

api_call(api_request) click to toggle source
# File lib/coinquery.rb, line 214
def api_call(api_request)
  
  begin
    Timeout::timeout(@timeout){
      response = Excon.get(@url_base + api_request)
      JSON.parse(response.body)
    }
  rescue Timeout::Error => e
    raise CoinQueryException, 'connection timed out'
  rescue OpenURI::HTTPError => e
    raise CoinQueryException, '400 bad request'
  end

end