fix: Date.UTC spread operator and EMA for rolling sats chart
This commit is contained in:
36
index.html
36
index.html
@ -1571,24 +1571,24 @@ function setupCumulCard(cutoff) {
|
||||
|
||||
function setupSatsCard(cutoff) {
|
||||
const DAY_MS = 86400000;
|
||||
/* Derive daily balances (latest snapshot per day) */
|
||||
/* Derive daily balances (latest snapshot per day) using UTC date strings */
|
||||
const dailyBalances = {};
|
||||
const selectedAddr = getSelectedAddresses() || [];
|
||||
selectedAddr.forEach(addr => {
|
||||
const snaps = addressSnapshots[addr] || [];
|
||||
snaps.forEach(snap => {
|
||||
const dateStr = snap.block_timestamp.slice(0, 10);
|
||||
const utcTs = new Date(snap.block_timestamp).getTime();
|
||||
const dateStr = new Date(utcTs).toISOString().slice(0, 10);
|
||||
const btcVal = getTokenAmount(snap?.wallet?.cbBTC, 'cbBTC') + getTokenAmount(snap?.collateral?.cbBTC, 'cbBTC');
|
||||
const ts = new Date(snap.block_timestamp).getTime();
|
||||
if (!dailyBalances[dateStr] || ts > dailyBalances[dateStr].ts) {
|
||||
dailyBalances[dateStr] = { ts, dateStr, btcVal };
|
||||
if (!dailyBalances[dateStr] || utcTs > dailyBalances[dateStr].ts) {
|
||||
dailyBalances[dateStr] = { ts: utcTs, dateStr, btcVal };
|
||||
} else {
|
||||
dailyBalances[dateStr].btcVal += btcVal;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* Sort by date, compute daily delta (acquisition), then fill continuous timeline */
|
||||
/* Sort by date, compute daily delta (acquisition) */
|
||||
const sortedDays = Object.values(dailyBalances).sort((a, b) => a.dateStr.localeCompare(b.dateStr));
|
||||
const dailyDeltas = {};
|
||||
sortedDays.forEach((d, i) => {
|
||||
@ -1596,29 +1596,31 @@ function setupSatsCard(cutoff) {
|
||||
dailyDeltas[d.dateStr] = d.btcVal - prevBalance;
|
||||
});
|
||||
|
||||
/* Fill continuous daily timeline so no days are skipped */
|
||||
const firstDate = new Date(sortedDays[0].dateStr).getTime();
|
||||
const lastDate = new Date(sortedDays[sortedDays.length - 1].dateStr).getTime();
|
||||
/* Fill continuous daily timeline — iterate every day from first to last */
|
||||
const firstUTC = Date.UTC(new Date(sortedDays[0].dateStr).getUTCFullYear(), new Date(sortedDays[0].dateStr).getUTCMonth(), new Date(sortedDays[0].dateStr).getUTCDate());
|
||||
const lastUTC = Date.UTC(new Date(sortedDays[sortedDays.length - 1].dateStr).getUTCFullYear(), new Date(sortedDays[sortedDays.length - 1].dateStr).getUTCMonth(), new Date(sortedDays[sortedDays.length - 1].dateStr).getUTCDate());
|
||||
const continuousDays = [];
|
||||
for (let t = firstDate; t <= lastDate; t += DAY_MS) {
|
||||
for (let t = firstUTC; t <= lastUTC; t += DAY_MS) {
|
||||
const ds = new Date(t).toISOString().slice(0, 10);
|
||||
continuousDays.push({ ts: t, dateStr: ds, delta: dailyDeltas[ds] || 0 });
|
||||
}
|
||||
|
||||
/* 30-day rolling average of daily deltas */
|
||||
/* Exponentially weighted moving average — older days decay so average drops when there are no acquisitions */
|
||||
const filtered = continuousDays.filter(d => d.ts >= cutoff);
|
||||
const rollingAvg = [];
|
||||
const halfLife = 7;
|
||||
const decay = Math.pow(0.5, 1 / halfLife);
|
||||
let ewmaVal = filtered[0]?.delta || 0;
|
||||
const emaSats = [];
|
||||
for (let i = 0; i < filtered.length; i++) {
|
||||
const window = filtered.slice(Math.max(0, i - 29), i + 1);
|
||||
const avgSats = Math.round(window.reduce((s, d) => s + d.delta, 0) / window.length * 1e8);
|
||||
rollingAvg.push([filtered[i].ts, avgSats]);
|
||||
ewmaVal = filtered[i].delta + decay * ewmaVal;
|
||||
emaSats.push([filtered[i].ts, Math.round(ewmaVal * 1e8)]);
|
||||
}
|
||||
|
||||
const latestAvg = rollingAvg.length > 0 ? rollingAvg[rollingAvg.length - 1][1] : 0;
|
||||
const latestAvg = emaSats.length > 0 ? emaSats[emaSats.length - 1][1] : 0;
|
||||
document.getElementById('avg-sats-val').innerText = new Intl.NumberFormat('en-US').format(Math.round(latestAvg));
|
||||
const options = {
|
||||
chart: { id: 'instance-sats', type: 'area', height: 200, background: 'transparent', toolbar: { show: false }, sparkline: { enabled: false }, zoom: { enabled: true, type: 'x', autoScaleYaxis: true }, animations: { enabled: false } },
|
||||
series: [{ name: 'Avg Sats/Day', data: rollingAvg }],
|
||||
series: [{ name: 'Avg Sats/Day', data: emaSats }],
|
||||
dataLabels: { enabled: false },
|
||||
colors: [orangeBrandColor],
|
||||
stroke: { curve: 'smooth', width: 2 },
|
||||
|
||||
Reference in New Issue
Block a user