Skip to content

Instantly share code, notes, and snippets.

@donpdonp
Last active June 25, 2021 01: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/6d005391de9dc33b7ba14eb0b6ae9953 to your computer and use it in GitHub Desktop.
Save donpdonp/6d005391de9dc33b7ba14eb0b6ae9953 to your computer and use it in GitHub Desktop.
gluon market watch
(function() {
setup()
return {
name: "market"
}
})
var history = {hour: 0, points: []}
var dbkey = "market:history"
var watch_list = ['btc', 'eth', 'doge', 'ada', 'bnb', 'xrp', 'bch']
function setup() {
//freshen()
//var last_updated = new Date(new Date() - 1000 * 60 * 60) // debug 1 hr ago
//historyupdate(last_updated, 1.23) // debug avg
db.get(dbkey, function(json) {
try {
history = JSON.parse(json)
bot.say(bot.admin_channel, "market history loaded: "+historylen()+" hours "+json.length+" bytes")
} catch(e) {
bot.say(bot.admin_channel, "market history load failed. clearing history")
db.set(dbkey, JSON.stringify(history))
}
})
}
function go(msg) {
if (msg.method == "clocktower") {
var time = new Date(Date.parse(msg.params.time))
if (time.getMinutes() == 30) {
doit(bot.admin_channel)
slopecheck()
}
if (time.getHours() == 6 && time.getMinutes() == 0) {
var tickers = history.points[history.hour].slice(0,10).map(function(h){return h.symbol})
var deltas = historydeltas(tickers)
if (deltas.length > 0) {
m = '6am top '+tickers.length+' coins %chg/hr: '+deltas.map(function(s){return cfmt(s)}).join(', ')
bot.say('#zrobo', m)
}
}
}
if(msg.method == "irc.privmsg") {
var slope_match = /^\!marketslope(\s+(.+))?$/.exec(msg.params.message)
if(slope_match){
slopecheck()
}
var market_match = /^\!market(\s+(.+))?$/.exec(msg.params.message)
if(market_match){
var hour = (new Date()).getHours()
if (!history.points[hour]) {
doit(msg.params.channel)
}
var tickers = []
if (market_match[2]) {
tickers = [market_match[2]]
} else {
tickers = watch_list
}
deltas = historydeltas(tickers)
var m = ''
if (deltas.length > 0) {
var stddev = standardDeviation(deltas.map(function(d){return d.avg}))
m = tickers+' %chg/hr: '+deltas.map(function(s){return cfmt(s)}).join(', ')+' '+
'('+stddev.toFixed(1)+'% stddev)'
} else {
m = 'not enough data yet from '+historylen()+' hours of history'
}
bot.say(msg.params.channel, m)
}
}
}
function slopecheck() {
var selected = history.points[history.hour]
for(var i=0; i < 20; i++) {
var symbol = selected[i].symbol
var sdout = stddevcheck(symbol)
var sdover = Math.abs(sdout.last) / sdout.stddev
var sdlimit = 2
if (sdover > sdlimit) {
bot.say(bot.admin_channel, symbol+" last hour chg "+sdout.last.toFixed(1)+"% is "+sdover.toFixed(1)+"x sd dev of "+sdout.stddev.toFixed(1)+"!")
}
}
}
function stddevcheck(symbol) {
var deltas = historydeltas([symbol])
var hourly_delta_avgs = deltas.map(function(d){return d.avg})
var stddev = standardDeviation(hourly_delta_avgs)
var mean = average(hourly_delta_avgs)
return { last: hourly_delta_avgs[0], stddev: stddev }
}
function cfmt(s) {
if (s) {
var prefix = '+'
if (s.avg < 0) { prefix = '' }
return prefix+s.avg.toFixed(1)+'%' // +'/sd:'+s.stddev.toFixed(1)
} else {
return "-null-"
}
}
function doit(channel) {
var markets = freshen()
var last_updated = new Date(markets[0].last_updated) // hacky
historyupdate(last_updated, markets)
}
function freshen() {
//var url = "https://api.coingecko.com/api/v3/coins/list"
var url = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&per_page=250&price_change_percentage=1h"
try {
var json = http.get(url)
markets = JSON.parse(json)
return markets
} catch(e) {
bot.say(bot.admin_channel, "market freshen err "+e)
}
}
function historyupdate(last_updated, markets) {
var hour = last_updated.getHours()
history.points[hour] = markets
history.hour = hour
var json = JSON.stringify(history)
db.set(dbkey, json)
//bot.say(bot.admin_channel, "historyupdate last hour "+hour+" coins "+markets.length+" total bytes "+json.length)
}
function hourlist(back) {
var hours = []
for(var i=0; i<back; i++) {
var h = history.hour - i
if (h < 0) { h = h + 24}
if (history.points[h]) {
hours.push(h)
}
}
return hours
}
function historydeltas(coins) {
var hours = hourlist(12)
return hours.map(function(h){
var points = history.points[h]
var chgs = coins.map(function(coin){
var cdata = find(coin, points)
if (cdata) {
return cdata.price_change_percentage_1h_in_currency
}
})
return stats(chgs)
})
}
function stats(list) {
return {
avg: average(list),
stddev: standardDeviation(list)
}
}
function find(coin, list) {
return list.reduce(function(m, c){
if (c.symbol == coin) {
m = c
}
return m
}, null)
}
function historylen() {
var len = 0
for(var i=0; i<history.points.length;i++) {
if(history.points[i]) { len = len + 1}
}
return len
}
/*{
"id": "iostoken",
"symbol": "iost",
"name": "IOST",
"image": "https://assets.coingecko.com/coins/images/2523/large/IOST.png?1557555183",
"current_price": 0.04953916,
"market_cap": 1118452489,
"market_cap_rank": 100,
"fully_diluted_valuation": 4469330938,
"total_volume": 380228219,
"high_24h": 0.05666,
"low_24h": 0.04825308,
"price_change_24h": -0.00696094,
"price_change_percentage_24h": -12.32022,
"market_cap_change_24h": -144899088.7055047,
"market_cap_change_percentage_24h": -11.46942,
"circulating_supply": 22522548772.0043,
"total_supply": 22522548772.0043,
"max_supply": 90000000000,
"ath": 0.129829,
"ath_change_percentage": -61.75017,
"ath_date": "2018-01-24T00:00:00.000Z",
"atl": 0.00160309,
"atl_change_percentage": 2997.72201,
"atl_date": "2020-03-13T02:25:35.257Z",
"roi": null,
"last_updated": "2021-05-13T15:44:16.928
} */
function calc(markets) {
var avgs = markets.map(function(cur) { return cur.price_change_percentage_24h })
var sum = avgs.reduce(function(acc,cur){return acc+cur}, 0)
var avg = sum / avgs.length
return { avg: avg, count: markets.length, date: markets[0].last_updated, stddev: standardDeviation(avgs) }
}
function standardDeviation(values){
var avg = average(values);
var squareDiffs = values.map(function(value){
var diff = value - avg;
var sqrDiff = diff * diff;
return sqrDiff;
});
var avgSquareDiff = average(squareDiffs);
var stdDev = Math.sqrt(avgSquareDiff);
return stdDev;
}
function average(data){
var sum = data.reduce(function(sum, value){
return sum + value;
}, 0);
var avg = sum / data.length;
return avg;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment