global: snapshot

This commit is contained in:
nym21
2026-02-27 18:48:37 +01:00
parent 6845ad409b
commit d5ec291579
62 changed files with 1960 additions and 1449 deletions

View File

@@ -1,7 +1,7 @@
import { colors } from "../utils/colors.js";
import { brk } from "../client.js";
import { Unit } from "../utils/units.js";
import { dots, line, price } from "./series.js";
import { dots, line, price, rollingWindowsTree } from "./series.js";
import { satsBtcUsd, createPriceRatioCharts } from "./shared.js";
/**
@@ -255,11 +255,11 @@ export function createCointimeSection() {
name: "Compare",
tree: [
{
name: "Sum",
name: "Base",
title: "Coinblocks",
bottom: coinblocks.map(({ pattern, name, color }) =>
line({
metric: pattern.sum,
metric: pattern.height,
name,
color,
unit: Unit.coinblocks,
@@ -284,17 +284,18 @@ export function createCointimeSection() {
name,
tree: [
{
name: "Sum",
name: "Base",
title,
bottom: [
line({
metric: pattern.sum,
metric: pattern.height,
name,
color,
unit: Unit.coinblocks,
}),
],
},
rollingWindowsTree({ windows: pattern.sum, title, unit: Unit.coinblocks }),
{
name: "Cumulative",
title: `${title} (Total)`,
@@ -320,14 +321,14 @@ export function createCointimeSection() {
name: "Compare",
tree: [
{
name: "Sum",
name: "Base",
title: "Cointime Value",
bottom: [
...cointimeValues.map(({ pattern, name, color }) =>
line({ metric: pattern.sum, name, color, unit: Unit.usd }),
line({ metric: pattern.height, name, color, unit: Unit.usd }),
),
line({
metric: vocdd.pattern.sum,
metric: vocdd.pattern.height,
name: vocdd.name,
color: vocdd.color,
unit: Unit.usd,
@@ -360,12 +361,13 @@ export function createCointimeSection() {
name,
tree: [
{
name: "Sum",
name: "Base",
title,
bottom: [
line({ metric: pattern.sum, name, color, unit: Unit.usd }),
line({ metric: pattern.height, name, color, unit: Unit.usd }),
],
},
rollingWindowsTree({ windows: pattern.sum, title, unit: Unit.usd }),
{
name: "Cumulative",
title: `${title} (Total)`,
@@ -384,11 +386,11 @@ export function createCointimeSection() {
name: vocdd.name,
tree: [
{
name: "Sum",
name: "Base",
title: vocdd.title,
bottom: [
line({
metric: vocdd.pattern.sum,
metric: vocdd.pattern.height,
name: vocdd.name,
color: vocdd.color,
unit: Unit.usd,
@@ -401,6 +403,7 @@ export function createCointimeSection() {
}),
],
},
rollingWindowsTree({ windows: vocdd.pattern.sum, title: vocdd.title, unit: Unit.usd }),
{
name: "Cumulative",
title: `${vocdd.title} (Total)`,

View File

@@ -174,13 +174,13 @@ function coinsDestroyedTree(list, all, title) {
title: title("Coins Destroyed"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({
metric: tree.activity.coinblocksDestroyed.sum,
metric: tree.activity.coinblocksDestroyed.sum._24h,
name,
color,
unit: Unit.coinblocks,
}),
line({
metric: tree.activity.coindaysDestroyed.sum,
metric: tree.activity.coindaysDestroyed.sum._24h,
name,
color,
unit: Unit.coindays,
@@ -677,19 +677,19 @@ export function createActivitySection({
defaultActive: false,
}),
line({
metric: tree.activity.sent.sats.sum,
metric: tree.activity.sent.base.sats,
name: "sum",
color,
unit: Unit.sats,
}),
line({
metric: tree.activity.sent.btc.sum,
metric: tree.activity.sent.base.btc,
name: "sum",
color,
unit: Unit.btc,
}),
line({
metric: tree.activity.sent.usd.sum,
metric: tree.activity.sent.base.usd,
name: "sum",
color,
unit: Unit.usd,
@@ -701,19 +701,19 @@ export function createActivitySection({
title: title("Sent Volume (Total)"),
bottom: [
line({
metric: tree.activity.sent.sats.cumulative,
metric: tree.activity.sent.cumulative.sats,
name: "all-time",
color,
unit: Unit.sats,
}),
line({
metric: tree.activity.sent.btc.cumulative,
metric: tree.activity.sent.cumulative.btc,
name: "all-time",
color,
unit: Unit.btc,
}),
line({
metric: tree.activity.sent.usd.cumulative,
metric: tree.activity.sent.cumulative.usd,
name: "all-time",
color,
unit: Unit.usd,
@@ -816,13 +816,13 @@ export function createActivitySection({
title: title("Coins Destroyed"),
bottom: [
line({
metric: tree.activity.coinblocksDestroyed.sum,
metric: tree.activity.coinblocksDestroyed.sum._24h,
name: "Coinblocks",
color,
unit: Unit.coinblocks,
}),
line({
metric: tree.activity.coindaysDestroyed.sum,
metric: tree.activity.coindaysDestroyed.sum._24h,
name: "Coindays",
color,
unit: Unit.coindays,
@@ -1021,9 +1021,9 @@ export function createGroupedActivitySection({
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({
pattern: {
sats: tree.activity.sent.sats.sum,
btc: tree.activity.sent.btc.sum,
usd: tree.activity.sent.usd.sum,
sats: tree.activity.sent.base.sats,
btc: tree.activity.sent.base.btc,
usd: tree.activity.sent.base.usd,
},
name,
color,

View File

@@ -74,7 +74,7 @@ export function createPricesSectionFull({ cohort, title }) {
context: cohort.name,
legend: "Realized",
pricePattern: tree.realized.realizedPrice,
ratio: tree.realized.realizedPriceExtra,
ratio: { ...tree.realized.realizedPriceExtra, ...tree.realized.realizedPriceRatioExt },
color,
priceTitle: title("Realized Price"),
titlePrefix: "Realized Price",
@@ -86,7 +86,7 @@ export function createPricesSectionFull({ cohort, title }) {
context: cohort.name,
legend: "Investor",
pricePattern: tree.realized.investorPrice,
ratio: tree.realized.investorPriceExtra,
ratio: { ...tree.realized.investorPriceExtra, ...tree.realized.investorPriceRatioExt },
color,
priceTitle: title("Investor Price"),
titlePrefix: "Investor Price",

View File

@@ -519,21 +519,21 @@ function realizedPnlSum(tree) {
unit: Unit.usd,
}),
dots({
metric: r.realizedProfit.sum,
metric: r.realizedProfit.height,
name: "Profit",
color: colors.profit,
unit: Unit.usd,
defaultActive: false,
}),
dots({
metric: r.negRealizedLoss.sum,
metric: r.negRealizedLoss,
name: "Negative Loss",
color: colors.loss,
unit: Unit.usd,
defaultActive: false,
}),
dots({
metric: r.realizedLoss.sum,
metric: r.realizedLoss.height,
name: "Loss",
color: colors.loss,
unit: Unit.usd,
@@ -547,13 +547,13 @@ function realizedPnlSum(tree) {
defaultActive: false,
}),
baseline({
metric: r.realizedProfitRelToRealizedCap.sum,
metric: r.realizedProfitRelToRealizedCap,
name: "Profit",
color: colors.profit,
unit: Unit.pctRcap,
}),
baseline({
metric: r.realizedLossRelToRealizedCap.sum,
metric: r.realizedLossRelToRealizedCap,
name: "Loss",
color: colors.loss,
unit: Unit.pctRcap,
@@ -575,13 +575,13 @@ function realizedNetPnlSum(tree) {
unit: Unit.usd,
}),
dotsBaseline({
metric: r.netRealizedPnl.sum,
metric: r.netRealizedPnl.height,
name: "Net",
unit: Unit.usd,
defaultActive: false,
}),
baseline({
metric: r.netRealizedPnlRelToRealizedCap.sum,
metric: r.netRealizedPnlRelToRealizedCap,
name: "Net",
unit: Unit.pctRcap,
}),
@@ -609,20 +609,20 @@ function realizedPnlCumulative(tree) {
unit: Unit.usd,
}),
line({
metric: r.negRealizedLoss.cumulative,
metric: r.negRealizedLoss,
name: "Negative Loss",
color: colors.loss,
unit: Unit.usd,
defaultActive: false,
}),
baseline({
metric: r.realizedProfitRelToRealizedCap.cumulative,
metric: r.realizedProfitRelToRealizedCap,
name: "Profit",
color: colors.profit,
unit: Unit.pctRcap,
}),
baseline({
metric: r.realizedLossRelToRealizedCap.cumulative,
metric: r.realizedLossRelToRealizedCap,
name: "Loss",
color: colors.loss,
unit: Unit.pctRcap,
@@ -644,7 +644,7 @@ function realizedNetPnlCumulative(tree) {
unit: Unit.usd,
}),
baseline({
metric: r.netRealizedPnlRelToRealizedCap.cumulative,
metric: r.netRealizedPnlRelToRealizedCap,
name: "Net",
unit: Unit.pctRcap,
}),
@@ -704,13 +704,13 @@ function sentInPnlTree(tree, title) {
}),
...satsBtcUsdFrom({
source: r.sentInProfit,
key: "sum",
key: "base",
name: "In Profit",
color: colors.profit,
}),
...satsBtcUsdFrom({
source: r.sentInLoss,
key: "sum",
key: "base",
name: "In Loss",
color: colors.loss,
}),
@@ -945,7 +945,7 @@ function realizedSubfolder(tree, title, rollingTree) {
title: title("Realized Peak Regret"),
bottom: [
line({
metric: r.peakRegret.sum,
metric: r.peakRegret.height,
name: "Peak Regret",
unit: Unit.usd,
}),
@@ -1839,7 +1839,7 @@ function groupedRealizedPnlSum(list, all, title) {
title: title("Realized Profit"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({
metric: tree.realized.realizedProfit.sum,
metric: tree.realized.realizedProfit.height,
name,
color,
unit: Unit.usd,
@@ -1851,7 +1851,7 @@ function groupedRealizedPnlSum(list, all, title) {
title: title("Realized Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({
metric: tree.realized.negRealizedLoss.sum,
metric: tree.realized.negRealizedLoss,
name,
color,
unit: Unit.usd,
@@ -1936,7 +1936,7 @@ function groupedRealizedPnlCumulative(list, all, title) {
title: title("Cumulative Realized Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({
metric: tree.realized.negRealizedLoss.cumulative,
metric: tree.realized.realizedLoss.cumulative,
name,
color,
unit: Unit.usd,
@@ -1973,7 +1973,7 @@ function groupedSentInPnl(list, all, title) {
...flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsdFrom({
source: tree.realized.sentInProfit,
key: "sum",
key: "base",
name,
color,
}),
@@ -1995,7 +1995,7 @@ function groupedSentInPnl(list, all, title) {
...flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsdFrom({
source: tree.realized.sentInLoss,
key: "sum",
key: "base",
name,
color,
}),
@@ -2104,7 +2104,7 @@ function groupedRealizedSubfolder(list, all, title) {
title: title("Net Realized P&L"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({
metric: tree.realized.netRealizedPnl.sum,
metric: tree.realized.netRealizedPnl.height,
name,
color,
unit: Unit.usd,
@@ -2166,7 +2166,7 @@ function groupedRealizedSubfolderWithExtras(list, all, title) {
title: title("Net Realized P&L"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({
metric: tree.realized.netRealizedPnl.sum,
metric: tree.realized.netRealizedPnl.height,
name,
color,
unit: Unit.usd,

View File

@@ -76,7 +76,7 @@ export function createValuationSectionFull({ cohort, title }) {
createRatioChart({
title,
pricePattern: tree.realized.realizedPrice,
ratio: tree.realized.realizedPriceExtra,
ratio: { ...tree.realized.realizedPriceExtra, ...tree.realized.realizedPriceRatioExt },
color,
name: "MVRV",
}),

View File

@@ -9,11 +9,11 @@ import {
dots,
dotted,
distributionBtcSatsUsd,
rollingWindowsTree,
} from "./series.js";
import {
satsBtcUsd,
satsBtcUsdFrom,
satsBtcUsdFromFull,
revenueBtcSatsUsd,
} from "./shared.js";
import { brk } from "../client.js";
@@ -53,7 +53,7 @@ const ANTPOOL_AND_FRIENDS_IDS = /** @type {const} */ ([
* @returns {PartialOptionsGroup}
*/
export function createMiningSection() {
const { blocks, transactions, pools, mining } = brk.metrics;
const { blocks, pools, mining } = brk.metrics;
// Pre-compute pool entries with resolved names
const poolData = entries(pools.vecs).map(([id, pool]) => ({
@@ -116,44 +116,17 @@ export function createMiningSection() {
name: "Blocks Mined",
tree: [
{
name: "Sum",
name: "Base",
title: `Blocks Mined: ${name}`,
bottom: [
line({
metric: pool.blocksMined.sum,
name: "sum",
metric: pool.blocksMined.height,
name: "base",
unit: Unit.count,
}),
line({
metric: pool.blocksMined24hSum,
name: "24h",
color: colors.time._24h,
unit: Unit.count,
defaultActive: false,
}),
line({
metric: pool.blocksMined1wSum,
name: "1w",
color: colors.time._1w,
unit: Unit.count,
defaultActive: false,
}),
line({
metric: pool.blocksMined1mSum,
name: "1m",
color: colors.time._1m,
unit: Unit.count,
defaultActive: false,
}),
line({
metric: pool.blocksMined1ySum,
name: "1y",
color: colors.time._1y,
unit: Unit.count,
defaultActive: false,
}),
],
},
rollingWindowsTree({ windows: pool.blocksMined.sum, title: `Blocks Mined: ${name}`, unit: Unit.count }),
{
name: "Cumulative",
title: `Blocks Mined: ${name} (Total)`,
@@ -177,7 +150,7 @@ export function createMiningSection() {
coinbase: pool.coinbase,
subsidy: pool.subsidy,
fee: pool.fee,
key: "sum",
key: "base",
}),
},
{
@@ -372,8 +345,8 @@ export function createMiningSection() {
bottom: revenueBtcSatsUsd({
coinbase: mining.rewards.coinbase,
subsidy: mining.rewards.subsidy,
fee: transactions.fees.fee,
key: "sum",
fee: mining.rewards.fees,
key: "base",
}),
},
{
@@ -382,7 +355,7 @@ export function createMiningSection() {
bottom: revenueBtcSatsUsd({
coinbase: mining.rewards.coinbase,
subsidy: mining.rewards.subsidy,
fee: transactions.fees.fee,
fee: mining.rewards.fees,
key: "cumulative",
}),
},
@@ -394,24 +367,11 @@ export function createMiningSection() {
{
name: "Sum",
title: "Coinbase Rewards",
bottom: [
...satsBtcUsdFromFull({
source: mining.rewards.coinbase,
key: "base",
name: "sum",
}),
...satsBtcUsdFrom({
source: mining.rewards.coinbase,
key: "sum",
name: "sum",
}),
...satsBtcUsd({
pattern: mining.rewards.coinbase24hSum,
name: "24h",
color: colors.time._24h,
defaultActive: false,
}),
],
bottom: satsBtcUsdFrom({
source: mining.rewards.coinbase,
key: "base",
name: "sum",
}),
},
{
name: "Rolling",
@@ -421,22 +381,22 @@ export function createMiningSection() {
title: "Coinbase Rolling Sum",
bottom: [
...satsBtcUsd({
pattern: mining.rewards.coinbase24hSum,
pattern: mining.rewards.coinbase._24h.sum,
name: "24h",
color: colors.time._24h,
}),
...satsBtcUsd({
pattern: mining.rewards.coinbase7dSum,
pattern: mining.rewards.coinbase._7d.sum,
name: "7d",
color: colors.time._1w,
}),
...satsBtcUsd({
pattern: mining.rewards.coinbase30dSum,
pattern: mining.rewards.coinbase._30d.sum,
name: "30d",
color: colors.time._1m,
}),
...satsBtcUsd({
pattern: mining.rewards.coinbase1ySum,
pattern: mining.rewards.coinbase._1y.sum,
name: "1y",
color: colors.time._1y,
}),
@@ -446,7 +406,7 @@ export function createMiningSection() {
name: "24h",
title: "Coinbase 24h Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.coinbase24hSum,
pattern: mining.rewards.coinbase._24h.sum,
name: "24h",
color: colors.time._24h,
}),
@@ -455,7 +415,7 @@ export function createMiningSection() {
name: "7d",
title: "Coinbase 7d Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.coinbase7dSum,
pattern: mining.rewards.coinbase._7d.sum,
name: "7d",
color: colors.time._1w,
}),
@@ -464,7 +424,7 @@ export function createMiningSection() {
name: "30d",
title: "Coinbase 30d Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.coinbase30dSum,
pattern: mining.rewards.coinbase._30d.sum,
name: "30d",
color: colors.time._1m,
}),
@@ -473,7 +433,7 @@ export function createMiningSection() {
name: "1y",
title: "Coinbase 1y Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.coinbase1ySum,
pattern: mining.rewards.coinbase._1y.sum,
name: "1y",
color: colors.time._1y,
}),
@@ -483,7 +443,7 @@ export function createMiningSection() {
{
name: "Distribution",
title: "Coinbase Rewards per Block Distribution",
bottom: distributionBtcSatsUsd(mining.rewards.coinbase),
bottom: distributionBtcSatsUsd(mining.rewards.coinbase._24h),
},
{
name: "Cumulative",
@@ -503,14 +463,9 @@ export function createMiningSection() {
name: "Sum",
title: "Block Subsidy",
bottom: [
...satsBtcUsdFromFull({
source: mining.rewards.subsidy,
key: "base",
name: "sum",
}),
...satsBtcUsdFrom({
source: mining.rewards.subsidy,
key: "sum",
key: "base",
name: "sum",
}),
line({
@@ -522,10 +477,77 @@ export function createMiningSection() {
}),
],
},
{
name: "Rolling",
tree: [
{
name: "Compare",
title: "Subsidy Rolling Sum",
bottom: [
...satsBtcUsd({
pattern: mining.rewards.subsidy._24h.sum,
name: "24h",
color: colors.time._24h,
}),
...satsBtcUsd({
pattern: mining.rewards.subsidy._7d.sum,
name: "7d",
color: colors.time._1w,
}),
...satsBtcUsd({
pattern: mining.rewards.subsidy._30d.sum,
name: "30d",
color: colors.time._1m,
}),
...satsBtcUsd({
pattern: mining.rewards.subsidy._1y.sum,
name: "1y",
color: colors.time._1y,
}),
],
},
{
name: "24h",
title: "Subsidy 24h Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.subsidy._24h.sum,
name: "24h",
color: colors.time._24h,
}),
},
{
name: "7d",
title: "Subsidy 7d Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.subsidy._7d.sum,
name: "7d",
color: colors.time._1w,
}),
},
{
name: "30d",
title: "Subsidy 30d Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.subsidy._30d.sum,
name: "30d",
color: colors.time._1m,
}),
},
{
name: "1y",
title: "Subsidy 1y Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.subsidy._1y.sum,
name: "1y",
color: colors.time._1y,
}),
},
],
},
{
name: "Distribution",
title: "Block Subsidy Distribution",
bottom: distributionBtcSatsUsd(mining.rewards.subsidy),
bottom: distributionBtcSatsUsd(mining.rewards.subsidy._24h),
},
{
name: "Cumulative",
@@ -545,8 +567,8 @@ export function createMiningSection() {
name: "Sum",
title: "Transaction Fee Revenue per Block",
bottom: satsBtcUsdFrom({
source: transactions.fees.fee,
key: "sum",
source: mining.rewards.fees,
key: "base",
name: "sum",
}),
},
@@ -558,22 +580,22 @@ export function createMiningSection() {
title: "Fee Rolling Sum",
bottom: [
...satsBtcUsd({
pattern: mining.rewards.fee24hSum,
pattern: mining.rewards.fees._24h.sum,
name: "24h",
color: colors.time._24h,
}),
...satsBtcUsd({
pattern: mining.rewards.fee7dSum,
pattern: mining.rewards.fees._7d.sum,
name: "7d",
color: colors.time._1w,
}),
...satsBtcUsd({
pattern: mining.rewards.fee30dSum,
pattern: mining.rewards.fees._30d.sum,
name: "30d",
color: colors.time._1m,
}),
...satsBtcUsd({
pattern: mining.rewards.fee1ySum,
pattern: mining.rewards.fees._1y.sum,
name: "1y",
color: colors.time._1y,
}),
@@ -583,7 +605,7 @@ export function createMiningSection() {
name: "24h",
title: "Fee 24h Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.fee24hSum,
pattern: mining.rewards.fees._24h.sum,
name: "24h",
color: colors.time._24h,
}),
@@ -592,7 +614,7 @@ export function createMiningSection() {
name: "7d",
title: "Fee 7d Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.fee7dSum,
pattern: mining.rewards.fees._7d.sum,
name: "7d",
color: colors.time._1w,
}),
@@ -601,7 +623,7 @@ export function createMiningSection() {
name: "30d",
title: "Fee 30d Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.fee30dSum,
pattern: mining.rewards.fees._30d.sum,
name: "30d",
color: colors.time._1m,
}),
@@ -610,7 +632,7 @@ export function createMiningSection() {
name: "1y",
title: "Fee 1y Rolling Sum",
bottom: satsBtcUsd({
pattern: mining.rewards.fee1ySum,
pattern: mining.rewards.fees._1y.sum,
name: "1y",
color: colors.time._1y,
}),
@@ -620,13 +642,13 @@ export function createMiningSection() {
{
name: "Distribution",
title: "Transaction Fee Revenue per Block Distribution",
bottom: distributionBtcSatsUsd(transactions.fees.fee),
bottom: distributionBtcSatsUsd(mining.rewards.fees._24h),
},
{
name: "Cumulative",
title: "Transaction Fee Revenue (Total)",
bottom: satsBtcUsdFrom({
source: transactions.fees.fee,
source: mining.rewards.fees,
key: "cumulative",
name: "all-time",
}),
@@ -813,7 +835,7 @@ export function createMiningSection() {
title: "Unclaimed Rewards",
bottom: satsBtcUsdFrom({
source: mining.rewards.unclaimedRewards,
key: "sum",
key: "base",
name: "sum",
}),
},
@@ -988,7 +1010,7 @@ export function createMiningSection() {
bottom: majorPools.flatMap((p, i) =>
satsBtcUsdFrom({
source: p.pool.coinbase,
key: "sum",
key: "base",
name: p.name,
color: colors.at(i, majorPools.length),
}),
@@ -1030,7 +1052,7 @@ export function createMiningSection() {
bottom: antpoolFriends.flatMap((p, i) =>
satsBtcUsdFrom({
source: p.pool.coinbase,
key: "sum",
key: "base",
name: p.name,
color: colors.at(i, antpoolFriends.length),
}),

View File

@@ -12,9 +12,12 @@ import {
fromSupplyPattern,
fromBaseStatsPattern,
chartsFromFullPerBlock,
chartsFromCount,
chartsFromValueFull,
fromStatsPattern,
chartsFromSumPerBlock,
statsAtWindow,
rollingWindowsTree,
} from "./series.js";
import { satsBtcUsd, satsBtcUsdFrom } from "./shared.js";
@@ -204,17 +207,34 @@ export function createNetworkSection() {
},
{
name: "New",
tree: chartsFromFullPerBlock({
pattern: distribution.newAddrCount[key],
title: `${titlePrefix}New Address Count`,
unit: Unit.count,
}),
tree: (() => {
const p = distribution.newAddrCount[key];
const t = `${titlePrefix}New Address Count`;
return [
{
name: "Sum",
title: t,
bottom: [
line({ metric: p.base, name: "base", unit: Unit.count }),
],
},
rollingWindowsTree({ windows: p.rest.sum, title: t, unit: Unit.count }),
{
name: "Cumulative",
title: `${t} (Total)`,
bottom: [
line({ metric: p.rest.cumulative, name: "all-time", unit: Unit.count }),
],
},
];
})(),
},
{
name: "Reactivated",
title: `${titlePrefix}Reactivated Addresses per Block`,
bottom: fromBaseStatsPattern({
pattern: distribution.addressActivity[key].reactivated,
window: "_24h",
unit: Unit.count,
}),
},
@@ -223,6 +243,7 @@ export function createNetworkSection() {
title: `${titlePrefix}Address Growth Rate per Block`,
bottom: fromBaseStatsPattern({
pattern: distribution.growthRate[key],
window: "_24h",
unit: Unit.ratio,
}),
},
@@ -235,6 +256,7 @@ export function createNetworkSection() {
title: `${titlePrefix}${t.title}`,
bottom: fromBaseStatsPattern({
pattern: distribution.addressActivity[key][t.key],
window: "_24h",
unit: Unit.count,
}),
})),
@@ -246,6 +268,7 @@ export function createNetworkSection() {
title: `${titlePrefix}${b.title}`,
bottom: fromBaseStatsPattern({
pattern: distribution.addressActivity[key][b.key],
window: "_24h",
unit: Unit.count,
}),
})),
@@ -287,7 +310,7 @@ export function createNetworkSection() {
unit: Unit.count,
}),
line({
metric: distribution.newAddrCount[t.key].sum,
metric: distribution.newAddrCount[t.key].rest.sum._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -299,13 +322,14 @@ export function createNetworkSection() {
title: `${groupName} Reactivated Addresses per Block`,
bottom: types.flatMap((t) => [
line({
metric: distribution.addressActivity[t.key].reactivated.base,
metric: distribution.addressActivity[t.key].reactivated.height,
name: t.name,
color: t.color,
unit: Unit.count,
}),
line({
metric: distribution.addressActivity[t.key].reactivated.average,
metric:
distribution.addressActivity[t.key].reactivated.average._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -317,13 +341,13 @@ export function createNetworkSection() {
title: `${groupName} Address Growth Rate per Block`,
bottom: types.flatMap((t) => [
dots({
metric: distribution.growthRate[t.key].base,
metric: distribution.growthRate[t.key].height,
name: t.name,
color: t.color,
unit: Unit.ratio,
}),
dots({
metric: distribution.growthRate[t.key].average,
metric: distribution.growthRate[t.key].average._24h,
name: t.name,
color: t.color,
unit: Unit.ratio,
@@ -337,13 +361,14 @@ export function createNetworkSection() {
title: `${groupName} ${tr.compareTitle}`,
bottom: types.flatMap((t) => [
line({
metric: distribution.addressActivity[t.key][tr.key].base,
metric: distribution.addressActivity[t.key][tr.key].height,
name: t.name,
color: t.color,
unit: Unit.count,
}),
line({
metric: distribution.addressActivity[t.key][tr.key].average,
metric:
distribution.addressActivity[t.key][tr.key].average._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -358,13 +383,14 @@ export function createNetworkSection() {
title: `${groupName} ${b.compareTitle}`,
bottom: types.flatMap((t) => [
line({
metric: distribution.addressActivity[t.key][b.key].base,
metric: distribution.addressActivity[t.key][b.key].height,
name: t.name,
color: t.color,
unit: Unit.count,
}),
line({
metric: distribution.addressActivity[t.key][b.key].average,
metric:
distribution.addressActivity[t.key][b.key].average._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -398,7 +424,7 @@ export function createNetworkSection() {
title: `${groupName} Output Count`,
bottom: types.map((t) =>
line({
metric: scripts.count[t.key].sum,
metric: /** @type {CountPattern<number>} */ (scripts.count[t.key]).sum._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -410,7 +436,7 @@ export function createNetworkSection() {
title: `${groupName} Output Count (Total)`,
bottom: types.map((t) =>
line({
metric: scripts.count[t.key].cumulative,
metric: /** @type {CountPattern<number>} */ (scripts.count[t.key]).cumulative,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -454,7 +480,7 @@ export function createNetworkSection() {
title: "Unspendable Supply",
bottom: satsBtcUsdFrom({
source: supply.burned.unspendable,
key: "sum",
key: "base",
name: "sum",
}),
},
@@ -495,7 +521,7 @@ export function createNetworkSection() {
name: "Fee Rate",
title: "Transaction Fee Rate",
bottom: fromStatsPattern({
pattern: transactions.fees.feeRate,
pattern: transactions.fees.feeRate.block,
unit: Unit.feeRate,
}),
},
@@ -532,11 +558,11 @@ export function createNetworkSection() {
title: "Transaction Size",
bottom: [
...fromStatsPattern({
pattern: transactions.size.weight,
pattern: transactions.size.weight.block,
unit: Unit.wu,
}),
...fromStatsPattern({
pattern: transactions.size.vsize,
pattern: transactions.size.vsize.block,
unit: Unit.vb,
}),
],
@@ -545,12 +571,12 @@ export function createNetworkSection() {
name: "Versions",
tree: [
{
name: "Sum",
name: "Base",
title: "Transaction Versions",
bottom: entries(transactions.versions).map(
([v, data], i, arr) =>
line({
metric: data.sum,
metric: data.height,
name: v,
color: colors.at(i, arr.length),
unit: Unit.count,
@@ -600,12 +626,12 @@ export function createNetworkSection() {
name: "Count",
tree: [
{
name: "Sum",
name: "Base",
title: "Block Count",
bottom: [
line({
metric: blocks.count.blockCount.sum,
name: "sum",
metric: blocks.count.blockCount.height,
name: "base",
unit: Unit.count,
}),
line({
@@ -617,36 +643,11 @@ export function createNetworkSection() {
}),
],
},
{
name: "Rolling",
title: "Block Count (Rolling)",
bottom: [
line({
metric: blocks.count.blockCount24hSum,
name: "24h",
color: colors.time._24h,
unit: Unit.count,
}),
line({
metric: blocks.count.blockCount1wSum,
name: "1w",
color: colors.time._1w,
unit: Unit.count,
}),
line({
metric: blocks.count.blockCount1mSum,
name: "1m",
color: colors.time._1m,
unit: Unit.count,
}),
line({
metric: blocks.count.blockCount1ySum,
name: "1y",
color: colors.time._1y,
unit: Unit.count,
}),
],
},
rollingWindowsTree({
windows: blocks.count.blockCountSum,
title: "Block Count",
unit: Unit.count,
}),
{
name: "Cumulative",
title: "Block Count (Total)",
@@ -666,6 +667,7 @@ export function createNetworkSection() {
bottom: [
...fromBaseStatsPattern({
pattern: blocks.interval,
window: "_24h",
unit: Unit.secs,
}),
priceLine({ unit: Unit.secs, name: "Target", number: 600 }),
@@ -675,7 +677,7 @@ export function createNetworkSection() {
name: "Size",
tree: [
{
name: "Sum",
name: "Base",
title: "Block Size",
bottom: [
line({
@@ -683,13 +685,9 @@ export function createNetworkSection() {
name: "base",
unit: Unit.bytes,
}),
line({
metric: blocks.size.sum,
name: "sum",
unit: Unit.bytes,
}),
],
},
rollingWindowsTree({ windows: blocks.size.sum, title: "Block Size", unit: Unit.bytes }),
{
name: "Distribution",
title: "Block Size Distribution",
@@ -700,7 +698,7 @@ export function createNetworkSection() {
unit: Unit.bytes,
}),
...fromStatsPattern({
pattern: blocks.size,
pattern: statsAtWindow(blocks.size, "_24h"),
unit: Unit.bytes,
}),
],
@@ -722,7 +720,7 @@ export function createNetworkSection() {
name: "Weight",
tree: [
{
name: "Sum",
name: "Base",
title: "Block Weight",
bottom: [
line({
@@ -730,13 +728,9 @@ export function createNetworkSection() {
name: "base",
unit: Unit.wu,
}),
line({
metric: blocks.weight.sum,
name: "sum",
unit: Unit.wu,
}),
],
},
rollingWindowsTree({ windows: blocks.weight.sum, title: "Block Weight", unit: Unit.wu }),
{
name: "Distribution",
title: "Block Weight Distribution",
@@ -747,7 +741,7 @@ export function createNetworkSection() {
unit: Unit.wu,
}),
...fromStatsPattern({
pattern: blocks.weight,
pattern: statsAtWindow(blocks.weight, "_24h"),
unit: Unit.wu,
}),
],
@@ -769,32 +763,28 @@ export function createNetworkSection() {
name: "vBytes",
tree: [
{
name: "Sum",
name: "Base",
title: "Block vBytes",
bottom: [
line({
metric: blocks.vbytes.base,
metric: blocks.vbytes.height,
name: "base",
unit: Unit.vb,
}),
line({
metric: blocks.vbytes.sum,
name: "sum",
unit: Unit.vb,
}),
],
},
rollingWindowsTree({ windows: blocks.vbytes.sum, title: "Block vBytes", unit: Unit.vb }),
{
name: "Distribution",
title: "Block vBytes Distribution",
bottom: [
line({
metric: blocks.vbytes.base,
metric: blocks.vbytes.height,
name: "base",
unit: Unit.vb,
}),
...fromStatsPattern({
pattern: blocks.vbytes,
pattern: statsAtWindow(blocks.vbytes, "_24h"),
unit: Unit.vb,
}),
],
@@ -817,6 +807,7 @@ export function createNetworkSection() {
title: "Block Fullness",
bottom: fromBaseStatsPattern({
pattern: blocks.fullness,
window: "_24h",
unit: Unit.percentage,
}),
},
@@ -949,7 +940,7 @@ export function createNetworkSection() {
defaultActive: t.defaultActive,
}),
line({
metric: distribution.newAddrCount[t.key].sum,
metric: distribution.newAddrCount[t.key].rest.sum._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -963,7 +954,7 @@ export function createNetworkSection() {
bottom: addressTypes.flatMap((t) => [
line({
metric:
distribution.addressActivity[t.key].reactivated.base,
distribution.addressActivity[t.key].reactivated.height,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -971,7 +962,7 @@ export function createNetworkSection() {
}),
line({
metric:
distribution.addressActivity[t.key].reactivated.average,
distribution.addressActivity[t.key].reactivated.average._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -984,14 +975,14 @@ export function createNetworkSection() {
title: "Address Growth Rate per Block by Type",
bottom: addressTypes.flatMap((t) => [
dots({
metric: distribution.growthRate[t.key].base,
metric: distribution.growthRate[t.key].height,
name: t.name,
color: t.color,
unit: Unit.ratio,
defaultActive: t.defaultActive,
}),
dots({
metric: distribution.growthRate[t.key].average,
metric: distribution.growthRate[t.key].average._24h,
name: t.name,
color: t.color,
unit: Unit.ratio,
@@ -1006,7 +997,7 @@ export function createNetworkSection() {
title: tr.compareTitle,
bottom: addressTypes.flatMap((t) => [
line({
metric: distribution.addressActivity[t.key][tr.key].base,
metric: distribution.addressActivity[t.key][tr.key].height,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -1014,7 +1005,7 @@ export function createNetworkSection() {
}),
line({
metric:
distribution.addressActivity[t.key][tr.key].average,
distribution.addressActivity[t.key][tr.key].average._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -1030,7 +1021,7 @@ export function createNetworkSection() {
title: b.compareTitle,
bottom: addressTypes.flatMap((t) => [
line({
metric: distribution.addressActivity[t.key][b.key].base,
metric: distribution.addressActivity[t.key][b.key].height,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -1038,7 +1029,7 @@ export function createNetworkSection() {
}),
line({
metric:
distribution.addressActivity[t.key][b.key].average,
distribution.addressActivity[t.key][b.key].average._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -1104,7 +1095,7 @@ export function createNetworkSection() {
title: "Output Count by Script Type",
bottom: scriptTypes.map((t) =>
line({
metric: scripts.count[t.key].sum,
metric: /** @type {CountPattern<number>} */ (scripts.count[t.key]).sum._24h,
name: t.name,
color: t.color,
unit: Unit.count,
@@ -1133,8 +1124,8 @@ export function createNetworkSection() {
createScriptCompare("Legacy", legacyScripts),
...legacyScripts.map((t) => ({
name: t.name,
tree: chartsFromFullPerBlock({
pattern: scripts.count[t.key],
tree: chartsFromCount({
pattern: /** @type {CountPattern<number>} */ (scripts.count[t.key]),
title: `${t.name} Output Count`,
unit: Unit.count,
}),
@@ -1147,8 +1138,8 @@ export function createNetworkSection() {
createScriptCompare("Script Hash", scriptHashScripts),
...scriptHashScripts.map((t) => ({
name: t.name,
tree: chartsFromFullPerBlock({
pattern: scripts.count[t.key],
tree: chartsFromCount({
pattern: /** @type {CountPattern<number>} */ (scripts.count[t.key]),
title: `${t.name} Output Count`,
unit: Unit.count,
}),
@@ -1161,8 +1152,8 @@ export function createNetworkSection() {
createScriptCompare("SegWit", segwitScripts),
...segwitScripts.map((t) => ({
name: t.name,
tree: chartsFromFullPerBlock({
pattern: scripts.count[t.key],
tree: chartsFromCount({
pattern: /** @type {CountPattern<number>} */ (scripts.count[t.key]),
title: `${t.name} Output Count`,
unit: Unit.count,
}),
@@ -1175,8 +1166,8 @@ export function createNetworkSection() {
createScriptCompare("Taproot", taprootAddresses),
...taprootAddresses.map((t) => ({
name: t.name,
tree: chartsFromFullPerBlock({
pattern: scripts.count[t.key],
tree: chartsFromCount({
pattern: /** @type {CountPattern<number>} */ (scripts.count[t.key]),
title: `${t.name} Output Count`,
unit: Unit.count,
}),
@@ -1189,8 +1180,8 @@ export function createNetworkSection() {
createScriptCompare("Other", otherScripts),
...otherScripts.map((t) => ({
name: t.name,
tree: chartsFromFullPerBlock({
pattern: scripts.count[t.key],
tree: chartsFromCount({
pattern: /** @type {CountPattern<number>} */ (scripts.count[t.key]),
title: `${t.name} Output Count`,
unit: Unit.count,
}),
@@ -1207,13 +1198,13 @@ export function createNetworkSection() {
title: "Script Adoption",
bottom: [
line({
metric: scripts.count.segwitAdoption.cumulative,
metric: scripts.adoption.segwit,
name: "SegWit",
color: colors.segwit,
unit: Unit.percentage,
}),
line({
metric: scripts.count.taprootAdoption.cumulative,
metric: scripts.adoption.taproot,
name: "Taproot",
color: taprootAddresses[1].color,
unit: Unit.percentage,
@@ -1225,19 +1216,8 @@ export function createNetworkSection() {
title: "SegWit Adoption",
bottom: [
line({
metric: scripts.count.segwitAdoption.base,
name: "Base",
unit: Unit.percentage,
}),
line({
metric: scripts.count.segwitAdoption.sum,
name: "Sum",
unit: Unit.percentage,
}),
line({
metric: scripts.count.segwitAdoption.cumulative,
name: "All-Time",
color: colors.time.all,
metric: scripts.adoption.segwit,
name: "Adoption",
unit: Unit.percentage,
}),
],
@@ -1247,19 +1227,8 @@ export function createNetworkSection() {
title: "Taproot Adoption",
bottom: [
line({
metric: scripts.count.taprootAdoption.base,
name: "Base",
unit: Unit.percentage,
}),
line({
metric: scripts.count.taprootAdoption.sum,
name: "Sum",
unit: Unit.percentage,
}),
line({
metric: scripts.count.taprootAdoption.cumulative,
name: "All-Time",
color: colors.time.all,
metric: scripts.adoption.taproot,
name: "Adoption",
unit: Unit.percentage,
}),
],

View File

@@ -47,7 +47,7 @@ export function price({
/**
* Create percentile series (max/min/median/pct75/pct25/pct90/pct10) from any stats pattern
* @param {StatsPattern<any> | BaseStatsPattern<any> | FullStatsPattern<any> | AnyStatsPattern} pattern
* @param {DistributionStats} pattern
* @param {Unit} unit
* @param {string} title
* @returns {AnyFetchedSeriesBlueprint[]}
@@ -356,9 +356,10 @@ export function histogram({
}
/**
* Create series from a BaseStatsPattern (base + avg + percentiles, NO sum)
* Create series from an AverageHeightMaxMedianMinP10P25P75P90Pattern (height + rolling stats)
* @param {Object} args
* @param {BaseStatsPattern<any>} args.pattern
* @param {{ height: AnyMetricPattern } & Record<string, any>} args.pattern - Pattern with .height and rolling stats (p10/p25/p75/p90 as _1y24h30d7dPattern)
* @param {string} args.window - Rolling window key (e.g., '_24h', '_7d', '_30d', '_1y')
* @param {Unit} args.unit
* @param {string} [args.title]
* @param {Color} [args.baseColor]
@@ -367,34 +368,37 @@ export function histogram({
*/
export function fromBaseStatsPattern({
pattern,
window,
unit,
title = "",
baseColor,
avgActive = true,
}) {
const { stat } = colors;
const stats = statsAtWindow(pattern, window);
return [
dots({
metric: pattern.base,
metric: pattern.height,
name: title || "base",
color: baseColor,
unit,
}),
dots({
metric: pattern.average,
metric: stats.average,
name: `${title} avg`.trim(),
color: stat.avg,
unit,
defaultActive: avgActive,
}),
...percentileSeries(pattern, unit, title),
...percentileSeries(stats, unit, title),
];
}
/**
* Create series from any pattern with avg + percentiles (works with StatsPattern, SumStatsPattern, etc.)
* Create series from a flat stats pattern (average + pct percentiles as single metrics)
* Use statsAtWindow() to extract from patterns with _1y24h30d7dPattern stats
* @param {Object} args
* @param {StatsPattern<any> | BaseStatsPattern<any> | FullStatsPattern<any> | AnyStatsPattern} args.pattern
* @param {{ average: AnyMetricPattern, median: AnyMetricPattern, max: AnyMetricPattern, min: AnyMetricPattern, pct75: AnyMetricPattern, pct25: AnyMetricPattern, pct90: AnyMetricPattern, pct10: AnyMetricPattern }} args.pattern
* @param {Unit} args.unit
* @param {string} [args.title]
* @returns {AnyFetchedSeriesBlueprint[]}
@@ -412,14 +416,96 @@ export function fromStatsPattern({ pattern, unit, title = "" }) {
}
/**
* Create distribution series for btc/sats/usd from a value pattern with stats (average + percentiles)
* @param {FullValuePattern | SumValuePattern} source
* Extract stats at a specific rolling window from patterns with _1y24h30d7dPattern stats
* @param {Record<string, any>} pattern - Pattern with pct10/pct25/pct75/pct90 and average/median/max/min as _1y24h30d7dPattern
* @param {string} window
*/
export function statsAtWindow(pattern, window) {
return {
average: pattern.average[window],
median: pattern.median[window],
max: pattern.max[window],
min: pattern.min[window],
pct75: pattern.pct75[window],
pct25: pattern.pct25[window],
pct90: pattern.pct90[window],
pct10: pattern.pct10[window],
};
}
/**
* Create a Rolling folder tree from a _1y24h30d7dPattern (4 rolling windows)
* @param {Object} args
* @param {{ _24h: AnyMetricPattern, _7d: AnyMetricPattern, _30d: AnyMetricPattern, _1y: AnyMetricPattern }} args.windows
* @param {string} args.title
* @param {Unit} args.unit
* @returns {PartialOptionsGroup}
*/
export function rollingWindowsTree({ windows, title, unit }) {
return {
name: "Rolling",
tree: [
{
name: "Compare",
title: `${title} Rolling`,
bottom: [
line({ metric: windows._24h, name: "24h", color: colors.time._24h, unit }),
line({ metric: windows._7d, name: "7d", color: colors.time._1w, unit }),
line({ metric: windows._30d, name: "30d", color: colors.time._1m, unit }),
line({ metric: windows._1y, name: "1y", color: colors.time._1y, unit }),
],
},
{
name: "24h",
title: `${title} 24h`,
bottom: [line({ metric: windows._24h, name: "24h", color: colors.time._24h, unit })],
},
{
name: "7d",
title: `${title} 7d`,
bottom: [line({ metric: windows._7d, name: "7d", color: colors.time._1w, unit })],
},
{
name: "30d",
title: `${title} 30d`,
bottom: [line({ metric: windows._30d, name: "30d", color: colors.time._1m, unit })],
},
{
name: "1y",
title: `${title} 1y`,
bottom: [line({ metric: windows._1y, name: "1y", color: colors.time._1y, unit })],
},
],
};
}
/**
* Map a rolling window slot's stats to a specific unit, producing a stats-compatible pattern
* @param {RollingWindowSlot} slot - Rolling window slot (e.g., pattern.rolling._24h)
* @param {BtcSatsUsdKey} unitKey
*/
function rollingSlotForUnit(slot, unitKey) {
return {
average: slot.average[unitKey],
median: slot.median[unitKey],
max: slot.max[unitKey],
min: slot.min[unitKey],
pct75: slot.pct75[unitKey],
pct25: slot.pct25[unitKey],
pct90: slot.pct90[unitKey],
pct10: slot.pct10[unitKey],
};
}
/**
* Create distribution series for btc/sats/usd from a rolling window slot
* @param {RollingWindowSlot} slot - Rolling window slot (e.g., pattern.rolling._24h)
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export const distributionBtcSatsUsd = (source) => [
...fromStatsPattern({ pattern: source.btc, unit: Unit.btc }),
...fromStatsPattern({ pattern: source.sats, unit: Unit.sats }),
...fromStatsPattern({ pattern: source.usd, unit: Unit.usd }),
export const distributionBtcSatsUsd = (slot) => [
...fromStatsPattern({ pattern: rollingSlotForUnit(slot, "btc"), unit: Unit.btc }),
...fromStatsPattern({ pattern: rollingSlotForUnit(slot, "sats"), unit: Unit.sats }),
...fromStatsPattern({ pattern: rollingSlotForUnit(slot, "usd"), unit: Unit.usd }),
];
/**
@@ -460,7 +546,7 @@ export function fromSupplyPattern({ pattern, title, color }) {
/**
* Create distribution series (avg + percentiles)
* @param {StatsPattern<any> | BaseStatsPattern<any> | FullStatsPattern<any> | AnyStatsPattern} pattern
* @param {DistributionStats} pattern
* @param {Unit} unit
* @returns {AnyFetchedSeriesBlueprint[]}
*/
@@ -556,9 +642,10 @@ function btcSatsUsdSeries({ metrics, name, color, defaultActive }) {
}
/**
* Split pattern with base + sum + distribution + cumulative into 3 charts
* Split flat per-block pattern into charts (Sum/Rolling/Distribution/Cumulative)
* Pattern has: .height, .cumulative, .sum (windowed), .average/.pct10/... (windowed, flat)
* @param {Object} args
* @param {FullStatsPattern<any>} args.pattern
* @param {FullPerBlockPattern} args.pattern
* @param {string} args.title
* @param {Unit} args.unit
* @param {string} [args.distributionSuffix]
@@ -577,15 +664,13 @@ export function chartsFromFull({
{
name: "Sum",
title,
bottom: [
{ metric: pattern.base, title: "sum", unit },
{ metric: pattern.sum, title: "sum", unit },
],
bottom: [{ metric: pattern.height, title: "base", unit }],
},
rollingWindowsTree({ windows: pattern.sum, title, unit }),
{
name: "Distribution",
title: distTitle,
bottom: distributionSeries(pattern, unit),
bottom: distributionSeries(statsAtWindow(pattern, "_24h"), unit),
},
{
name: "Cumulative",
@@ -596,9 +681,9 @@ export function chartsFromFull({
}
/**
* Split pattern into 3 charts with "per Block" in distribution title
* Split pattern into 4 charts with "per Block" in distribution title
* @param {Object} args
* @param {FullStatsPattern<any>} args.pattern
* @param {FullPerBlockPattern} args.pattern
* @param {string} args.title
* @param {Unit} args.unit
* @returns {PartialOptionsTree}
@@ -609,7 +694,7 @@ export const chartsFromFullPerBlock = (args) =>
/**
* Split pattern with sum + distribution + cumulative into 3 charts (no base)
* @param {Object} args
* @param {AnyStatsPattern} args.pattern
* @param {FullStatsPattern} args.pattern
* @param {string} args.title
* @param {Unit} args.unit
* @param {string} [args.distributionSuffix]
@@ -647,7 +732,7 @@ export function chartsFromSum({
/**
* Split pattern into 3 charts with "per Block" in distribution title (no base)
* @param {Object} args
* @param {AnyStatsPattern} args.pattern
* @param {FullStatsPattern} args.pattern
* @param {string} args.title
* @param {Unit} args.unit
* @returns {PartialOptionsTree}
@@ -656,7 +741,7 @@ export const chartsFromSumPerBlock = (args) =>
chartsFromSum({ ...args, distributionSuffix: "per Block" });
/**
* Split pattern with sum + cumulative into 2 charts
* Split pattern with rolling sum windows + cumulative into charts
* @param {Object} args
* @param {CountPattern<any>} args.pattern
* @param {string} args.title
@@ -666,11 +751,7 @@ export const chartsFromSumPerBlock = (args) =>
*/
export function chartsFromCount({ pattern, title, unit, color }) {
return [
{
name: "Sum",
title,
bottom: [{ metric: pattern.sum, title: "sum", color, unit }],
},
rollingWindowsTree({ windows: pattern.sum, title, unit }),
{
name: "Cumulative",
title: `${title} (Total)`,
@@ -680,46 +761,7 @@ export function chartsFromCount({ pattern, title, unit, color }) {
}
/**
* Split value pattern (btc/sats/usd with sum + cumulative) into 2 charts
* @param {Object} args
* @param {ValuePattern} args.pattern
* @param {string} args.title
* @param {Color} [args.color]
* @returns {PartialOptionsTree}
*/
export function chartsFromValue({ pattern, title, color }) {
return [
{
name: "Sum",
title,
bottom: btcSatsUsdSeries({
metrics: {
btc: pattern.btc.sum,
sats: pattern.sats.sum,
usd: pattern.usd.sum,
},
name: "sum",
color,
}),
},
{
name: "Cumulative",
title: `${title} (Total)`,
bottom: btcSatsUsdSeries({
metrics: {
btc: pattern.btc.cumulative,
sats: pattern.sats.cumulative,
usd: pattern.usd.cumulative,
},
name: "all-time",
color,
}),
},
];
}
/**
* Split btc/sats/usd pattern with full stats into 3 charts
* Split BaseCumulativeRollingPattern into 3 charts (Sum/Distribution/Cumulative)
* @param {Object} args
* @param {CoinbasePattern} args.pattern
* @param {string} args.title
@@ -731,44 +773,23 @@ export function chartsFromValueFull({ pattern, title }) {
name: "Sum",
title,
bottom: [
...btcSatsUsdSeries({ metrics: pattern.base, name: "sum" }),
...btcSatsUsdSeries({
metrics: {
btc: pattern.btc.base,
sats: pattern.sats.base,
usd: pattern.usd.base,
},
name: "sum",
}),
...btcSatsUsdSeries({
metrics: {
btc: pattern.btc.sum,
sats: pattern.sats.sum,
usd: pattern.usd.sum,
},
name: "sum",
metrics: pattern._24h.sum,
name: "24h sum",
defaultActive: false,
}),
],
},
{
name: "Distribution",
title: `${title} Distribution`,
bottom: [
...distributionSeries(pattern.btc, Unit.btc),
...distributionSeries(pattern.sats, Unit.sats),
...distributionSeries(pattern.usd, Unit.usd),
],
bottom: distributionBtcSatsUsd(pattern._24h),
},
{
name: "Cumulative",
title: `${title} (Total)`,
bottom: btcSatsUsdSeries({
metrics: {
btc: pattern.btc.cumulative,
sats: pattern.sats.cumulative,
usd: pattern.usd.cumulative,
},
name: "all-time",
}),
bottom: btcSatsUsdSeries({ metrics: pattern.cumulative, name: "all-time" }),
},
];
}

View File

@@ -146,10 +146,10 @@ export function satsBtcUsdBaseline({ pattern, name, color, defaultActive }) {
}
/**
* Create sats/btc/usd series from any value pattern using sum or cumulative key
* Create sats/btc/usd series from any value pattern using base or cumulative key
* @param {Object} args
* @param {AnyValuePatternType} args.source
* @param {'sum' | 'cumulative'} args.key
* @param {'base' | 'cumulative'} args.key
* @param {string} args.name
* @param {Color} [args.color]
* @param {boolean} [args.defaultActive]
@@ -157,11 +157,7 @@ export function satsBtcUsdBaseline({ pattern, name, color, defaultActive }) {
*/
export function satsBtcUsdFrom({ source, key, name, color, defaultActive }) {
return satsBtcUsd({
pattern: {
btc: source.btc[key],
sats: source.sats[key],
usd: source.usd[key],
},
pattern: source[key],
name,
color,
defaultActive,
@@ -169,10 +165,10 @@ export function satsBtcUsdFrom({ source, key, name, color, defaultActive }) {
}
/**
* Create sats/btc/usd series from a full value pattern using base or average key
* Create sats/btc/usd series from a full value pattern using base or cumulative key
* @param {Object} args
* @param {FullValuePattern} args.source
* @param {'base' | 'average'} args.key
* @param {'base' | 'cumulative'} args.key
* @param {string} args.name
* @param {Color} [args.color]
* @param {boolean} [args.defaultActive]
@@ -186,11 +182,7 @@ export function satsBtcUsdFromFull({
defaultActive,
}) {
return satsBtcUsd({
pattern: {
btc: source.btc[key],
sats: source.sats[key],
usd: source.usd[key],
},
pattern: source[key],
name,
color,
defaultActive,
@@ -203,7 +195,7 @@ export function satsBtcUsdFromFull({
* @param {AnyValuePatternType} args.coinbase
* @param {AnyValuePatternType} args.subsidy
* @param {AnyValuePatternType} args.fee
* @param {'sum' | 'cumulative'} args.key
* @param {'base' | 'cumulative'} args.key
* @returns {FetchedLineSeriesBlueprint[]}
*/
export function revenueBtcSatsUsd({ coinbase, subsidy, fee, key }) {
@@ -229,6 +221,47 @@ export function revenueBtcSatsUsd({ coinbase, subsidy, fee, key }) {
];
}
/**
* Create sats/btc/usd series from a rolling window (24h/7d/30d/1y sum)
* @param {Object} args
* @param {AnyValuePattern} args.pattern - A BtcSatsUsdPattern (e.g., source.rolling._24h.sum)
* @param {string} args.name
* @param {Color} [args.color]
* @param {boolean} [args.defaultActive]
* @returns {FetchedLineSeriesBlueprint[]}
*/
export function satsBtcUsdRolling({ pattern, name, color, defaultActive }) {
return satsBtcUsd({ pattern, name, color, defaultActive });
}
/**
* Create coinbase/subsidy/fee rolling sum series from separate sources
* @param {Object} args
* @param {AnyValuePattern} args.coinbase - Rolling sum pattern (e.g., mining.rewards.coinbase.rolling._24h.sum)
* @param {AnyValuePattern} args.subsidy
* @param {AnyValuePattern} args.fee
* @returns {FetchedLineSeriesBlueprint[]}
*/
export function revenueRollingBtcSatsUsd({ coinbase, subsidy, fee }) {
return [
...satsBtcUsd({
pattern: coinbase,
name: "Coinbase",
color: colors.mining.coinbase,
}),
...satsBtcUsd({
pattern: subsidy,
name: "Subsidy",
color: colors.mining.subsidy,
}),
...satsBtcUsd({
pattern: fee,
name: "Fees",
color: colors.mining.fee,
}),
];
}
/**
* Build percentile USD mappings from a ratio pattern
* @param {AnyRatioPattern} ratio

View File

@@ -163,9 +163,8 @@
* - AgeRangePattern (ageRange.*)
* @typedef {LongTermPattern | AgeRangePattern} PatternWithPercentiles
*
* Patterns with RelToMarketCap in relative (RelativePattern):
* - BasicUtxoPattern (minAge.*, geAmount.*, ltAmount.*)
* @typedef {BasicUtxoPattern} PatternBasicWithMarketCap
* Patterns with RelToMarketCap in relative (geAmount.*, ltAmount.*):
* @typedef {UtxoAmountPattern | AddressAmountPattern} PatternBasicWithMarketCap
*
* Patterns without RelToMarketCap in relative (RelativePattern4):
* - EpochPattern (epoch.*, amountRange.*, year.*, type.*)