Last active
June 25, 2021 01:47
-
-
Save donpdonp/6d005391de9dc33b7ba14eb0b6ae9953 to your computer and use it in GitHub Desktop.
gluon market watch
This file contains hidden or 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: "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