Skip to content

Instantly share code, notes, and snippets.

@donpdonp
Last active January 5, 2024 03:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save donpdonp/e6b0da4f4876e9422008c33f8f829f51 to your computer and use it in GitHub Desktop.
Save donpdonp/e6b0da4f4876e9422008c33f8f829f51 to your computer and use it in GitHub Desktop.
gluon simple price watch
(function() {
setup()
return {
name: "price"
}
})
var dbkey = "price"
var alert_channel = "#zrobo"
var state = { watches: {} }
var last = {}
var etherscan_apikey
function setup() {
// etherscan key
db.get('coin:etherscan_apikey', function(key){
if(key) {
etherscan_apikey = key
bot.say(bot.admin_channel, 'etherscan apikey loaded')
} else {
//bot.say(bot.admin_channel, 'coinmarketcap apikey missing')
}
})
// reload state
db.get(dbkey, function(json) {
try {
state = JSON.parse(json)
Object.keys(state.watches).forEach(function(ticker){
var watch = state.watches[ticker]
last[ticker] = price_get(ticker)
var msg = ticker + " " + watch.formula
if (watch.price) {
msg = msg + " last: "+watch.price.current_price.usd+" "+watch.price.last_updated
}
bot.say(bot.admin_channel, msg)
})
} catch(e) {
bot.say(bot.admin_channel, "price watches decode failed. resetting")
save()
}
})
}
function go(msg) {
if (msg.method == "clocktower") {
var time = new Date(Date.parse(msg.params.time))
if (time.getMinutes() % 10 == 0) {
clock_watches()
}
}
if(msg.method == "irc.privmsg") {
var match = /^\!price(\s+(.+))?$/.exec(msg.params.message)
if(match){
cmd(match[2], msg.params)
}
}
}
function clock_watches() {
Object.keys(state.watches).forEach(function(ticker){
var watch = state.watches[ticker]
var price = price_get(ticker)
if (price) {
var result = eval(watch, price)
if (result.go) {
bot.say(watch.channel, watch.nick+": "+result.msg+" ["+ticker+" "+watch.formula+"]")
state.watches[ticker].price = price
save()
}
}
})
}
function cmd(line, params) {
var parts = line ? line.split(' ') : []
if (parts.length == 2) {
if (parts[1] == 0) {
del(parts[0])
bot.say(params.channel, "deleted "+parts[0])
} else {
add(params.nick, params.channel, parts[0], parts[1])
bot.say(params.channel, "added "+parts[0]+" "+parts[1])
}
}
if (parts.length == 1) {
var coin = price_get(parts[0])
bot.say(params.channel, ""+parts[0]+" found "+coin.name+"("+coin.symbol+") $"+coin.current_price.usd)
}
if (parts.length == 0) {
if (Object.keys(state.watches).length > 0) {
Object.keys(state.watches).forEach(function(ticker){
var watch = state.watches[ticker]
var price = price_get(ticker)
var result = eval(watch, price)
bot.say(params.channel, "["+ticker+" "+watch.formula+"] "+result.msg)
})
} else {
bot.say(params.channel, "watch list empty. !price [<token> [<rule>]]. rule = >num, <num, num%")
}
}
}
function del(ticker) {
delete state.watches[ticker]
save()
}
function add(nick, channel, ticker, formula) {
state.watches[ticker] = {nick: nick, channel: channel, formula: formula, price: price_get(ticker)}
save()
}
function save() {
db.set(dbkey, JSON.stringify(state), function(result){
if (!result) {
bot.say(bot.admin_channel, "price state save err: "+e)
}
})
}
function eval(watch, market) {
var formula = watch.formula
var price = market.current_price.usd
var go = false
var msg = ""
if (formula[0] == ">") {
var limit = formula.substring(1);
go = price > limit
var percent = ((price / limit)-1)*100
msg = " $"+price+" "+percent.toFixed(1)+"% chg"
}
if (formula[0] == "<") {
var limit = formula.substring(1);
go = price < limit
var percent = ((price / limit)-1)*100
msg = " $"+price+" "+percent.toFixed(1)+"% chg"
}
if (formula[formula.length-1] == "%") {
var limit = watch.price.current_price.usd
var limit_percent = formula.substring(0, formula.length-1)
var chg = price - limit
var chg_sign = chg > 0 ? "+" : ""
var chg_ratio = (price - limit) / limit
go = Math.abs(chg_ratio) > limit_percent / 100
var ago = time_since(new Date(watch.price.last_updated))
var log10 = Math.log(price) / Math.log(10)
var fixed = 6 - (log10 > 0 ? log10 : 0)
if (fixed < 0) { fixed = 0 }
if (fixed > 20) { fixed = 20 }
msg = price +
" chg: "+chg_sign+chg.toFixed(fixed)+" ("+(chg_ratio*100).toFixed(1)+"%)"+
" last: "+watch.price.current_price.usd+" ago: "+ago
}
return {go: go, msg: msg}
}
function time_since(then) {
var now = new Date()
var elapsed_sec = (now - then)/1000
var temp
temp = elapsed_sec / 60 / 60 / 24
if (temp >= 1) {
return temp.toFixed(1)+" days"
}
temp = elapsed_sec / 60 / 60
if (temp >= 1) {
return temp.toFixed(1)+" hours"
}
temp = elapsed_sec / 60
if (temp >= 1) {
return temp.toFixed(1)+" minutes"
}
return elapsed_sec.toFixed(1)+" seconds"
}
function price_get(ticker) {
if (ticker == "eth:gas") {
var gas = eth('gas')
return { current_price: {usd: gas.FastGasPrice},
last_updated: new Date()}
} else if (ticker == "feargreed") {
// curl https://coinmarketcap.com/ | grep NEXT_DATA | cut -c82- | jq .props.pageProps.pageSharedData.fearGreedIndexData.currentIndex
// {"score": 57.45799120387904, "maxScore": 100, "name": "Neutral", "updateTime": "2023-07-18T00:00:00.000Z" }
} else if (ticker == "allbridge:usdc") {
var ab_price = allbridge('usdc')
return { current_price: {usd: ab_price},
last_updated: new Date()}
} else {
var url = "https://api.coingecko.com/api/v3/coins/"+ticker // limit=100 (maximum and default)
try {
var reply = http.get({url: url})
if (reply.status == 200) {
var report = JSON.parse(reply.body)
return report.market_data
} else {
//bot.say(bot.admin_channel, JSON.stringify(reply)) // status is undefined?
//bot.say(bot.admin_channel, "price coingecko http "+reply.status+" "+url)
}
} catch(e) {
//bot.say(bot.admin_channel, "price fetch err "+e)
}
}
}
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) {
//var value = parseFloat(tokens[0]['apr']) *100
var value = parseFloat(tokens[0]['poolInfo']['totalLpAmount'])
return value
}
} catch(e) {
bot.say(bot.admin_channel, "allbridge api query failed "+e+" "+url)
}
}
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)
// {"status":"1","message":"OK","result":{"LastBlock":"17238385","SafeGasPrice":"156","ProposeGasPrice":"156","FastGasPrice":"160","suggestBaseFee":"155.096570607","gasUsedRatio":"0.808357866666667,0.628340933333333,0.2736735,0.8038242,0.367055133333333"}}
return data.result
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment