I've always been amazed about cryptocurrencies, so I decided to build a CLI app that gets prices and more detailed information about any cryptocurrency out there.
To make my app I used Open URI
, Net/http
and JSON
to gather and parse data from an API, I used PRY
for testing and I also used TTY-Prompt
, Launchy
and Colorize
to add style.
Note: Before even sketching your app you should first research the right API for your app, play around and see what data can you get from it. In my case I used CoinGecko.
I created an API
class with methods to handle gathering and parsing full information from the top 20 cryptocurrencies and from an individual cryptocurrency. Another method handles gathering and parsing partial information (Names and IDs) from ALL coins out there.
class FINDCRYPTO::API
def initialize
@url_top_20 = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=bitcoin%2C%20ethereum%2C%20binancecoin%2C%20tether%2C%20polkadot%2C%20cardano%2C%20ripple%2C%20litecoin%2C%20chainlink%2C%20bitcoin-cash%2C%20stellar%2C%20usd-coin%2C%20uniswap%2C%20dogecoin%2C%20wrapped-bitcoin%2C%20okb%2C%20aave%2C%20cosmos%2C%20nem%2C%20solana%20%20&order=market_cap_desc&per_page=100&page=1&sparkline=false&price_change_percentage=1h"
end
def get_top_20_cryptocurrencies
request = URI.parse(@url_top_20)
response = Net::HTTP.get_response(request)
crypto_hash = JSON.parse(response.body)
#binding.pry
self.create_cryptocurrency_objects(crypto_hash)
end
def create_cryptocurrency_objects(crypto_hash)
crypto_hash.each do |crypto_object|
FINDCRYPTO::Cryptocurrency.new(crypto_object)
end
end
def get_data_from_new_crypto(crypto_id)
url = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=#{crypto_id}&order=market_cap_desc&per_page=100&page=1&sparkline=false&price_change_percentage=1h"
request = URI.parse(url)
response = Net::HTTP.get_response(request)
crypto_hash = JSON.parse(response.body)
self.create_cryptocurrency_objects(crypto_hash)
end
def get_all_cryptocurrencies_names_and_ids
url = "https://api.coingecko.com/api/v3/coins/list?include_platform=false"
request = URI.parse(url)
response = Net::HTTP.get_response(request)
crypto_hash = JSON.parse(response.body)
self.create_cryptocurrency_names_and_ids_objects(crypto_hash)
end
def create_cryptocurrency_names_and_ids_objects(crypto_hash)
crypto_hash.each do |crypto_object|
FINDCRYPTO::Cryptocurrency_lookup.new(crypto_object)
end
end
end
The Cryptocurrency
class takes a hash from the API
class and handles the creation of individual cryptocurrency objects with full information, it also keeps on track of objects created.
class FINDCRYPTO::Cryptocurrency
@@all = []
def initialize(crypto_hash)
crypto_hash.each do |key, value|
self.class.attr_accessor(key)
self.send("#{key}=", value)
end
@@all << self
end
def self.all
@@all
end
end
The Cryptocurrency_lookup
class takes a hash from the API
class and handles the creation of individual cryptocurrency objects with partial information (Names and IDs only), it also keeps on track of objects created. What's the point of this class? Well, first of all my app counts all available crypto coins, then we'll need a full list of coins along with its id in order to request full information of a specific coin from the API later.
class FINDCRYPTO::Cryptocurrency_lookup
@@all = []
def initialize(crypto_hash)
crypto_hash.each do |key, value|
self.class.attr_accessor(key)
self.send("#{key}=", value)
end
@@all << self
end
def self.all
@@all
end
end
At this point you may be wondering what's that FINDCRYPTO:: right before a class name. Well, it's called module FINDCRYPTO
and it's just a wrapper for our code.
module FINDCRYPTO
end
The CLI
class keeps track of the user's menu choices. It initialize by displaying a welcome message along with the top 20 cryptocurrencies of the day and also gets a list of all crypto coins. The run
method greets the user and displays the menu
. In menu the user have the ability to select one of the 20 coins displayed, user can search for any cryptocurrency, user can also get updated data, see its logo in a browser or just display a list of 6000+ cryptocurrencies. The following code is easy to follow.
class FINDCRYPTO::CLI
def initialize
puts "\n"
puts "--------------------------------$--------------------------------"
crypt_is_everywhere = "Crypto Is Everywhere, But Should You Invest?"
puts " #{crypt_is_everywhere.colorize(:green)} "
puts "--------------------------------$--------------------------------"
puts "\n"
FINDCRYPTO::API.new.get_top_20_cryptocurrencies
FINDCRYPTO::API.new.get_all_cryptocurrencies_names_and_ids
@prompt = TTY::Prompt.new(help_color: :cyan)
end
def run
greeting
menu
end
def greeting
puts "There are exactly #{FINDCRYPTO::Cryptocurrency_lookup.all.count} cryptocurrencies at the time of this writing."
puts "Some experts have suggested that Bitcoin could be worth as much as $100,000 one day!"
puts "But, not everyone thinks investing in cryptocurrency is a good idea."
puts "Check the following valuable data and make your own conclusions:"
puts "\n"
end
def menu
puts "--------------------------------$--------------------------------"
top_20_crypt_prices = "Top 20 Cryptocurrency Prices by Market Cap:"
puts " #{top_20_crypt_prices.colorize(:green)} "
puts "--------------------------------$--------------------------------"
display_top_20_cryptocurrencies
puts "--------------------------------$--------------------------------"
input = @prompt.select("Would you like more information?") do |menu|
menu.choice "Yes, let me choose a cryptocurrency from the list above"
menu.choice "Yes, but let me search for a different cryptocurrency"
menu.choice "Nope! Please exit now."
end
if input == 'Yes, let me choose a cryptocurrency from the list above'
input_number = @prompt.ask("Type its number please:", default: "e.g. 1 for Bitcoin")
# if input.to_i > 0 && input.to_i <= FINDCRYPTO::Cryptocurrency.all.count
number = input_number.to_i
if number > FINDCRYPTO::Cryptocurrency.all.count || number == 0
invalid_input_try_again
else
display_crypto(number)
display_cryto_footer_menu
end
elsif input == 'Yes, but let me search for a different cryptocurrency'
puts "-----------------------$------------------------"
puts "Can't find your favorite crypto?"
display_search_input = @prompt.select("Choose an option:") do |menu|
menu.choice "Search a cryptocurrency"
menu.choice "Show full list of cryptocurrencies"
menu.choice "Go back"
menu.choice "Exit"
end
if display_search_input == 'Show full list of cryptocurrencies'
display_all_cryptocurrencies_names_and_ids
display_cryto_footer_menu
elsif display_search_input == 'Go back'
menu
elsif display_search_input == 'Search a cryptocurrency'
display_new_crypto
elsif display_search_input == 'Exit'
exit_cli
end
elsif input == 'Nope! Please exit now.'
exit_cli
end
end
def invalid_input_try_again
puts "Invalid input. Please try again"
sleep(1.5)
menu
end
def exit_cli
puts "If you don’t believe it or don’t get it, I don’t have the time to try to convince you, sorry."
puts "– Satoshi Nakamoto"
exit
end
def display_cryto_footer_menu
puts "\n"
puts "Very interesting, right?"
back_to_menu_input = @prompt.select("Would you like to see data of another cryptocurrency?", %w(Yes Exit))
if back_to_menu_input == "Yes"
menu
elsif back_to_menu_input == "Exit"
exit_cli
end
end
def display_new_crypto
input = @prompt.ask("Please type a Cryptocurrency name:", default: "e.g. Terra")
FINDCRYPTO::Cryptocurrency.all.each.with_index(1) do |cryptocurrency, index|
if cryptocurrency.name.downcase == input.downcase
crypto_id = cryptocurrency.id
puts "Oops! #{cryptocurrency.name}'s price is already displayed in main menu."
upadated_data_menu_input = @prompt.select("Do you want to see updated data?") do |menu|
menu.choice "Yes"
menu.choice "No. I love old news! Show me old data!"
end
#upadated_data_menu_input = gets.strip.downcase
if upadated_data_menu_input == "Yes"
FINDCRYPTO::API.new.get_data_from_new_crypto(crypto_id)
number = FINDCRYPTO::Cryptocurrency.all.count
display_crypto(number)
display_cryto_footer_menu
else upadated_data_menu_input == "No. I love old news! Show me old data!"
display_crypto(index)
display_cryto_footer_menu
end
end
end
### Iterate over all 6000+ cryptos to confirm name
FINDCRYPTO::Cryptocurrency_lookup.all.each do |cryptocurrency|
if cryptocurrency.name.downcase == input.downcase
crypto_id = cryptocurrency.id
FINDCRYPTO::API.new.get_data_from_new_crypto(crypto_id)
number = FINDCRYPTO::Cryptocurrency.all.count
display_crypto(number)
display_cryto_footer_menu
end
end
puts "Oops!"
puts "Sorry! I just iterated over #{FINDCRYPTO::Cryptocurrency_lookup.all.count} cryptocurrencies and I couldn't find '#{input}'"
puts "Double check its name and try again!"
sleep(1)
display_new_crypto
end
def display_crypto(number)
dollar_sign = '$'
index_number = number -1
crypto = FINDCRYPTO::Cryptocurrency.all[index_number]
bar_left = "--------------------$"
bar_right = "$--------------------"
puts "#{bar_left.ljust(24)} #{crypto.name.upcase.ljust(10).colorize(:green)} #{bar_right}"
puts "#{crypto.name}(#{crypto.symbol.upcase}) can be purchased on peer-to-peer networks"
puts "and cryptocurrency exchanges, just like buying stocks."
puts "-----------------------$ DATA $-----------------------"
puts "*** This data is valid as #{convert_to_local_time(crypto.last_updated)} ***"
coin_symbol_and_price = crypto.symbol.upcase + " price:"
puts "#{coin_symbol_and_price.ljust(25)} #{dollar_sign.colorize(:green)}#{crypto.current_price.to_s.colorize(:green)}"
pc24h = "Price Change 24 Hours:"
puts "#{pc24h.ljust(25)} #{dollar_sign.colorize(:green)}#{crypto.price_change_24h.to_s.colorize(:green)} or #{sprintf('%+.2f', crypto.price_change_percentage_24h)}%"
pc1h = "Price Change 1 Hour:"
puts "#{pc1h.ljust(25)} #{dollar_sign.colorize(:green)}#{sprintf('%.2f', ((crypto.price_change_percentage_1h_in_currency * crypto.current_price)/100)).to_s.colorize(:green)} or #{sprintf('%+.2f', crypto.price_change_percentage_1h_in_currency)}%"
hh24 = "24 Hour High:"
puts "#{hh24.ljust(25)} #{dollar_sign.colorize(:green)}#{crypto.high_24h.to_s.colorize(:green)}"
hl24 = "24 Hour Low:"
puts "#{hl24.ljust(25)} #{dollar_sign.colorize(:green)}#{crypto.low_24h.to_s.colorize(:green)}"
tv24 = "Trading Volume 24 Hours:"
puts "#{tv24.ljust(25)} #{dollar_sign.colorize(:green)}#{crypto.total_volume.to_s.colorize(:green)}"
mc = "Market Cap:"
puts "#{mc.ljust(25)} #{dollar_sign.colorize(:green)}#{crypto.market_cap.to_s.colorize(:green)}"
mcr = "Market Cap Rank:"
hash_sign = '#'
puts "#{mcr.ljust(25)} #{hash_sign.colorize(:green)}#{crypto.market_cap_rank.to_s.colorize(:green)}"
cs = "Circulating Supply:"
puts "#{cs.ljust(25)} #{dollar_sign.colorize(:green)}#{crypto.circulating_supply.to_s.colorize(:green)}"
#puts "Logo link: #{crypto.image}"
puts "--------------------------$---------------------------"
puts "Showing you #{crypto.name}'s logo in your browser!"
sleep(1)
Launchy.open(crypto.image)
end
def display_top_20_cryptocurrencies
dollar_sign = '$'
dot = '.'
price_string = 'PRICE:'
puts "# COIN: #{price_string.colorize(:green)} DATE:"
FINDCRYPTO::Cryptocurrency.all.each.with_index(1) do |cryptocurrency, index|
puts "#{index.to_s.ljust(3)} #{cryptocurrency.name.ljust(20)} #{dollar_sign.colorize(:green)}#{cryptocurrency.current_price.to_s.ljust(18).colorize(:green)} #{convert_to_local_time(cryptocurrency.last_updated)}"
end
end
def display_all_cryptocurrencies_names_and_ids
puts "***This is a LOOOOOOOOOONG list! I'm warning you!***"
sleep(1)
puts "# COIN:"
FINDCRYPTO::Cryptocurrency_lookup.all.each.with_index(1) do |cryptocurrency, index|
puts "#{index}. #{cryptocurrency.name}(#{cryptocurrency.symbol.upcase})"
end
end
private
def convert_to_local_time(utc_time)
utc_parsed = Time.parse(utc_time)
utc_parsed.localtime
end
end
In order to RUN
this app you'll need to set up your environment
:
require 'pry'
require 'net/http'
require 'open-uri'
require 'json'
require 'tty-prompt'
require 'launchy'
require 'colorize'
require_relative '../lib/modules/findcrypto.rb'
require_relative '../lib/api'
require_relative '../lib/cli'
require_relative '../lib/cryptocurrency'
require_relative '../lib/cryptocurrency_lookup'
And make sure to create a run
file:
#!/usr/bin/env ruby
require_relative '../config/environment'
FINDCRYPTO::CLI.new.run
Final product:
Check out a quick YouTube video of my project.
Check out the project here on GitHub!
Top comments (6)
Quite an interesting program, I think it's a really cool thing, the only thing I think is that not so many cryptocurrencies support especially niche ones, but for the main ones - just super. But it would be great to do something like this for parsing crypto wallet for business. Very curious thing would be, but it's probably not welcomed)
I like to analyze and predict stock market events. Many factors suggest that this is a good time to buy bitcoin now. I think buying bitcoin anonymously is a great option. After reading the reviews in general, it was clear that there is a lot of fraud around and so you need to protect yourself.
I urge you to contact a professional hacker if you are a victim of a scam. I lost a huge sum of money to a crypto scammer who lured me to invest in what I later found out to be a scam, but the good news is that HACKWEST AT WRITEME DOT COM recovered all the money back to my blockchain wallet. The fraudster stole about $468k in USDT, BTC, Ethereum and Sol. I strongly recommend West and his team if you’re a victim of crypto scam.
This tutorial is really helpful to me, in addition of this I discovered and learn a lot from other website regarding cryptocurrency.
You can visit this website to know more about Cryptocurrency [](cryptoknights.online/)
I'm always on the lookout for cool and user friendly crypto trading apps so I'll check this one out.
Do you like being a trader? If you are an experienced trader, give a couple of good tips.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.