Last active
December 31, 2023 08:02
-
-
Save donpdonp/fb21db62bf6bd95644cc9129b8fc0a1d to your computer and use it in GitHub Desktop.
gluon coinmarketcap coin price
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
setup() | |
return { | |
name: "coin" | |
} | |
}) | |
var etherscan_apikey | |
var coingecko_apikey | |
var cache_date = new Date(0) | |
var cache = {data:[]} | |
var ok_channels = ['#pdxcoins', '#zrobo', '#pdxbots', '#portlandor'] | |
var gecko_list = {} | |
function setup() { | |
gecko_list = JSON.parse(http.get("https://api.coingecko.com/api/v3/coins/list")) | |
bot.say(bot.admin_channel, 'coingecko list cached '+gecko_list.length+' coins') | |
db.get('coin:etherscan_apikey', function(key){ | |
if(key) { | |
etherscan_apikey = key | |
bot.say(bot.admin_channel, 'coin: etherscan apikey loaded') | |
} else { | |
bot.say(bot.admin_channel, 'coin: etherscan apikey missing') | |
} | |
}) | |
db.get('coin:coingecko_apikey', function(key){ | |
if(key) { | |
coingecko_apikey = key | |
bot.say(bot.admin_channel, 'coin: coingecko apikey loaded') | |
} else { | |
bot.say(bot.admin_channel, 'coin: coingecko apikey missing') | |
} | |
}) | |
} | |
function go(msg) { | |
if(msg.method == "irc.privmsg") { | |
var cmd = /^\!coin(\s+(.+))?$/ | |
var match = cmd.exec(msg.params.message) | |
if(match){ | |
var service = 'gecko' | |
var ticker = match[2] | |
//report(msg.params, ticker) | |
quote(msg.params.channel, service, ticker) | |
} | |
var parts = msg.params.message.split(' ') | |
for(var i=0; i < parts.length; i++) { | |
var word = parts[i] | |
var coincmd = /\$((\w+):)?([0-9A-Za-z]+\S*)+/ | |
var coinmatch = coincmd.exec(word) | |
if (coinmatch) { | |
//bot.say(bot.admin_channel, "coin: "+word+" 1:"+coinmatch[1]+" 2:"+coinmatch[2]+" 3:"+coinmatch[3]) | |
if (ok_channels.indexOf(msg.params.channel) >= 0) { | |
var service = coinmatch[2] | |
var ticker = coinmatch[3] | |
if (!service) { service = "gecko" } | |
quote(msg.params.channel, service, ticker) | |
} | |
} else { | |
return //early abort | |
} | |
} | |
} | |
} | |
function quote(channel, service, ticker) { | |
switch(service) { | |
case 'coinmarketcap': | |
// obsolete | |
var quote = coinmarketcap(ticker) | |
if(quote) { | |
var parts = coinmarketcapreport(quote) | |
bot.say(channel, parts.join(' ')+" coinmarketcap.com") | |
} | |
break | |
case 'coincap': | |
var quote = coincap(ticker) | |
if(quote) { | |
var parts = coincapreport(quote) | |
bot.say(channel, parts.join(' ')+" coincap.io") | |
} | |
break | |
case 'gecko': | |
var quotes = gecko(ticker) | |
quotes.forEach(function(quote){ | |
var parts = geckoreport(quote) | |
bot.say(channel, parts.join(' ')+" coingecko.com") | |
}) | |
break | |
case 'yahoo': | |
var quote = yahoo(ticker) | |
if(quote.status == 200) { | |
var parts = yahooreport(JSON.parse(quote.body)) | |
bot.say(channel, parts+" yahoo.com") | |
} else { | |
bot.say(channel, "yahoo err http " + quote.status + " " + quote.body.substr(0,90) ) | |
} | |
break | |
case 'compound': | |
var data = compound_data() | |
var quote = compound_find(data, ticker.toUpperCase()) | |
if (quote) { | |
var eth_price = coincap('ETH').priceUsd | |
var csay = compoundreport(quote, eth_price) | |
bot.say(channel, ticker+" "+csay) | |
} else { | |
var token_list = data.map(function(c){return c.underlying_symbol}).join(", ") | |
bot.say(channel, "compound cTokens are: "+token_list) | |
} | |
break | |
case 'dai': | |
bot.say(channel, daicdpfee(ticker)) | |
break | |
case 'fed': | |
fedstlouis(ticker, function(quote){ | |
if(quote){ | |
bot.say(channel, fedstlouisreport(quote)) | |
} | |
}) | |
break | |
case 'eth': | |
bot.say(channel, "ethgasstation fast: "+eth('gas')+" gwei") | |
break | |
case 'allbridge': | |
bot.say(channel, "allbridge "+ticker+": "+allbridge(ticker).toFixed(1)+"%") | |
break | |
} | |
} | |
function eth(cmd) { | |
switch(cmd) { | |
case 'gas': | |
var url = 'https://api.etherscan.io/api?module=gastracker&action=gasoracle&apikey='+etherscan_apikey | |
var json = http.get(url) | |
var data = JSON.parse(json) | |
return data.result.FastGasPrice | |
} | |
} | |
function alphavantage(ticker) { | |
db.get('coin:alphavantage', function(key){ }) | |
//https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&apikey= | |
} | |
function worldtradingdata() { | |
db.get('coin:worldtradingdata', function(key){ }) | |
//https://api.worldtradingdata.com/api/v1/stock?symbol=SNAP,TWTR,VOD.L&api_token= | |
} | |
function fedstlouis(series, cb) { | |
var unit = '' | |
if(!series || series == "rate") { series = 'EFFR'; unit = '%' } | |
if(series == "m3") { series = 'MABMM301USM189S' } | |
if(series == "m2") { series = 'M2SL' } | |
if(series == "m1") { series = 'M1SL' } | |
db.get('coin:fedstlouis', function(key){ | |
var meta_url = 'https://api.stlouisfed.org/fred/series?series_id='+series+'&api_key='+key+'&file_type=json' | |
var meta_json = http.get(meta_url) | |
var meta = JSON.parse(meta_json) | |
var title = meta['seriess'][0]['title'] | |
var data_url = 'https://api.stlouisfed.org/fred/series/observations?series_id='+series+'&api_key='+key+'&file_type=json' | |
bot.say(bot.admin_channel, data_url) | |
var json = http.get(data_url) | |
var data = JSON.parse(json) | |
var ocount = data.observations.length | |
var last_report = data.observations[ocount-1] | |
last_report.title = title | |
last_report.unit = unit | |
cb(last_report) | |
}) | |
} | |
function fedstlouisreport(quote) { | |
return quote.title+": "+quote.value+quote.unit+" stlouisfed.org" | |
} | |
function coincapreport(quote) { | |
var parts = [quote.id] | |
parts.push("$"+(quote.priceUsd/1).toFixed(4)) | |
parts.push("#"+quote.rank) | |
if(quote.vwap24Hr) { | |
var h24chg = quote.priceUsd/quote.vwap24Hr | |
var sign | |
if (h24chg > 1) { | |
sign = "+" | |
h24chg -= 1 | |
} else { | |
sign = "-" | |
h24chg = 1-h24chg | |
} | |
parts.push("24hr chg "+sign+(h24chg*100).toFixed(1)+"%") | |
} | |
return parts | |
} | |
function allbridge(ticker) { | |
var url = "https://core.api.allbridgecoreapi.net/token-info" | |
//bot.say(bot.admin_channel, url) | |
try { | |
var json = http.get(url) | |
var data = JSON.parse(json) | |
var tokens = data['ETH']['tokens'].filter(function(c){return c.symbol.toLowerCase() == ticker.toLowerCase() }) | |
if (tokens.length > 0) { | |
return parseFloat(tokens[0]['apr']) * 100 | |
} else { | |
return ticker+" not found" | |
} | |
} catch(e) { | |
bot.say(bot.admin_channel, "allbridge api query failed "+e+" "+url) | |
} | |
} | |
function coinmarketcap(ticker) { | |
var url = "https://api.coinmarketcap.com/v2/ticker/" // limit=100 (maximum and default) | |
bot.say(bot.admin_channel, url) | |
try { | |
var json = http.get(url) | |
var quote = JSON.parse(json) | |
var winner | |
Object.keys(quote.data).forEach(function(k) { | |
var q = quote.data[k] | |
if (q.symbol == ticker.toUpperCase()) { | |
winner = q | |
} | |
}) | |
return winner | |
} catch(e) { | |
bot.say(bot.admin_channel, "coinmarketcap api query failed "+e+" "+url) | |
} | |
} | |
function coinmarketcapreport(report) { | |
//{"circulating_supply":17927750,"id":1,"last_updated":1568143291,"max_supply":21000000,"name":"Bitcoin", | |
//"quotes":{"USD":{"market_cap":183306673898,"percent_change_1h":-0.19,"percent_change_24h":-0.69, | |
// "percent_change_7d":-4.01,"price":10224.7450962,"volume_24h":14149978597.9706}}, | |
//"rank":1,"symbol":"BTC","total_supply":17927750,"website_slug":"bitcoin"} | |
return [report.symbol, report.quotes.USD.price.toFixed(4), "24 hr chg", report.quotes.USD.percent_change_24h+"%"] | |
} | |
function gecko_find(ticker) { | |
return gecko_list.reduce(function(m, record){ | |
var ticker_lower = ticker.toLowerCase() | |
if (ticker_lower == record.symbol.toLowerCase() || | |
ticker_lower == record.id.toLowerCase()) { | |
m.push(record) | |
} | |
return m | |
}, []) | |
} | |
function gecko(ticker) { | |
var coinlist = gecko_find(ticker) | |
if (coinlist.length == 0) { | |
bot.say(bot.admin_channel, "coingecko list does not contain '"+ticker+"'") | |
} | |
var close_coins = coinlist.reduce(function(m,coin){ | |
var url = "https://api.coingecko.com/api/v3/coins/"+coin.id+"?x_cg_demo_api_key="+coingecko_apikey | |
//bot.say(bot.admin_channel, url) | |
try { | |
var json = http.get(url) | |
var quote = JSON.parse(json) | |
if (quote.market_data) { | |
m.push(quote) | |
} else { | |
bot.say(bot.admin_channel, "coingecko "+coin.id+" missing market_data: "+json) | |
} | |
} catch(e) { | |
bot.say(bot.admin_channel, "coingecko api query failed "+e+" "+url) | |
} finally { | |
return m | |
} | |
}, []) | |
var sorted_close_coins = close_coins.sort(function(a,b){return a.market_data.total_volume.usd < b.market_data.total_volume.usd}) | |
if (sorted_close_coins.length > 1) { | |
var a = sorted_close_coins[0] | |
var b = sorted_close_coins[1] | |
if (a.market_data.total_volume.usd > 10*b.market_data.total_volume.usd) { // clear winner | |
return [a] | |
} | |
} | |
return sorted_close_coins | |
} | |
function geckoreport(report) { | |
var parts = [report['name']+'('+report['symbol']+')', | |
'$'+report['market_data']['current_price']['usd']] | |
var rank = report['market_cap_rank'] | |
if (rank) { parts.push('#'+rank) } | |
var pcp24 = report['market_data']['price_change_percentage_24h'] | |
var sign = pcp24 > 0 ? "+" : "" | |
if (pcp24) { | |
parts.push(sign+pcp24.toFixed(1)+'%') | |
} else { | |
parts.push('no price') | |
} | |
var vol = report['market_data']['total_volume']['usd'] | |
if (vol) { | |
parts.push('$'+units(vol)+"vol") | |
} else { | |
parts.push('no volume') | |
} | |
var ath_date_str = report['market_data']['ath_date']['usd'] | |
if (ath_date_str) { | |
var ath_date = new Date(ath_date_str) | |
var ath_time_diff = new Date() - ath_date | |
if (ath_time_diff < 1000 * 60 * 60 * 24) { | |
var ath = report['market_data']['ath']['usd'] | |
parts.push(" All time high was today: $" + ath) | |
} | |
} | |
return parts | |
} | |
function yahoo(ticker) { | |
return http.get({url:'https://query1.finance.yahoo.com/v8/finance/chart/'+ticker}) | |
} | |
function yahooreport(report) { | |
if (report.chart.error) { | |
return report.chart.error.description | |
} else { | |
var meta = report.chart.result[0].meta | |
return meta.symbol + '('+meta.instrumentType+') $' + meta.regularMarketPrice + meta.currency+ ' '+ | |
'(previous close $' + meta.previousClose+')' | |
} | |
} | |
function coincap(ticker) { | |
/* */ | |
var url = "https://api.coincap.io/v2/assets?limit=1&search="+encodeURIComponent(ticker) | |
try { | |
var json = http.get(url) | |
var quote = JSON.parse(json) | |
if (quote.data) { | |
return quote.data[0] | |
} | |
} catch(e) { | |
} | |
} | |
function compound_data() { | |
var url = 'https://api.compound.finance/api/v2/ctoken' | |
var json = http.get(url) | |
var data = JSON.parse(json) | |
return data.cToken | |
} | |
function compound_find(tokens, ticker) { | |
for(var i=0; i < tokens.length; i++) { | |
var token = tokens[i] | |
if(token.underlying_symbol == ticker) { | |
return token | |
} | |
} | |
} | |
function compoundreport(quote, eth_price) { | |
var supply_usd = quote.total_supply.value*quote.underlying_price.value*eth_price | |
var borrow_usd = quote.total_borrows.value*quote.underlying_price.value*eth_price | |
return "supply "+((quote.total_supply.value)/1000000).toFixed(3)+"M"+ | |
"($"+(supply_usd/1000000).toFixed(3)+"M) pays "+ | |
(quote.supply_rate.value*100).toFixed(1)+"%/yr. "+ | |
"borrow "+((quote.total_borrows.value)/1000000).toFixed(3)+"M"+ | |
"($"+(borrow_usd/1000000).toFixed(3)+"M) costs "+ | |
(quote.borrow_rate.value*100).toFixed(1)+"%/yr. "+ | |
"compound.finance v2" | |
/* | |
{ | |
"borrow_rate": { | |
"value": "0.030601136172511351" | |
}, | |
"cash": { | |
"value": "82.55526888" | |
}, | |
"collateral_factor": { | |
"value": "0" | |
}, | |
"exchange_rate": { | |
"value": "0.020001332991763432" | |
}, | |
"interest_rate_model_address": "0xbae04cbf96391086dc643e842b517734e214d698", | |
"name": "Compound Wrapped BTC", | |
"number_of_borrowers": 31, | |
"number_of_suppliers": 75, | |
"reserves": { | |
"value": "0.0006450620000000000000000" | |
}, | |
"supply_rate": { | |
"value": "0.000973227770582953" | |
}, | |
"symbol": "cWBTC", | |
"token_address": "0xc11b1268c1a384e55c48c2391d8d480264a3a7f4", | |
"total_borrows": { | |
"value": "3.02412952" | |
}, | |
"total_supply": { | |
"value": "4278.65249647" | |
}, | |
"underlying_address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", | |
"underlying_name": "Wrapped BTC", | |
"underlying_price": { | |
"value": "53.1117068891602500000000000" | |
}, | |
"underlying_symbol": "WBTC" | |
} | |
*/ | |
} | |
function report(params, ticker) { | |
coinmarketcap_freshen(params.channel) | |
var matches = cache_find(ticker) | |
if (matches.length == 0) { | |
bot.say(params.channel, "no coins match "+ticker+" ("+Object.keys(cache.data).length+" coins in cache)") | |
} | |
if (matches.length == 1) { | |
var coin = matches[0] | |
coin.last_updated = new Date(parseInt(coin.last_updated)*1000) | |
var delay = (new Date() - coin.last_updated) | |
//{"circulating_supply":17180737,"id":1,"last_updated":"2018-07-30T23:23:28.000Z","max_supply" | |
// :21000000,"name":"Bitcoin","quotes":{"USD":{"market_cap":140363700920,"percent_change_1h":0.06,"per | |
// cent_change_24h":-0.24,"percent_change_7d":5.48,"price":8169.83002069,"volume_24h":5602012567.1652} | |
// },"rank":1,"symbol":"BTC","total_supply":17180737,"website_slug":"bitcoin"} | |
var msg = coin.symbol.toLowerCase() + " $" + usd_digits(coin.quotes.USD.price) + | |
" rank: #"+coin.rank+" 24hr: "+parseInt(coin.quotes.USD.percent_change_24h)+"% "+ | |
"[coinmarketcap.com "+duration_seconds(new Date(), coin.last_updated)+"]" | |
if (delay > 1000 * 60 * 10) { | |
msg = msg + " warning: report is more than 10 min old." | |
} | |
bot.say(params.channel, msg) | |
} | |
if (matches.length > 1) { | |
bot.say(params.channel, ""+matches.length+" coins match "+ticker) | |
} | |
} | |
function daicdpfee(symbol) { | |
if (symbol == "fee") { | |
try { | |
var url = "https://defiexplore.com/api/stats/globalInfo" | |
bot.say(bot.admin_channel, url) | |
var json = http.get(url) | |
var data = JSON.parse(json).tokenData | |
if (data) { | |
var fee_desc = function(coin, coin_data){return coin + " " + coin_data.stabilityFee +"%/yr"} | |
return "DAI loan fee from "+ Object.keys(data).map(function (coin) {return fee_desc(coin, data[coin])}).join(", ") | |
} else { | |
return symbol + " data missing? " + Object.keys(data) | |
} | |
} catch(e) { | |
return e + ". bad json? " + json.substr(0,20) + ".." + json.substr(json.length-20, json.length) | |
} | |
} else { | |
return "unknown "+symbol+" available commands: $dai:fee" | |
} | |
} | |
function siafee(ticker) { | |
if(ticker == 'STORAGE') { | |
return JSON.parse(http.get("https://siastats.info/dbs/storagepricesdb.json"))[0] | |
} | |
} | |
function cache_find(ticker) { | |
return Object.keys(cache.data).filter(function(coin_id){ | |
var coin=cache.data[coin_id]; | |
return coin.symbol.toLowerCase() == ticker.toLowerCase() | |
}).map(function(coin_id){return cache.data[coin_id]}) | |
} | |
function coinmarketcap_freshen(channel) { | |
var limit = new Date(new Date().getTime() - (5*60*1000)) | |
if (cache_date < limit) { | |
var start = new Date() | |
var url = "https://api.coinmarketcap.com/v2/ticker/" // limit=100 (maximum and default) | |
try { | |
var json = http.get(url) | |
cache = JSON.parse(json) | |
cache_date = new Date() | |
bot.say(channel, "coinmarketcap "+Object.keys(cache.data).length+" of "+cache.metadata.num_cryptocurrencies+ | |
" coins in "+ duration_seconds(cache_date, start)) | |
} catch(e) { | |
bot.say(channel, "coinmarketcap api query failed "+e+" "+url) | |
} | |
} else { | |
var duration = (new Date()) - cache_date | |
//bot.say(params.channel, "coinmarketcap cache good. "+duration+" seconds") | |
} | |
} | |
/* | |
{ | |
"data": { | |
"1": { | |
"id": 1, | |
"name": "Bitcoin", | |
"symbol": "BTC", | |
"website_slug": "bitcoin", | |
"rank": 1, | |
"circulating_supply": 17180662.0, | |
"total_supply": 17180662.0, | |
"max_supply": 21000000.0, | |
"quotes": { | |
"USD": { | |
"price": 8167.57617335, | |
"volume_24h": 5603038684.12216, | |
"market_cap": 140324365594.0, | |
"percent_change_1h": 0.3, | |
"percent_change_24h": -0.35, | |
"percent_change_7d": 5.5 | |
} | |
}, | |
"last_updated": 1532991927 | |
}, */ | |
function duration_seconds(a, b) { | |
var count = (a - b) / 1000 | |
var unit = "seconds" | |
if (count >= 60) { | |
count = count / 60 | |
unit = "minutes" | |
} | |
return count.toFixed(1) + " " + unit | |
} | |
function usd_digits(price_str) { | |
price = parseFloat(price_str) | |
if (price >= 0.1) { | |
return price.toFixed(2) | |
} else { | |
return price.toFixed(4) | |
} | |
} | |
function units(num) { | |
int = num | |
units = "" | |
if (num >= 1000) { | |
int = num/1000 | |
units="K" | |
} | |
if (num >= 1000000) { | |
int = num/1000000 | |
units="M" | |
} | |
if (num >= 1000000000) { | |
int = num/1000000000 | |
units="B" | |
} | |
return int.toFixed(1)+units | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment