mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-22 04:18:50 -07:00
global: metrics -> series rename
This commit is contained in:
@@ -88,8 +88,8 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
/** @param {ChartableIndex} idx */
|
||||
const getTimeEndpoint = (idx) =>
|
||||
idx === "height"
|
||||
? brk.metrics.blocks.time.timestampMonotonic.by[idx]
|
||||
: brk.metrics.blocks.time.timestamp.by[idx];
|
||||
? brk.series.blocks.time.timestampMonotonic.by[idx]
|
||||
: brk.series.blocks.time.timestamp.by[idx];
|
||||
|
||||
const index = {
|
||||
/** @type {Set<(index: ChartableIndex) => void>} */
|
||||
@@ -118,9 +118,9 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
let generation = 0;
|
||||
|
||||
const time = {
|
||||
/** @type {MetricData<number> | null} */
|
||||
/** @type {SeriesData<number> | null} */
|
||||
data: null,
|
||||
/** @type {Set<(data: MetricData<number>) => void>} */
|
||||
/** @type {Set<(data: SeriesData<number>) => void>} */
|
||||
callbacks: new Set(),
|
||||
/** @type {ReturnType<typeof getTimeEndpoint> | null} */
|
||||
endpoint: null,
|
||||
@@ -150,7 +150,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
};
|
||||
|
||||
// Memory cache for instant index switching
|
||||
/** @type {Map<string, MetricData<any>>} */
|
||||
/** @type {Map<string, SeriesData<any>>} */
|
||||
const cache = new Map();
|
||||
|
||||
// Range state: localStorage stores all ranges per-index, URL stores current range only
|
||||
@@ -425,7 +425,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {Color[]} args.colors
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.source
|
||||
* @param {number} args.paneIndex
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
@@ -438,7 +438,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {() => void} args.onRemove
|
||||
*/
|
||||
create({
|
||||
metric,
|
||||
source,
|
||||
name,
|
||||
order,
|
||||
paneIndex,
|
||||
@@ -486,7 +486,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
lastTimeVersion: null,
|
||||
/** @type {VoidFunction | null} */
|
||||
fetch: null,
|
||||
/** @type {((data: MetricData<number>) => void) | null} */
|
||||
/** @type {((data: SeriesData<number>) => void) | null} */
|
||||
onTime: null,
|
||||
reset() {
|
||||
this.hasData = false;
|
||||
@@ -572,8 +572,8 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
state.reset();
|
||||
state.fetch = null;
|
||||
|
||||
const _valuesEndpoint = metric.by[idx];
|
||||
// Gracefully skip - series may be about to be removed by option change
|
||||
const _valuesEndpoint = source.by[idx];
|
||||
// Gracefully skip - source may be about to be removed by option change
|
||||
if (!_valuesEndpoint) return;
|
||||
const valuesEndpoint = _valuesEndpoint;
|
||||
|
||||
@@ -702,7 +702,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
}
|
||||
|
||||
async function fetchAndProcess() {
|
||||
/** @type {MetricData<number> | null} */
|
||||
/** @type {SeriesData<number> | null} */
|
||||
let timeData = null;
|
||||
/** @type {(number | null | [number, number, number, number])[] | null} */
|
||||
let valuesData = null;
|
||||
@@ -769,7 +769,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {Object} args
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.source
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {number} [args.paneIndex]
|
||||
@@ -778,7 +778,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {CandlestickSeriesPartialOptions} [args.options]
|
||||
*/
|
||||
addCandlestick({
|
||||
metric,
|
||||
source,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
@@ -830,7 +830,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
source,
|
||||
setOrder(order) {
|
||||
candlestickISeries.setSeriesOrder(order);
|
||||
lineISeries.setSeriesOrder(order);
|
||||
@@ -880,7 +880,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {Object} args
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.source
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color | [Color, Color]} [args.color] - Single color or [positive, negative] colors
|
||||
@@ -889,7 +889,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {HistogramSeriesPartialOptions} [args.options]
|
||||
*/
|
||||
addHistogram({
|
||||
metric,
|
||||
source,
|
||||
name,
|
||||
key,
|
||||
color = colors.bi.p1,
|
||||
@@ -920,7 +920,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
source,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
applyOptions(active, highlighted) {
|
||||
iseries.applyOptions({
|
||||
@@ -953,7 +953,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {Object} args
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.source
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color} args.color
|
||||
@@ -962,7 +962,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {LineSeriesPartialOptions} [args.options]
|
||||
*/
|
||||
addLine({
|
||||
metric,
|
||||
source,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
@@ -991,7 +991,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
source,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
applyOptions(active, highlighted) {
|
||||
iseries.applyOptions({
|
||||
@@ -1010,7 +1010,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {Object} args
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.source
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color} args.color
|
||||
@@ -1019,7 +1019,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {LineSeriesPartialOptions} [args.options]
|
||||
*/
|
||||
addDots({
|
||||
metric,
|
||||
source,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
@@ -1063,7 +1063,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
source,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
applyOptions(active, highlighted) {
|
||||
iseries.applyOptions({
|
||||
@@ -1089,7 +1089,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {Object} args
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.source
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {number} [args.paneIndex]
|
||||
@@ -1099,7 +1099,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {BaselineSeriesPartialOptions} [args.options]
|
||||
*/
|
||||
addBaseline({
|
||||
metric,
|
||||
source,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
@@ -1139,7 +1139,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
source,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
applyOptions(active, highlighted) {
|
||||
iseries.applyOptions({
|
||||
@@ -1159,7 +1159,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
/**
|
||||
* Add a DotsBaseline series (baseline with point markers instead of line)
|
||||
* @param {Object} args
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.source
|
||||
* @param {string} args.name
|
||||
* @param {string} [args.key]
|
||||
* @param {number} args.order
|
||||
@@ -1171,7 +1171,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {BaselineSeriesPartialOptions} [args.options]
|
||||
*/
|
||||
addDotsBaseline({
|
||||
metric,
|
||||
source,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
@@ -1224,7 +1224,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
source,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
applyOptions(active, highlighted) {
|
||||
iseries.applyOptions({
|
||||
@@ -1343,10 +1343,10 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
const defaultColor = unit === Unit.usd ? colors.usd : colors.bitcoin;
|
||||
|
||||
map.get(unit)?.forEach((blueprint, order) => {
|
||||
if (!Object.keys(blueprint.metric.by).includes(idx)) return;
|
||||
if (!Object.keys(blueprint.series.by).includes(idx)) return;
|
||||
|
||||
const common = {
|
||||
metric: blueprint.metric,
|
||||
source: blueprint.series,
|
||||
name: blueprint.title,
|
||||
key: blueprint.key,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
@@ -1398,7 +1398,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
pane.series.push(
|
||||
serieses.addCandlestick({
|
||||
...common,
|
||||
metric: blueprint.ohlcMetric,
|
||||
source: blueprint.ohlcSeries,
|
||||
colors: blueprint.colors,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -119,7 +119,7 @@ export function createLegend() {
|
||||
anchor.href = series.url;
|
||||
anchor.target = "_blank";
|
||||
anchor.rel = "noopener noreferrer";
|
||||
anchor.title = "Open the metric data in a new tab";
|
||||
anchor.title = "Open the series data in a new tab";
|
||||
div.append(anchor);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@ import { satsBtcUsd, priceRatioPercentilesTree } from "./shared.js";
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createCointimeSection() {
|
||||
const { cointime, cohorts, supply } = brk.metrics;
|
||||
const { cointime, cohorts, supply } = brk.series;
|
||||
const {
|
||||
prices: cointimePrices,
|
||||
cap,
|
||||
@@ -24,9 +24,9 @@ export function createCointimeSection() {
|
||||
|
||||
// Reference lines for cap comparisons
|
||||
const capReferenceLines = /** @type {const} */ ([
|
||||
{ metric: supply.marketCap.usd, name: "Market", color: colors.default },
|
||||
{ series: supply.marketCap.usd, name: "Market", color: colors.default },
|
||||
{
|
||||
metric: all.realized.cap.usd,
|
||||
series: all.realized.cap.usd,
|
||||
name: "Realized",
|
||||
color: colors.realized,
|
||||
},
|
||||
@@ -76,11 +76,11 @@ export function createCointimeSection() {
|
||||
]);
|
||||
|
||||
const caps = /** @type {const} */ ([
|
||||
{ metric: cap.vaulted.usd, name: "Vaulted", color: colors.vaulted },
|
||||
{ metric: cap.active.usd, name: "Active", color: colors.active },
|
||||
{ metric: cap.cointime.usd, name: "Cointime", color: colors.cointime },
|
||||
{ metric: cap.investor.usd, name: "Investor", color: colors.investor },
|
||||
{ metric: cap.thermo.usd, name: "Thermo", color: colors.thermo },
|
||||
{ series: cap.vaulted.usd, name: "Vaulted", color: colors.vaulted },
|
||||
{ series: cap.active.usd, name: "Active", color: colors.active },
|
||||
{ series: cap.cointime.usd, name: "Cointime", color: colors.cointime },
|
||||
{ series: cap.investor.usd, name: "Investor", color: colors.investor },
|
||||
{ series: cap.thermo.usd, name: "Thermo", color: colors.thermo },
|
||||
]);
|
||||
|
||||
const supplyBreakdown = /** @type {const} */ ([
|
||||
@@ -159,17 +159,17 @@ export function createCointimeSection() {
|
||||
title: "Cointime Prices",
|
||||
top: [
|
||||
price({
|
||||
metric: all.realized.price,
|
||||
series: all.realized.price,
|
||||
name: "Realized",
|
||||
color: colors.realized,
|
||||
}),
|
||||
price({
|
||||
metric: all.realized.investor.price,
|
||||
series: all.realized.investor.price,
|
||||
name: "Investor",
|
||||
color: colors.investor,
|
||||
}),
|
||||
...prices.map(({ pattern, name, color }) =>
|
||||
price({ metric: pattern, name, color }),
|
||||
price({ series: pattern, name, color }),
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -181,7 +181,7 @@ export function createCointimeSection() {
|
||||
legend: name,
|
||||
color,
|
||||
priceReferences: [
|
||||
price({ metric: all.realized.price, name: "Realized", color: colors.realized, defaultActive: false }),
|
||||
price({ series: all.realized.price, name: "Realized", color: colors.realized, defaultActive: false }),
|
||||
],
|
||||
}),
|
||||
})),
|
||||
@@ -196,22 +196,22 @@ export function createCointimeSection() {
|
||||
name: "Compare",
|
||||
title: "Cointime Caps",
|
||||
bottom: [
|
||||
...capReferenceLines.map(({ metric, name, color }) =>
|
||||
line({ metric, name, color, unit: Unit.usd }),
|
||||
...capReferenceLines.map(({ series, name, color }) =>
|
||||
line({ series, name, color, unit: Unit.usd }),
|
||||
),
|
||||
...caps.map(({ metric, name, color }) =>
|
||||
line({ metric, name, color, unit: Unit.usd }),
|
||||
...caps.map(({ series, name, color }) =>
|
||||
line({ series, name, color, unit: Unit.usd }),
|
||||
),
|
||||
],
|
||||
},
|
||||
...caps.map(({ metric, name, color }) => ({
|
||||
...caps.map(({ series, name, color }) => ({
|
||||
name,
|
||||
title: `${name} Cap`,
|
||||
bottom: [
|
||||
line({ metric, name, color, unit: Unit.usd }),
|
||||
line({ series, name, color, unit: Unit.usd }),
|
||||
...capReferenceLines.map((ref) =>
|
||||
line({
|
||||
metric: ref.metric,
|
||||
series: ref.series,
|
||||
name: ref.name,
|
||||
color: ref.color,
|
||||
unit: Unit.usd,
|
||||
@@ -237,19 +237,19 @@ export function createCointimeSection() {
|
||||
title: "Liveliness & Vaultedness",
|
||||
bottom: [
|
||||
line({
|
||||
metric: activity.liveliness,
|
||||
series: activity.liveliness,
|
||||
name: "Liveliness",
|
||||
color: colors.liveliness,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: activity.vaultedness,
|
||||
series: activity.vaultedness,
|
||||
name: "Vaultedness",
|
||||
color: colors.vaulted,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: activity.ratio,
|
||||
series: activity.ratio,
|
||||
name: "L/V Ratio",
|
||||
color: colors.activity,
|
||||
unit: Unit.ratio,
|
||||
@@ -270,7 +270,7 @@ export function createCointimeSection() {
|
||||
title: "Coinblocks",
|
||||
bottom: coinblocks.map(({ pattern, name, color }) =>
|
||||
line({
|
||||
metric: pattern.base,
|
||||
series: pattern.base,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.coinblocks,
|
||||
@@ -282,7 +282,7 @@ export function createCointimeSection() {
|
||||
title: "Coinblocks (Total)",
|
||||
bottom: coinblocks.map(({ pattern, name, color }) =>
|
||||
line({
|
||||
metric: pattern.cumulative,
|
||||
series: pattern.cumulative,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.coinblocks,
|
||||
@@ -299,7 +299,7 @@ export function createCointimeSection() {
|
||||
title,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pattern.base,
|
||||
series: pattern.base,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.coinblocks,
|
||||
@@ -312,7 +312,7 @@ export function createCointimeSection() {
|
||||
title: `${title} (Total)`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pattern.cumulative,
|
||||
series: pattern.cumulative,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.coinblocks,
|
||||
@@ -336,10 +336,10 @@ export function createCointimeSection() {
|
||||
title: "Cointime Value",
|
||||
bottom: [
|
||||
...cointimeValues.map(({ pattern, name, color }) =>
|
||||
line({ metric: pattern.base, name, color, unit: Unit.usd }),
|
||||
line({ series: pattern.base, name, color, unit: Unit.usd }),
|
||||
),
|
||||
line({
|
||||
metric: vocdd.pattern.base,
|
||||
series: vocdd.pattern.base,
|
||||
name: vocdd.name,
|
||||
color: vocdd.color,
|
||||
unit: Unit.usd,
|
||||
@@ -352,14 +352,14 @@ export function createCointimeSection() {
|
||||
bottom: [
|
||||
...cointimeValues.map(({ pattern, name, color }) =>
|
||||
line({
|
||||
metric: pattern.cumulative,
|
||||
series: pattern.cumulative,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
),
|
||||
line({
|
||||
metric: vocdd.pattern.cumulative,
|
||||
series: vocdd.pattern.cumulative,
|
||||
name: vocdd.name,
|
||||
color: vocdd.color,
|
||||
unit: Unit.usd,
|
||||
@@ -375,7 +375,7 @@ export function createCointimeSection() {
|
||||
name: "Base",
|
||||
title,
|
||||
bottom: [
|
||||
line({ metric: pattern.base, name, color, unit: Unit.usd }),
|
||||
line({ series: pattern.base, name, color, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
rollingWindowsTree({ windows: pattern.sum, title, unit: Unit.usd }),
|
||||
@@ -384,7 +384,7 @@ export function createCointimeSection() {
|
||||
title: `${title} (Total)`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pattern.cumulative,
|
||||
series: pattern.cumulative,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
@@ -401,13 +401,13 @@ export function createCointimeSection() {
|
||||
title: vocdd.title,
|
||||
bottom: [
|
||||
line({
|
||||
metric: vocdd.pattern.base,
|
||||
series: vocdd.pattern.base,
|
||||
name: vocdd.name,
|
||||
color: vocdd.color,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: reserveRisk.vocddMedian1y,
|
||||
series: reserveRisk.vocddMedian1y,
|
||||
name: "365d Median",
|
||||
color: colors.time._1y,
|
||||
unit: Unit.usd,
|
||||
@@ -420,7 +420,7 @@ export function createCointimeSection() {
|
||||
title: `${vocdd.title} (Total)`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: vocdd.pattern.cumulative,
|
||||
series: vocdd.pattern.cumulative,
|
||||
name: vocdd.name,
|
||||
color: vocdd.color,
|
||||
unit: Unit.usd,
|
||||
@@ -432,7 +432,7 @@ export function createCointimeSection() {
|
||||
],
|
||||
},
|
||||
|
||||
// Indicators - derived decision metrics
|
||||
// Indicators - derived decision series
|
||||
{
|
||||
name: "Indicators",
|
||||
tree: [
|
||||
@@ -441,7 +441,7 @@ export function createCointimeSection() {
|
||||
title: "Reserve Risk",
|
||||
bottom: [
|
||||
line({
|
||||
metric: reserveRisk.value,
|
||||
series: reserveRisk.value,
|
||||
name: "Ratio",
|
||||
color: colors.reserveRisk,
|
||||
unit: Unit.ratio,
|
||||
@@ -453,7 +453,7 @@ export function createCointimeSection() {
|
||||
title: "AVIV Ratio",
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: cap.aviv.ratio,
|
||||
series: cap.aviv.ratio,
|
||||
name: "Ratio",
|
||||
color: colors.reserveRisk,
|
||||
unit: Unit.ratio,
|
||||
@@ -466,7 +466,7 @@ export function createCointimeSection() {
|
||||
title: "HODL Bank",
|
||||
bottom: [
|
||||
line({
|
||||
metric: reserveRisk.hodlBank,
|
||||
series: reserveRisk.hodlBank,
|
||||
name: "Value",
|
||||
color: colors.hodlBank,
|
||||
unit: Unit.usd,
|
||||
@@ -476,7 +476,7 @@ export function createCointimeSection() {
|
||||
],
|
||||
},
|
||||
|
||||
// Cointime-Adjusted - comparing base vs adjusted metrics
|
||||
// Cointime-Adjusted - comparing base vs adjusted series
|
||||
{
|
||||
name: "Cointime-Adjusted",
|
||||
tree: [
|
||||
@@ -485,7 +485,7 @@ export function createCointimeSection() {
|
||||
title: "Cointime-Adjusted Inflation",
|
||||
bottom: [
|
||||
dots({
|
||||
metric: supply.inflationRate.percent,
|
||||
series: supply.inflationRate.percent,
|
||||
name: "Base",
|
||||
color: colors.base,
|
||||
unit: Unit.percentage,
|
||||
@@ -505,13 +505,13 @@ export function createCointimeSection() {
|
||||
title: "Cointime-Adjusted BTC Velocity",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.velocity.native,
|
||||
series: supply.velocity.native,
|
||||
name: "Base",
|
||||
color: colors.base,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: adjusted.txVelocityNative,
|
||||
series: adjusted.txVelocityNative,
|
||||
name: "Cointime-Adjusted",
|
||||
color: colors.adjusted,
|
||||
unit: Unit.ratio,
|
||||
@@ -523,13 +523,13 @@ export function createCointimeSection() {
|
||||
title: "Cointime-Adjusted USD Velocity",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.velocity.fiat,
|
||||
series: supply.velocity.fiat,
|
||||
name: "Base",
|
||||
color: colors.thermo,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: adjusted.txVelocityFiat,
|
||||
series: adjusted.txVelocityFiat,
|
||||
name: "Cointime-Adjusted",
|
||||
color: colors.vaulted,
|
||||
unit: Unit.ratio,
|
||||
|
||||
@@ -7,17 +7,17 @@ import { line } from "./series.js";
|
||||
/**
|
||||
* Get constant pattern by number dynamically from tree
|
||||
* Examples: 0 → _0, 38.2 → _382, -1 → minus1
|
||||
* @param {BrkClient["metrics"]["constants"]} constants
|
||||
* @param {BrkClient["series"]["constants"]} constants
|
||||
* @param {number} num
|
||||
* @returns {AnyMetricPattern}
|
||||
* @returns {AnySeriesPattern}
|
||||
*/
|
||||
export function getConstant(constants, num) {
|
||||
const key =
|
||||
num >= 0
|
||||
? `_${String(num).replace(".", "")}`
|
||||
: `minus${Math.abs(num)}`;
|
||||
const constant = /** @type {AnyMetricPattern | undefined} */ (
|
||||
/** @type {Record<string, AnyMetricPattern>} */ (constants)[key]
|
||||
const constant = /** @type {AnySeriesPattern | undefined} */ (
|
||||
/** @type {Record<string, AnySeriesPattern>} */ (constants)[key]
|
||||
);
|
||||
if (!constant) throw new Error(`Unknown constant: ${num} (key: ${key})`);
|
||||
return constant;
|
||||
@@ -25,12 +25,12 @@ export function getConstant(constants, num) {
|
||||
|
||||
/**
|
||||
* Create a price line series (horizontal reference line)
|
||||
* @param {{ number?: number, name?: string } & Omit<(Parameters<typeof line>)[0], 'name' | 'metric'>} args
|
||||
* @param {{ number?: number, name?: string } & Omit<(Parameters<typeof line>)[0], 'name' | 'series'>} args
|
||||
*/
|
||||
export function priceLine(args) {
|
||||
return line({
|
||||
...args,
|
||||
metric: getConstant(brk.metrics.constants, args.number || 0),
|
||||
series: getConstant(brk.series.constants, args.number || 0),
|
||||
name: args.name || `${args.number ?? 0}`,
|
||||
color: args.color ?? colors.gray,
|
||||
options: {
|
||||
|
||||
@@ -23,7 +23,7 @@ import { colors } from "../../utils/colors.js";
|
||||
/**
|
||||
* @param {{ sent: Brk.BaseCumulativeInSumPattern, coindaysDestroyed: Brk.BaseCumulativeSumPattern<number> }} activity
|
||||
* @param {Color} color
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function volumeAndCoinsTree(activity, color, title) {
|
||||
@@ -35,18 +35,18 @@ function volumeAndCoinsTree(activity, color, title) {
|
||||
name: "Sum",
|
||||
title: title("Sent Volume"),
|
||||
bottom: [
|
||||
line({ metric: activity.sent.base, name: "Sum", color, unit: Unit.sats }),
|
||||
line({ metric: activity.sent.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: activity.sent.sum._1w, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: activity.sent.sum._1m, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: activity.sent.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: activity.sent.base, name: "Sum", color, unit: Unit.sats }),
|
||||
line({ series: activity.sent.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: activity.sent.sum._1w, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: activity.sent.sum._1m, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: activity.sent.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title("Sent Volume (Total)"),
|
||||
bottom: [
|
||||
line({ metric: activity.sent.cumulative, name: "All-time", color, unit: Unit.sats }),
|
||||
line({ series: activity.sent.cumulative, name: "All-time", color, unit: Unit.sats }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -58,18 +58,18 @@ function volumeAndCoinsTree(activity, color, title) {
|
||||
name: "Base",
|
||||
title: title("Coindays Destroyed"),
|
||||
bottom: [
|
||||
line({ metric: activity.coindaysDestroyed.base, name: "Base", color, unit: Unit.coindays }),
|
||||
line({ metric: activity.coindaysDestroyed.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ metric: activity.coindaysDestroyed.sum._1w, name: "1w", color: colors.time._1w, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ metric: activity.coindaysDestroyed.sum._1m, name: "1m", color: colors.time._1m, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ metric: activity.coindaysDestroyed.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ series: activity.coindaysDestroyed.base, name: "Base", color, unit: Unit.coindays }),
|
||||
line({ series: activity.coindaysDestroyed.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ series: activity.coindaysDestroyed.sum._1w, name: "1w", color: colors.time._1w, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ series: activity.coindaysDestroyed.sum._1m, name: "1m", color: colors.time._1m, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ series: activity.coindaysDestroyed.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.coindays, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title("Cumulative Coindays Destroyed"),
|
||||
bottom: [
|
||||
line({ metric: activity.coindaysDestroyed.cumulative, name: "All-time", color, unit: Unit.coindays }),
|
||||
line({ series: activity.coindaysDestroyed.cumulative, name: "All-time", color, unit: Unit.coindays }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -80,7 +80,7 @@ function volumeAndCoinsTree(activity, color, title) {
|
||||
/**
|
||||
* Sent in profit/loss breakdown tree (shared by full and mid-level activity)
|
||||
* @param {Brk.BaseCumulativeInSumPattern} sent
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function sentProfitLossTree(sent, title) {
|
||||
@@ -92,39 +92,39 @@ function sentProfitLossTree(sent, title) {
|
||||
name: "USD",
|
||||
title: title("Sent Volume In Profit"),
|
||||
bottom: [
|
||||
line({ metric: sent.inProfit.base.usd, name: "Base", color: colors.profit, unit: Unit.usd }),
|
||||
line({ metric: sent.inProfit.sum._24h.usd, name: "24h", color: colors.time._24h, unit: Unit.usd, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1w.usd, name: "1w", color: colors.time._1w, unit: Unit.usd, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1m.usd, name: "1m", color: colors.time._1m, unit: Unit.usd, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1y.usd, name: "1y", color: colors.time._1y, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inProfit.base.usd, name: "Base", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: sent.inProfit.sum._24h.usd, name: "24h", color: colors.time._24h, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1w.usd, name: "1w", color: colors.time._1w, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1m.usd, name: "1m", color: colors.time._1m, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1y.usd, name: "1y", color: colors.time._1y, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "BTC",
|
||||
title: title("Sent Volume In Profit (BTC)"),
|
||||
bottom: [
|
||||
line({ metric: sent.inProfit.base.btc, name: "Base", color: colors.profit, unit: Unit.btc }),
|
||||
line({ metric: sent.inProfit.sum._24h.btc, name: "24h", color: colors.time._24h, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1w.btc, name: "1w", color: colors.time._1w, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1m.btc, name: "1m", color: colors.time._1m, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1y.btc, name: "1y", color: colors.time._1y, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.base.btc, name: "Base", color: colors.profit, unit: Unit.btc }),
|
||||
line({ series: sent.inProfit.sum._24h.btc, name: "24h", color: colors.time._24h, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1w.btc, name: "1w", color: colors.time._1w, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1m.btc, name: "1m", color: colors.time._1m, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1y.btc, name: "1y", color: colors.time._1y, unit: Unit.btc, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sats",
|
||||
title: title("Sent Volume In Profit (Sats)"),
|
||||
bottom: [
|
||||
line({ metric: sent.inProfit.base.sats, name: "Base", color: colors.profit, unit: Unit.sats }),
|
||||
line({ metric: sent.inProfit.sum._24h.sats, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1w.sats, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1m.sats, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.sum._1y.sats, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.base.sats, name: "Base", color: colors.profit, unit: Unit.sats }),
|
||||
line({ series: sent.inProfit.sum._24h.sats, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1w.sats, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1m.sats, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1y.sats, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{ name: "Cumulative", title: title("Cumulative Sent In Profit"), bottom: [
|
||||
line({ metric: sent.inProfit.cumulative.usd, name: "USD", color: colors.profit, unit: Unit.usd }),
|
||||
line({ metric: sent.inProfit.cumulative.btc, name: "BTC", color: colors.profit, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inProfit.cumulative.sats, name: "Sats", color: colors.profit, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.cumulative.usd, name: "USD", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: sent.inProfit.cumulative.btc, name: "BTC", color: colors.profit, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.cumulative.sats, name: "Sats", color: colors.profit, unit: Unit.sats, defaultActive: false }),
|
||||
]},
|
||||
],
|
||||
},
|
||||
@@ -135,39 +135,39 @@ function sentProfitLossTree(sent, title) {
|
||||
name: "USD",
|
||||
title: title("Sent Volume In Loss"),
|
||||
bottom: [
|
||||
line({ metric: sent.inLoss.base.usd, name: "Base", color: colors.loss, unit: Unit.usd }),
|
||||
line({ metric: sent.inLoss.sum._24h.usd, name: "24h", color: colors.time._24h, unit: Unit.usd, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1w.usd, name: "1w", color: colors.time._1w, unit: Unit.usd, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1m.usd, name: "1m", color: colors.time._1m, unit: Unit.usd, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1y.usd, name: "1y", color: colors.time._1y, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inLoss.base.usd, name: "Base", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: sent.inLoss.sum._24h.usd, name: "24h", color: colors.time._24h, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1w.usd, name: "1w", color: colors.time._1w, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1m.usd, name: "1m", color: colors.time._1m, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1y.usd, name: "1y", color: colors.time._1y, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "BTC",
|
||||
title: title("Sent Volume In Loss (BTC)"),
|
||||
bottom: [
|
||||
line({ metric: sent.inLoss.base.btc, name: "Base", color: colors.loss, unit: Unit.btc }),
|
||||
line({ metric: sent.inLoss.sum._24h.btc, name: "24h", color: colors.time._24h, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1w.btc, name: "1w", color: colors.time._1w, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1m.btc, name: "1m", color: colors.time._1m, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1y.btc, name: "1y", color: colors.time._1y, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.base.btc, name: "Base", color: colors.loss, unit: Unit.btc }),
|
||||
line({ series: sent.inLoss.sum._24h.btc, name: "24h", color: colors.time._24h, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1w.btc, name: "1w", color: colors.time._1w, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1m.btc, name: "1m", color: colors.time._1m, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1y.btc, name: "1y", color: colors.time._1y, unit: Unit.btc, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sats",
|
||||
title: title("Sent Volume In Loss (Sats)"),
|
||||
bottom: [
|
||||
line({ metric: sent.inLoss.base.sats, name: "Base", color: colors.loss, unit: Unit.sats }),
|
||||
line({ metric: sent.inLoss.sum._24h.sats, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1w.sats, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1m.sats, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.sum._1y.sats, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.base.sats, name: "Base", color: colors.loss, unit: Unit.sats }),
|
||||
line({ series: sent.inLoss.sum._24h.sats, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1w.sats, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1m.sats, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1y.sats, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{ name: "Cumulative", title: title("Cumulative Sent In Loss"), bottom: [
|
||||
line({ metric: sent.inLoss.cumulative.usd, name: "USD", color: colors.loss, unit: Unit.usd }),
|
||||
line({ metric: sent.inLoss.cumulative.btc, name: "BTC", color: colors.loss, unit: Unit.btc, defaultActive: false }),
|
||||
line({ metric: sent.inLoss.cumulative.sats, name: "Sats", color: colors.loss, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.cumulative.usd, name: "USD", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: sent.inLoss.cumulative.btc, name: "BTC", color: colors.loss, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.cumulative.sats, name: "Sats", color: colors.loss, unit: Unit.sats, defaultActive: false }),
|
||||
]},
|
||||
],
|
||||
},
|
||||
@@ -178,7 +178,7 @@ function sentProfitLossTree(sent, title) {
|
||||
* Volume and coins tree with coinyears, dormancy, and sent in profit/loss (All/STH/LTH)
|
||||
* @param {Brk.CoindaysCoinyearsDormancySentPattern} activity
|
||||
* @param {Color} color
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function fullVolumeTree(activity, color, title) {
|
||||
@@ -188,12 +188,12 @@ function fullVolumeTree(activity, color, title) {
|
||||
{
|
||||
name: "Coinyears Destroyed",
|
||||
title: title("Coinyears Destroyed"),
|
||||
bottom: [line({ metric: activity.coinyearsDestroyed, name: "CYD", color, unit: Unit.years })],
|
||||
bottom: [line({ series: activity.coinyearsDestroyed, name: "CYD", color, unit: Unit.years })],
|
||||
},
|
||||
{
|
||||
name: "Dormancy",
|
||||
title: title("Dormancy"),
|
||||
bottom: [line({ metric: activity.dormancy, name: "Dormancy", color, unit: Unit.days })],
|
||||
bottom: [line({ series: activity.dormancy, name: "Dormancy", color, unit: Unit.days })],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -204,7 +204,7 @@ function fullVolumeTree(activity, color, title) {
|
||||
|
||||
/**
|
||||
* @param {Brk._1m1w1y24hPattern<number>} ratio
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
@@ -214,31 +214,31 @@ function singleRollingSoprTree(ratio, title, prefix = "") {
|
||||
name: "Compare",
|
||||
title: title(`Rolling ${prefix}SOPR`),
|
||||
bottom: [
|
||||
baseline({ metric: ratio._24h, name: "24h", color: colors.time._24h, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ metric: ratio._1w, name: "7d", color: colors.time._1w, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ metric: ratio._1m, name: "30d", color: colors.time._1m, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ metric: ratio._1y, name: "1y", color: colors.time._1y, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: ratio._24h, name: "24h", color: colors.time._24h, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: ratio._1w, name: "7d", color: colors.time._1w, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: ratio._1m, name: "30d", color: colors.time._1m, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: ratio._1y, name: "1y", color: colors.time._1y, unit: Unit.ratio, base: 1 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "24h",
|
||||
title: title(`${prefix}SOPR (24h)`),
|
||||
bottom: [dotsBaseline({ metric: ratio._24h, name: "24h", unit: Unit.ratio, base: 1 })],
|
||||
bottom: [dotsBaseline({ series: ratio._24h, name: "24h", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}SOPR (7d)`),
|
||||
bottom: [baseline({ metric: ratio._1w, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
bottom: [baseline({ series: ratio._1w, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}SOPR (30d)`),
|
||||
bottom: [baseline({ metric: ratio._1m, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
bottom: [baseline({ series: ratio._1m, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
{
|
||||
name: "1y",
|
||||
title: title(`${prefix}SOPR (1y)`),
|
||||
bottom: [baseline({ metric: ratio._1y, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
bottom: [baseline({ series: ratio._1y, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -249,7 +249,7 @@ function singleRollingSoprTree(ratio, title, prefix = "") {
|
||||
|
||||
/**
|
||||
* @param {Brk._1m1w1y24hPattern6} sellSideRisk
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function singleSellSideRiskTree(sellSideRisk, title) {
|
||||
@@ -294,7 +294,7 @@ function singleSellSideRiskTree(sellSideRisk, title) {
|
||||
/**
|
||||
* @param {Brk.BaseCumulativeSumPattern<number>} valueCreated
|
||||
* @param {Brk.BaseCumulativeSumPattern<number>} valueDestroyed
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
@@ -307,20 +307,20 @@ function singleRollingValueTree(valueCreated, valueDestroyed, title, prefix = ""
|
||||
name: "Created",
|
||||
title: title(`Rolling ${prefix}Value Created`),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.usd }),
|
||||
line({ metric: valueCreated.sum._1w, name: "7d", color: colors.time._1w, unit: Unit.usd }),
|
||||
line({ metric: valueCreated.sum._1m, name: "30d", color: colors.time._1m, unit: Unit.usd }),
|
||||
line({ metric: valueCreated.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1w, name: "7d", color: colors.time._1w, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1m, name: "30d", color: colors.time._1m, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Destroyed",
|
||||
title: title(`Rolling ${prefix}Value Destroyed`),
|
||||
bottom: [
|
||||
line({ metric: valueDestroyed.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.sum._1w, name: "7d", color: colors.time._1w, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.sum._1m, name: "30d", color: colors.time._1m, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1w, name: "7d", color: colors.time._1w, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1m, name: "30d", color: colors.time._1m, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -329,40 +329,40 @@ function singleRollingValueTree(valueCreated, valueDestroyed, title, prefix = ""
|
||||
name: "24h",
|
||||
title: title(`${prefix}Value Created & Destroyed (24h)`),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.sum._24h, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.sum._24h, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._24h, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._24h, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}Value Created & Destroyed (7d)`),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.sum._1w, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.sum._1w, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1w, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1w, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}Value Created & Destroyed (30d)`),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.sum._1m, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.sum._1m, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1m, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1m, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "1y",
|
||||
title: title(`${prefix}Value Created & Destroyed (1y)`),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.sum._1y, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.sum._1y, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1y, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1y, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title(`${prefix}Value Created & Destroyed (Total)`),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.cumulative, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.cumulative, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: valueCreated.cumulative, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.cumulative, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -374,12 +374,12 @@ function singleRollingValueTree(valueCreated, valueDestroyed, title, prefix = ""
|
||||
* @param {Brk.BaseCapitulationCumulativeNegativeRelSumValuePattern} loss
|
||||
* @param {Brk.BaseCumulativeSumPattern<number>} valueCreated
|
||||
* @param {Brk.BaseCumulativeSumPattern<number>} valueDestroyed
|
||||
* @param {AnyFetchedSeriesBlueprint[]} extraValueMetrics
|
||||
* @param {AnyFetchedSeriesBlueprint[]} extraValueSeries
|
||||
* @param {PartialOptionsTree} rollingTree
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function fullValueSection(profit, loss, valueCreated, valueDestroyed, extraValueMetrics, rollingTree, title) {
|
||||
function fullValueSection(profit, loss, valueCreated, valueDestroyed, extraValueSeries, rollingTree, title) {
|
||||
return {
|
||||
name: "Value",
|
||||
tree: [
|
||||
@@ -387,17 +387,17 @@ function fullValueSection(profit, loss, valueCreated, valueDestroyed, extraValue
|
||||
name: "Flows",
|
||||
title: title("Profit & Capitulation Flows"),
|
||||
bottom: [
|
||||
line({ metric: profit.distributionFlow, name: "Distribution Flow", color: colors.profit, unit: Unit.usd }),
|
||||
line({ metric: loss.capitulationFlow, name: "Capitulation Flow", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: profit.distributionFlow, name: "Distribution Flow", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: loss.capitulationFlow, name: "Capitulation Flow", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Created & Destroyed",
|
||||
title: title("Value Created & Destroyed"),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.base, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
...extraValueMetrics,
|
||||
line({ series: valueCreated.base, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
...extraValueSeries,
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -407,16 +407,16 @@ function fullValueSection(profit, loss, valueCreated, valueDestroyed, extraValue
|
||||
name: "Profit",
|
||||
title: title("Profit Value Created & Destroyed"),
|
||||
bottom: [
|
||||
line({ metric: profit.valueCreated.base, name: "Created", color: colors.profit, unit: Unit.usd }),
|
||||
line({ metric: profit.valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: profit.valueCreated.base, name: "Created", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: profit.valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Loss",
|
||||
title: title("Loss Value Created & Destroyed"),
|
||||
bottom: [
|
||||
line({ metric: loss.valueCreated.base, name: "Created", color: colors.profit, unit: Unit.usd }),
|
||||
line({ metric: loss.valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: loss.valueCreated.base, name: "Created", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: loss.valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -430,7 +430,7 @@ function fullValueSection(profit, loss, valueCreated, valueDestroyed, extraValue
|
||||
* Simple value section (created & destroyed + rolling)
|
||||
* @param {Brk.BaseCumulativeSumPattern<number>} valueCreated
|
||||
* @param {Brk.BaseCumulativeSumPattern<number>} valueDestroyed
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function simpleValueSection(valueCreated, valueDestroyed, title) {
|
||||
@@ -441,8 +441,8 @@ function simpleValueSection(valueCreated, valueDestroyed, title) {
|
||||
name: "Created & Destroyed",
|
||||
title: title("Value Created & Destroyed"),
|
||||
bottom: [
|
||||
line({ metric: valueCreated.base, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ metric: valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: valueCreated.base, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -459,7 +459,7 @@ function simpleValueSection(valueCreated, valueDestroyed, title) {
|
||||
|
||||
/**
|
||||
* Full activity with adjusted SOPR (All/STH)
|
||||
* @param {{ cohort: CohortAll | CohortFull, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortAll | CohortFull, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createActivitySectionWithAdjusted({ cohort, title }) {
|
||||
@@ -489,8 +489,8 @@ export function createActivitySectionWithAdjusted({ cohort, title }) {
|
||||
r.profit, r.loss,
|
||||
sopr.valueCreated, sopr.valueDestroyed,
|
||||
[
|
||||
line({ metric: sopr.adjusted.valueCreated.base, name: "Adjusted Created", color: colors.adjustedCreated, unit: Unit.usd, defaultActive: false }),
|
||||
line({ metric: sopr.adjusted.valueDestroyed.base, name: "Adjusted Destroyed", color: colors.adjustedDestroyed, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sopr.adjusted.valueCreated.base, name: "Adjusted Created", color: colors.adjustedCreated, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sopr.adjusted.valueDestroyed.base, name: "Adjusted Destroyed", color: colors.adjustedDestroyed, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
[
|
||||
{
|
||||
@@ -510,7 +510,7 @@ export function createActivitySectionWithAdjusted({ cohort, title }) {
|
||||
|
||||
/**
|
||||
* Activity section for cohorts with rolling SOPR + sell side risk (LTH, also CohortFull | CohortLongTerm)
|
||||
* @param {{ cohort: CohortFull | CohortLongTerm, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortFull | CohortLongTerm, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createActivitySection({ cohort, title }) {
|
||||
@@ -540,7 +540,7 @@ export function createActivitySection({ cohort, title }) {
|
||||
|
||||
/**
|
||||
* Activity section for cohorts with activity but basic realized (AgeRange/MaxAge — 24h SOPR only)
|
||||
* @param {{ cohort: CohortAgeRange | CohortWithAdjusted, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortAgeRange | CohortWithAdjusted, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createActivitySectionWithActivity({ cohort, title }) {
|
||||
@@ -555,7 +555,7 @@ export function createActivitySectionWithActivity({ cohort, title }) {
|
||||
{
|
||||
name: "SOPR",
|
||||
title: title("SOPR (24h)"),
|
||||
bottom: [dotsBaseline({ metric: sopr.ratio._24h, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
bottom: [dotsBaseline({ series: sopr.ratio._24h, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
simpleValueSection(sopr.valueCreated, sopr.valueDestroyed, title),
|
||||
],
|
||||
@@ -564,7 +564,7 @@ export function createActivitySectionWithActivity({ cohort, title }) {
|
||||
|
||||
/**
|
||||
* Minimal activity section for cohorts without activity field (value only)
|
||||
* @param {{ cohort: CohortBasicWithMarketCap | CohortBasicWithoutMarketCap | CohortWithoutRelative | CohortAddress | AddressCohortObject, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortBasicWithMarketCap | CohortBasicWithoutMarketCap | CohortWithoutRelative | CohortAddress | AddressCohortObject, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createActivitySectionMinimal({ cohort, title }) {
|
||||
@@ -587,10 +587,10 @@ export function createActivitySectionMinimal({ cohort, title }) {
|
||||
* @template {{ color: Color, name: string }} A
|
||||
* @param {readonly T[]} list
|
||||
* @param {A} all
|
||||
* @param {(item: T | A) => AnyMetricPattern} getRaw
|
||||
* @param {(item: T | A) => AnyMetricPattern} get7d
|
||||
* @param {(item: T | A) => AnyMetricPattern} get30d
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(item: T | A) => AnySeriesPattern} getRaw
|
||||
* @param {(item: T | A) => AnySeriesPattern} get7d
|
||||
* @param {(item: T | A) => AnySeriesPattern} get30d
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
@@ -600,21 +600,21 @@ function groupedSoprCharts(list, all, getRaw, get7d, get30d, title, prefix = "")
|
||||
name: "Raw",
|
||||
title: title(`${prefix}SOPR`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
baseline({ metric: getRaw(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: getRaw(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}SOPR (7d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
baseline({ metric: get7d(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: get7d(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}SOPR (30d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
baseline({ metric: get30d(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: get30d(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -625,11 +625,11 @@ function groupedSoprCharts(list, all, getRaw, get7d, get30d, title, prefix = "")
|
||||
* @template {{ color: Color, name: string }} A
|
||||
* @param {readonly T[]} list
|
||||
* @param {A} all
|
||||
* @param {(item: T | A) => AnyMetricPattern} get24h
|
||||
* @param {(item: T | A) => AnyMetricPattern} get7d
|
||||
* @param {(item: T | A) => AnyMetricPattern} get30d
|
||||
* @param {(item: T | A) => AnyMetricPattern} get1y
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(item: T | A) => AnySeriesPattern} get24h
|
||||
* @param {(item: T | A) => AnySeriesPattern} get7d
|
||||
* @param {(item: T | A) => AnySeriesPattern} get30d
|
||||
* @param {(item: T | A) => AnySeriesPattern} get1y
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
@@ -639,28 +639,28 @@ function groupedRollingSoprCharts(list, all, get24h, get7d, get30d, get1y, title
|
||||
name: "24h",
|
||||
title: title(`${prefix}SOPR (24h)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ metric: get24h(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: get24h(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}SOPR (7d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ metric: get7d(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: get7d(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}SOPR (30d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ metric: get30d(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: get30d(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "1y",
|
||||
title: title(`${prefix}SOPR (1y)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ metric: get1y(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: get1y(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -675,8 +675,8 @@ function groupedRollingSoprCharts(list, all, get24h, get7d, get30d, get1y, title
|
||||
* @template {{ color: Color, name: string }} A
|
||||
* @param {readonly T[]} list
|
||||
* @param {A} all
|
||||
* @param {readonly { name: string, getCreated: (item: T | A) => AnyMetricPattern, getDestroyed: (item: T | A) => AnyMetricPattern }[]} windows
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {readonly { name: string, getCreated: (item: T | A) => AnySeriesPattern, getDestroyed: (item: T | A) => AnySeriesPattern }[]} windows
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
@@ -688,7 +688,7 @@ function groupedRollingValueCharts(list, all, windows, title, prefix = "") {
|
||||
name: w.name,
|
||||
title: title(`${prefix}Value Created (${w.name})`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
line({ metric: w.getCreated(item), name: item.name, color: item.color, unit: Unit.usd }),
|
||||
line({ series: w.getCreated(item), name: item.name, color: item.color, unit: Unit.usd }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
@@ -698,7 +698,7 @@ function groupedRollingValueCharts(list, all, windows, title, prefix = "") {
|
||||
name: w.name,
|
||||
title: title(`${prefix}Value Destroyed (${w.name})`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
line({ metric: w.getDestroyed(item), name: item.name, color: item.color, unit: Unit.usd }),
|
||||
line({ series: w.getDestroyed(item), name: item.name, color: item.color, unit: Unit.usd }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
@@ -723,7 +723,7 @@ function valueWindows(list, all) {
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @param {{ list: readonly CohortFull[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly CohortFull[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
|
||||
@@ -734,7 +734,7 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
|
||||
name: "Volume",
|
||||
title: title("Sent Volume"),
|
||||
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
line({ metric: tree.activity.sent.sum._24h, name, color, unit: Unit.sats }),
|
||||
line({ series: tree.activity.sent.sum._24h, name, color, unit: Unit.sats }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
@@ -793,10 +793,10 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
|
||||
{
|
||||
name: "Sell Side Risk",
|
||||
tree: [
|
||||
{ name: "24h", title: title("Sell Side Risk (24h)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._24h.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "7d", title: title("Sell Side Risk (7d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._1w.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "30d", title: title("Sell Side Risk (30d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._1m.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "1y", title: title("Sell Side Risk (1y)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._1y.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "24h", title: title("Sell Side Risk (24h)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._24h.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "7d", title: title("Sell Side Risk (7d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1w.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "30d", title: title("Sell Side Risk (30d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1m.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "1y", title: title("Sell Side Risk (1y)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1y.ratio, name, color, unit: Unit.ratio })) },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -805,12 +805,12 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
|
||||
{
|
||||
name: "Flows",
|
||||
tree: [
|
||||
{ name: "Distribution", title: title("Distribution Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.profit.distributionFlow, name, color, unit: Unit.usd })) },
|
||||
{ name: "Capitulation", title: title("Capitulation Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.loss.capitulationFlow, name, color, unit: Unit.usd })) },
|
||||
{ name: "Distribution", title: title("Distribution Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.profit.distributionFlow, name, color, unit: Unit.usd })) },
|
||||
{ name: "Capitulation", title: title("Capitulation Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.loss.capitulationFlow, name, color, unit: Unit.usd })) },
|
||||
],
|
||||
},
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: [
|
||||
@@ -840,7 +840,7 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
|
||||
name: "Coins Destroyed",
|
||||
title: title("Coindays Destroyed"),
|
||||
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
line({ metric: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
|
||||
line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
|
||||
]),
|
||||
},
|
||||
],
|
||||
@@ -849,7 +849,7 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
|
||||
|
||||
/**
|
||||
* Grouped activity for cohorts with rolling SOPR + sell side risk (LTH-like)
|
||||
* @param {{ list: readonly (CohortFull | CohortLongTerm)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (CohortFull | CohortLongTerm)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedActivitySection({ list, all, title }) {
|
||||
@@ -860,7 +860,7 @@ export function createGroupedActivitySection({ list, all, title }) {
|
||||
name: "Volume",
|
||||
title: title("Sent Volume"),
|
||||
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
line({ metric: tree.activity.sent.sum._24h, name, color, unit: Unit.sats }),
|
||||
line({ series: tree.activity.sent.sum._24h, name, color, unit: Unit.sats }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
@@ -889,10 +889,10 @@ export function createGroupedActivitySection({ list, all, title }) {
|
||||
{
|
||||
name: "Sell Side Risk",
|
||||
tree: [
|
||||
{ name: "24h", title: title("Sell Side Risk (24h)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._24h.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "7d", title: title("Sell Side Risk (7d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._1w.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "30d", title: title("Sell Side Risk (30d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._1m.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "1y", title: title("Sell Side Risk (1y)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sellSideRiskRatio._1y.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "24h", title: title("Sell Side Risk (24h)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._24h.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "7d", title: title("Sell Side Risk (7d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1w.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "30d", title: title("Sell Side Risk (30d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1m.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "1y", title: title("Sell Side Risk (1y)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1y.ratio, name, color, unit: Unit.ratio })) },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -901,12 +901,12 @@ export function createGroupedActivitySection({ list, all, title }) {
|
||||
{
|
||||
name: "Flows",
|
||||
tree: [
|
||||
{ name: "Distribution", title: title("Distribution Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.profit.distributionFlow, name, color, unit: Unit.usd })) },
|
||||
{ name: "Capitulation", title: title("Capitulation Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.loss.capitulationFlow, name, color, unit: Unit.usd })) },
|
||||
{ name: "Distribution", title: title("Distribution Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.profit.distributionFlow, name, color, unit: Unit.usd })) },
|
||||
{ name: "Capitulation", title: title("Capitulation Flow"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.loss.capitulationFlow, name, color, unit: Unit.usd })) },
|
||||
],
|
||||
},
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: groupedRollingValueCharts(list, all, valueWindows(list, all), title),
|
||||
@@ -917,7 +917,7 @@ export function createGroupedActivitySection({ list, all, title }) {
|
||||
name: "Coins Destroyed",
|
||||
title: title("Coindays Destroyed"),
|
||||
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
line({ metric: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
|
||||
line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
|
||||
]),
|
||||
},
|
||||
],
|
||||
@@ -926,7 +926,7 @@ export function createGroupedActivitySection({ list, all, title }) {
|
||||
|
||||
/**
|
||||
* Grouped activity for cohorts with activity but basic realized (AgeRange/MaxAge)
|
||||
* @param {{ list: readonly (CohortAgeRange | CohortWithAdjusted)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (CohortAgeRange | CohortWithAdjusted)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedActivitySectionWithActivity({ list, all, title }) {
|
||||
@@ -937,28 +937,28 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) {
|
||||
name: "Volume",
|
||||
title: title("Sent Volume"),
|
||||
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
line({ metric: tree.activity.sent.sum._24h, name, color, unit: Unit.sats }),
|
||||
line({ series: tree.activity.sent.sum._24h, name, color, unit: Unit.sats }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
name: "SOPR",
|
||||
title: title("SOPR (24h)"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
baseline({ metric: tree.realized.sopr.ratio._24h, name, color, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: tree.realized.sopr.ratio._24h, name, color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Value",
|
||||
tree: [
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Coins Destroyed",
|
||||
title: title("Coindays Destroyed"),
|
||||
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
line({ metric: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
|
||||
line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
|
||||
]),
|
||||
},
|
||||
],
|
||||
@@ -967,15 +967,15 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) {
|
||||
|
||||
/**
|
||||
* Grouped minimal activity (value only, no activity field)
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative | CohortAddress | AddressCohortObject)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative | CohortAddress | AddressCohortObject)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedActivitySectionMinimal({ list, all, title }) {
|
||||
return {
|
||||
name: "Activity",
|
||||
tree: [
|
||||
{ name: "Value Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Value Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ metric: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Value Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Value Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ const ACTIVE_PCTS = new Set(["pct75", "pct50", "pct25"]);
|
||||
function createCorePercentileSeries(p, n = (x) => x) {
|
||||
return entries(p)
|
||||
.reverse()
|
||||
.map(([key, metric], i, arr) =>
|
||||
.map(([key, s], i, arr) =>
|
||||
price({
|
||||
metric,
|
||||
series: s,
|
||||
name: n(key.replace("pct", "p")),
|
||||
color: colors.at(i, arr.length),
|
||||
...(ACTIVE_PCTS.has(key) ? {} : { defaultActive: false }),
|
||||
@@ -45,28 +45,28 @@ function createSingleSummarySeries(cohort) {
|
||||
const { color, tree } = cohort;
|
||||
const p = tree.costBasis.percentiles;
|
||||
return [
|
||||
price({ metric: tree.realized.price, name: "Average", color }),
|
||||
price({ series: tree.realized.price, name: "Average", color }),
|
||||
price({
|
||||
metric: tree.costBasis.max,
|
||||
series: tree.costBasis.max,
|
||||
name: "Max (p100)",
|
||||
color: colors.stat.max,
|
||||
defaultActive: false,
|
||||
}),
|
||||
price({
|
||||
metric: p.pct75,
|
||||
series: p.pct75,
|
||||
name: "Q3 (p75)",
|
||||
color: colors.stat.pct75,
|
||||
defaultActive: false,
|
||||
}),
|
||||
price({ metric: p.pct50, name: "Median (p50)", color: colors.stat.median }),
|
||||
price({ series: p.pct50, name: "Median (p50)", color: colors.stat.median }),
|
||||
price({
|
||||
metric: p.pct25,
|
||||
series: p.pct25,
|
||||
name: "Q1 (p25)",
|
||||
color: colors.stat.pct25,
|
||||
defaultActive: false,
|
||||
}),
|
||||
price({
|
||||
metric: tree.costBasis.min,
|
||||
series: tree.costBasis.min,
|
||||
name: "Min (p0)",
|
||||
color: colors.stat.min,
|
||||
defaultActive: false,
|
||||
@@ -81,7 +81,7 @@ function createSingleSummarySeries(cohort) {
|
||||
*/
|
||||
function createGroupedSummarySeries(list, all) {
|
||||
return mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ metric: tree.realized.price, name, color }),
|
||||
price({ series: tree.realized.price, name, color }),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,16 +93,16 @@ function createSingleByCoinSeries(cohort) {
|
||||
const { color, tree } = cohort;
|
||||
const cb = tree.costBasis;
|
||||
return [
|
||||
price({ metric: tree.realized.price, name: "Average", color }),
|
||||
price({ series: tree.realized.price, name: "Average", color }),
|
||||
price({
|
||||
metric: cb.max,
|
||||
series: cb.max,
|
||||
name: "p100",
|
||||
color: colors.stat.max,
|
||||
defaultActive: false,
|
||||
}),
|
||||
...createCorePercentileSeries(cb.percentiles),
|
||||
price({
|
||||
metric: cb.min,
|
||||
series: cb.min,
|
||||
name: "p0",
|
||||
color: colors.stat.min,
|
||||
defaultActive: false,
|
||||
@@ -117,7 +117,7 @@ function createSingleByCoinSeries(cohort) {
|
||||
function createSingleByCapitalSeries(cohort) {
|
||||
const { color, tree } = cohort;
|
||||
return [
|
||||
price({ metric: tree.realized.investor.price, name: "Average", color }),
|
||||
price({ series: tree.realized.investor.price, name: "Average", color }),
|
||||
...createCorePercentileSeries(tree.costBasis.investedCapital),
|
||||
];
|
||||
}
|
||||
@@ -139,7 +139,7 @@ function createSingleSupplyDensitySeries(cohort) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ cohort: CohortAll | CohortFull | CohortLongTerm, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortAll | CohortFull | CohortLongTerm, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createCostBasisSectionWithPercentiles({ cohort, title }) {
|
||||
@@ -171,7 +171,7 @@ export function createCostBasisSectionWithPercentiles({ cohort, title }) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ list: readonly (CohortAll | CohortFull | CohortLongTerm)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (CohortAll | CohortFull | CohortLongTerm)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedCostBasisSectionWithPercentiles({
|
||||
@@ -194,28 +194,28 @@ export function createGroupedCostBasisSectionWithPercentiles({
|
||||
name: "Average",
|
||||
title: title("Realized Price Comparison"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ metric: tree.realized.price, name, color }),
|
||||
price({ series: tree.realized.price, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Median",
|
||||
title: title("Cost Basis Median (BTC-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ metric: tree.costBasis.percentiles.pct50, name, color }),
|
||||
price({ series: tree.costBasis.percentiles.pct50, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Q3",
|
||||
title: title("Cost Basis Q3 (BTC-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ metric: tree.costBasis.percentiles.pct75, name, color }),
|
||||
price({ series: tree.costBasis.percentiles.pct75, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Q1",
|
||||
title: title("Cost Basis Q1 (BTC-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ metric: tree.costBasis.percentiles.pct25, name, color }),
|
||||
price({ series: tree.costBasis.percentiles.pct25, name, color }),
|
||||
),
|
||||
},
|
||||
],
|
||||
@@ -227,7 +227,7 @@ export function createGroupedCostBasisSectionWithPercentiles({
|
||||
name: "Average",
|
||||
title: title("Investor Price Comparison"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ metric: tree.realized.investor.price, name, color }),
|
||||
price({ series: tree.realized.investor.price, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -235,7 +235,7 @@ export function createGroupedCostBasisSectionWithPercentiles({
|
||||
title: title("Cost Basis Median (USD-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({
|
||||
metric: tree.costBasis.investedCapital.pct50,
|
||||
series: tree.costBasis.investedCapital.pct50,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
@@ -246,7 +246,7 @@ export function createGroupedCostBasisSectionWithPercentiles({
|
||||
title: title("Cost Basis Q3 (USD-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({
|
||||
metric: tree.costBasis.investedCapital.pct75,
|
||||
series: tree.costBasis.investedCapital.pct75,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
@@ -257,7 +257,7 @@ export function createGroupedCostBasisSectionWithPercentiles({
|
||||
title: title("Cost Basis Q1 (USD-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({
|
||||
metric: tree.costBasis.investedCapital.pct25,
|
||||
series: tree.costBasis.investedCapital.pct25,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
|
||||
@@ -19,9 +19,9 @@ const isAddressable = (key) =>
|
||||
/** @type {readonly string[]} */ (ADDRESSABLE_TYPES).includes(key);
|
||||
|
||||
export function buildCohortData() {
|
||||
const utxoCohorts = brk.metrics.cohorts.utxo;
|
||||
const addressCohorts = brk.metrics.cohorts.address;
|
||||
const { addresses } = brk.metrics;
|
||||
const utxoCohorts = brk.series.cohorts.utxo;
|
||||
const addressCohorts = brk.series.cohorts.address;
|
||||
const { addresses } = brk.series;
|
||||
const {
|
||||
TERM_NAMES,
|
||||
EPOCH_NAMES,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Supply pattern capabilities by cohort type:
|
||||
* - DeltaHalfInRelTotalPattern2 (STH/LTH): inProfit + inLoss + relToCirculating + relToOwn
|
||||
* - MetricsTree_Cohorts_Utxo_All_Supply (All): inProfit + inLoss + relToOwn (no relToCirculating)
|
||||
* - SeriesTree_Cohorts_Utxo_All_Supply (All): inProfit + inLoss + relToOwn (no relToCirculating)
|
||||
* - DeltaHalfInRelTotalPattern (AgeRange/MaxAge/Epoch): inProfit + inLoss + relToCirculating (no relToOwn)
|
||||
* - DeltaHalfInTotalPattern2 (Type.*): inProfit + inLoss (no rel)
|
||||
* - DeltaHalfTotalPattern (Empty/UtxoAmount/AddrAmount): total + half only
|
||||
@@ -74,40 +74,40 @@ function fullSupplySeries(supply) {
|
||||
|
||||
/**
|
||||
* % of Own Supply series (profit/loss relative to own supply)
|
||||
* @param {{ inProfit: { relToOwn: { percent: AnyMetricPattern, ratio: AnyMetricPattern } }, inLoss: { relToOwn: { percent: AnyMetricPattern, ratio: AnyMetricPattern } } }} supply
|
||||
* @param {{ inProfit: { relToOwn: { percent: AnySeriesPattern, ratio: AnySeriesPattern } }, inLoss: { relToOwn: { percent: AnySeriesPattern, ratio: AnySeriesPattern } } }} supply
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function ownSupplyPctSeries(supply) {
|
||||
return [
|
||||
line({ metric: supply.inProfit.relToOwn.percent, name: "In Profit", color: colors.profit, unit: Unit.pctOwn }),
|
||||
line({ metric: supply.inLoss.relToOwn.percent, name: "In Loss", color: colors.loss, unit: Unit.pctOwn }),
|
||||
line({ metric: supply.inProfit.relToOwn.ratio, name: "In Profit", color: colors.profit, unit: Unit.ratio }),
|
||||
line({ metric: supply.inLoss.relToOwn.ratio, name: "In Loss", color: colors.loss, unit: Unit.ratio }),
|
||||
line({ series: supply.inProfit.relToOwn.percent, name: "In Profit", color: colors.profit, unit: Unit.pctOwn }),
|
||||
line({ series: supply.inLoss.relToOwn.percent, name: "In Loss", color: colors.loss, unit: Unit.pctOwn }),
|
||||
line({ series: supply.inProfit.relToOwn.ratio, name: "In Profit", color: colors.profit, unit: Unit.ratio }),
|
||||
line({ series: supply.inLoss.relToOwn.ratio, name: "In Loss", color: colors.loss, unit: Unit.ratio }),
|
||||
...priceLines({ numbers: [100, 50, 0], unit: Unit.pctOwn }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* % of Circulating Supply series (total, profit, loss)
|
||||
* @param {{ relToCirculating: { percent: AnyMetricPattern }, inProfit: { relToCirculating: { percent: AnyMetricPattern } }, inLoss: { relToCirculating: { percent: AnyMetricPattern } } }} supply
|
||||
* @param {{ relToCirculating: { percent: AnySeriesPattern }, inProfit: { relToCirculating: { percent: AnySeriesPattern } }, inLoss: { relToCirculating: { percent: AnySeriesPattern } } }} supply
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function circulatingSupplyPctSeries(supply) {
|
||||
return [
|
||||
line({
|
||||
metric: supply.relToCirculating.percent,
|
||||
series: supply.relToCirculating.percent,
|
||||
name: "Total",
|
||||
color: colors.default,
|
||||
unit: Unit.pctSupply,
|
||||
}),
|
||||
line({
|
||||
metric: supply.inProfit.relToCirculating.percent,
|
||||
series: supply.inProfit.relToCirculating.percent,
|
||||
name: "In Profit",
|
||||
color: colors.profit,
|
||||
unit: Unit.pctSupply,
|
||||
}),
|
||||
line({
|
||||
metric: supply.inLoss.relToCirculating.percent,
|
||||
series: supply.inLoss.relToCirculating.percent,
|
||||
name: "In Loss",
|
||||
color: colors.loss,
|
||||
unit: Unit.pctSupply,
|
||||
@@ -117,25 +117,25 @@ function circulatingSupplyPctSeries(supply) {
|
||||
|
||||
/**
|
||||
* Ratio of Circulating Supply series (total, profit, loss)
|
||||
* @param {{ relToCirculating: { ratio: AnyMetricPattern }, inProfit: { relToCirculating: { ratio: AnyMetricPattern } }, inLoss: { relToCirculating: { ratio: AnyMetricPattern } } }} supply
|
||||
* @param {{ relToCirculating: { ratio: AnySeriesPattern }, inProfit: { relToCirculating: { ratio: AnySeriesPattern } }, inLoss: { relToCirculating: { ratio: AnySeriesPattern } } }} supply
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function circulatingSupplyRatioSeries(supply) {
|
||||
return [
|
||||
line({
|
||||
metric: supply.relToCirculating.ratio,
|
||||
series: supply.relToCirculating.ratio,
|
||||
name: "Total",
|
||||
color: colors.default,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: supply.inProfit.relToCirculating.ratio,
|
||||
series: supply.inProfit.relToCirculating.ratio,
|
||||
name: "In Profit",
|
||||
color: colors.profit,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: supply.inLoss.relToCirculating.ratio,
|
||||
series: supply.inLoss.relToCirculating.ratio,
|
||||
name: "In Loss",
|
||||
color: colors.loss,
|
||||
unit: Unit.ratio,
|
||||
@@ -146,7 +146,7 @@ function circulatingSupplyRatioSeries(supply) {
|
||||
/**
|
||||
* @param {readonly (UtxoCohortObject | CohortWithoutRelative)[]} list
|
||||
* @param {CohortAll} all
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
*/
|
||||
function groupedUtxoCountChart(list, all, title) {
|
||||
return {
|
||||
@@ -154,7 +154,7 @@ function groupedUtxoCountChart(list, all, title) {
|
||||
title: title("UTXO Count"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.outputs.unspentCount.inner,
|
||||
series: tree.outputs.unspentCount.inner,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.count,
|
||||
@@ -164,9 +164,9 @@ function groupedUtxoCountChart(list, all, title) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ absolute: { _24h: AnyMetricPattern, _1w: AnyMetricPattern, _1m: AnyMetricPattern, _1y: AnyMetricPattern }, rate: { _24h: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1w: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1m: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1y: { percent: AnyMetricPattern, ratio: AnyMetricPattern } } }} delta
|
||||
* @param {{ absolute: { _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }, rate: { _24h: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, _1w: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, _1m: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, _1y: { percent: AnySeriesPattern, ratio: AnySeriesPattern } } }} delta
|
||||
* @param {Unit} unit
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} name
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
@@ -187,7 +187,7 @@ function singleDeltaTree(delta, unit, title, name) {
|
||||
* @param {A} all
|
||||
* @param {(c: T | A) => DeltaPattern} getDelta
|
||||
* @param {Unit} unit
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} name
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
@@ -201,7 +201,7 @@ function groupedDeltaTree(list, all, getDelta, unit, title, name) {
|
||||
name: w.name,
|
||||
title: title(`${name} Change (${w.name})`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ metric: getDelta(c).absolute[w.key], name: c.name, color: c.color, unit }),
|
||||
baseline({ series: getDelta(c).absolute[w.key], name: c.name, color: c.color, unit }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
@@ -221,7 +221,7 @@ function groupedDeltaTree(list, all, getDelta, unit, title, name) {
|
||||
|
||||
/**
|
||||
* @param {UtxoCohortObject | CohortWithoutRelative} cohort
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
function singleUtxoCountChart(cohort, title) {
|
||||
@@ -230,7 +230,7 @@ function singleUtxoCountChart(cohort, title) {
|
||||
title: title("UTXO Count"),
|
||||
bottom: [
|
||||
line({
|
||||
metric: cohort.tree.outputs.unspentCount.inner,
|
||||
series: cohort.tree.outputs.unspentCount.inner,
|
||||
name: "UTXO Count",
|
||||
color: cohort.color,
|
||||
unit: Unit.count,
|
||||
@@ -242,7 +242,7 @@ function singleUtxoCountChart(cohort, title) {
|
||||
|
||||
/**
|
||||
* @param {CohortAll | CohortAddress | AddressCohortObject} cohort
|
||||
* @param {(metric: string) => string} title
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
function singleAddressCountChart(cohort, title) {
|
||||
@@ -251,7 +251,7 @@ function singleAddressCountChart(cohort, title) {
|
||||
title: title("Address Count"),
|
||||
bottom: [
|
||||
line({
|
||||
metric: cohort.addressCount.inner,
|
||||
series: cohort.addressCount.inner,
|
||||
name: "Address Count",
|
||||
color: cohort.color,
|
||||
unit: Unit.count,
|
||||
@@ -268,7 +268,7 @@ function singleAddressCountChart(cohort, title) {
|
||||
/**
|
||||
* Basic holdings (total + half only, no supply breakdown)
|
||||
* For: CohortWithoutRelative, CohortBasicWithMarketCap, CohortBasicWithoutMarketCap
|
||||
* @param {{ cohort: UtxoCohortObject | CohortWithoutRelative, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: UtxoCohortObject | CohortWithoutRelative, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createHoldingsSection({ cohort, title }) {
|
||||
@@ -294,7 +294,7 @@ export function createHoldingsSection({ cohort, title }) {
|
||||
|
||||
/**
|
||||
* Holdings for CohortAll (has inProfit/inLoss with relToOwn but no relToCirculating)
|
||||
* @param {{ cohort: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createHoldingsSectionAll({ cohort, title }) {
|
||||
@@ -325,9 +325,9 @@ export function createHoldingsSectionAll({ cohort, title }) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holdings with full relative metrics (relToCirculating + relToOwn)
|
||||
* Holdings with full relative series (relToCirculating + relToOwn)
|
||||
* For: CohortFull, CohortLongTerm (have DeltaHalfInRelTotalPattern2)
|
||||
* @param {{ cohort: CohortFull | CohortLongTerm, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortFull | CohortLongTerm, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createHoldingsSectionWithRelative({ cohort, title }) {
|
||||
@@ -369,7 +369,7 @@ export function createHoldingsSectionWithRelative({ cohort, title }) {
|
||||
/**
|
||||
* Holdings with inProfit/inLoss + relToCirculating (no relToOwn)
|
||||
* For: CohortWithAdjusted, CohortAgeRange (have DeltaHalfInRelTotalPattern)
|
||||
* @param {{ cohort: CohortWithAdjusted | CohortAgeRange, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortWithAdjusted | CohortAgeRange, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createHoldingsSectionWithOwnSupply({ cohort, title }) {
|
||||
@@ -410,7 +410,7 @@ export function createHoldingsSectionWithOwnSupply({ cohort, title }) {
|
||||
/**
|
||||
* Holdings with inProfit/inLoss (no rel, no address count)
|
||||
* For: CohortWithoutRelative (p2ms, unknown, empty)
|
||||
* @param {{ cohort: CohortWithoutRelative, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortWithoutRelative, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createHoldingsSectionWithProfitLoss({ cohort, title }) {
|
||||
@@ -436,7 +436,7 @@ export function createHoldingsSectionWithProfitLoss({ cohort, title }) {
|
||||
|
||||
/**
|
||||
* Holdings for CohortAddress (has inProfit/inLoss but no rel, plus address count)
|
||||
* @param {{ cohort: CohortAddress, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortAddress, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createHoldingsSectionAddress({ cohort, title }) {
|
||||
@@ -464,7 +464,7 @@ export function createHoldingsSectionAddress({ cohort, title }) {
|
||||
|
||||
/**
|
||||
* Holdings for address amount cohorts (no inProfit/inLoss, has address count)
|
||||
* @param {{ cohort: AddressCohortObject, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: AddressCohortObject, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createHoldingsSectionAddressAmount({ cohort, title }) {
|
||||
@@ -495,7 +495,7 @@ export function createHoldingsSectionAddressAmount({ cohort, title }) {
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @param {{ list: readonly CohortAddress[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly CohortAddress[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedHoldingsSectionAddress({ list, all, title }) {
|
||||
@@ -541,7 +541,7 @@ export function createGroupedHoldingsSectionAddress({ list, all, title }) {
|
||||
name: "Address Count",
|
||||
title: title("Address Count"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, addressCount }) =>
|
||||
line({ metric: addressCount.inner, name, color, unit: Unit.count }),
|
||||
line({ series: addressCount.inner, name, color, unit: Unit.count }),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -558,7 +558,7 @@ export function createGroupedHoldingsSectionAddress({ list, all, title }) {
|
||||
|
||||
/**
|
||||
* Grouped holdings for address amount cohorts (no inProfit/inLoss, has address count)
|
||||
* @param {{ list: readonly AddressCohortObject[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly AddressCohortObject[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedHoldingsSectionAddressAmount({
|
||||
@@ -586,7 +586,7 @@ export function createGroupedHoldingsSectionAddressAmount({
|
||||
name: "Address Count",
|
||||
title: title("Address Count"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, addressCount }) =>
|
||||
line({ metric: addressCount.inner, name, color, unit: Unit.count }),
|
||||
line({ series: addressCount.inner, name, color, unit: Unit.count }),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -603,7 +603,7 @@ export function createGroupedHoldingsSectionAddressAmount({
|
||||
|
||||
/**
|
||||
* Basic grouped holdings (total + half only)
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedHoldingsSection({ list, all, title }) {
|
||||
@@ -637,7 +637,7 @@ export function createGroupedHoldingsSection({ list, all, title }) {
|
||||
/**
|
||||
* Grouped holdings with inProfit/inLoss (no rel, no address count)
|
||||
* For: CohortWithoutRelative (p2ms, unknown, empty)
|
||||
* @param {{ list: readonly CohortWithoutRelative[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly CohortWithoutRelative[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedHoldingsSectionWithProfitLoss({
|
||||
@@ -697,7 +697,7 @@ export function createGroupedHoldingsSectionWithProfitLoss({
|
||||
/**
|
||||
* Grouped holdings with inProfit/inLoss + relToCirculating (no relToOwn)
|
||||
* For: CohortWithAdjusted, CohortAgeRange
|
||||
* @param {{ list: readonly (CohortWithAdjusted | CohortAgeRange)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (CohortWithAdjusted | CohortAgeRange)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedHoldingsSectionWithOwnSupply({
|
||||
@@ -720,7 +720,7 @@ export function createGroupedHoldingsSectionWithOwnSupply({
|
||||
),
|
||||
...mapCohorts(list, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.relToCirculating.percent,
|
||||
series: tree.supply.relToCirculating.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctSupply,
|
||||
@@ -741,7 +741,7 @@ export function createGroupedHoldingsSectionWithOwnSupply({
|
||||
),
|
||||
...mapCohorts(list, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.inProfit.relToCirculating.percent,
|
||||
series: tree.supply.inProfit.relToCirculating.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctSupply,
|
||||
@@ -762,7 +762,7 @@ export function createGroupedHoldingsSectionWithOwnSupply({
|
||||
),
|
||||
...mapCohorts(list, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.inLoss.relToCirculating.percent,
|
||||
series: tree.supply.inLoss.relToCirculating.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctSupply,
|
||||
@@ -785,9 +785,9 @@ export function createGroupedHoldingsSectionWithOwnSupply({
|
||||
}
|
||||
|
||||
/**
|
||||
* Grouped holdings with full relative metrics (relToCirculating + relToOwn)
|
||||
* Grouped holdings with full relative series (relToCirculating + relToOwn)
|
||||
* For: CohortFull, CohortLongTerm
|
||||
* @param {{ list: readonly (CohortFull | CohortLongTerm)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (CohortFull | CohortLongTerm)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedHoldingsSectionWithRelative({ list, all, title }) {
|
||||
@@ -806,7 +806,7 @@ export function createGroupedHoldingsSectionWithRelative({ list, all, title }) {
|
||||
),
|
||||
...mapCohorts(list, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.relToCirculating.percent,
|
||||
series: tree.supply.relToCirculating.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctSupply,
|
||||
@@ -827,7 +827,7 @@ export function createGroupedHoldingsSectionWithRelative({ list, all, title }) {
|
||||
),
|
||||
...mapCohorts(list, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.inProfit.relToCirculating.percent,
|
||||
series: tree.supply.inProfit.relToCirculating.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctSupply,
|
||||
@@ -835,7 +835,7 @@ export function createGroupedHoldingsSectionWithRelative({ list, all, title }) {
|
||||
),
|
||||
...mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.inProfit.relToOwn.percent,
|
||||
series: tree.supply.inProfit.relToOwn.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctOwn,
|
||||
@@ -857,7 +857,7 @@ export function createGroupedHoldingsSectionWithRelative({ list, all, title }) {
|
||||
),
|
||||
...mapCohorts(list, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.inLoss.relToCirculating.percent,
|
||||
series: tree.supply.inLoss.relToCirculating.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctSupply,
|
||||
@@ -865,7 +865,7 @@ export function createGroupedHoldingsSectionWithRelative({ list, all, title }) {
|
||||
),
|
||||
...mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.supply.inLoss.relToOwn.percent,
|
||||
series: tree.supply.inLoss.relToOwn.percent,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.pctOwn,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import { formatCohortTitle, satsBtcUsd, satsBtcUsdFullTree } from "../shared.js";
|
||||
import { ROLLING_WINDOWS, line, baseline, percentRatio, rollingWindowsTree, rollingPercentRatioTree } from "../series.js";
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { colors } from "../../utils/colors.js";
|
||||
|
||||
// Section builders
|
||||
import {
|
||||
@@ -602,14 +603,12 @@ function singleBucketFolder({ name, color, pattern }) {
|
||||
name: "Supply",
|
||||
tree: [
|
||||
{
|
||||
name: "All",
|
||||
name: "Value",
|
||||
title: `${name}: Supply`,
|
||||
bottom: satsBtcUsd({ pattern: pattern.supply.all, name, color }),
|
||||
},
|
||||
{
|
||||
name: "STH",
|
||||
title: `${name}: STH Supply`,
|
||||
bottom: satsBtcUsd({ pattern: pattern.supply.sth, name, color }),
|
||||
bottom: [
|
||||
...satsBtcUsd({ pattern: pattern.supply.all, name: "Total" }),
|
||||
...satsBtcUsd({ pattern: pattern.supply.sth, name: "STH", color: colors.term.short }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Change",
|
||||
@@ -622,23 +621,16 @@ function singleBucketFolder({ name, color, pattern }) {
|
||||
},
|
||||
{
|
||||
name: "Realized Cap",
|
||||
tree: [
|
||||
{
|
||||
name: "All",
|
||||
title: `${name}: Realized Cap`,
|
||||
bottom: [line({ metric: pattern.realizedCap.all, name, color, unit: Unit.usd })],
|
||||
},
|
||||
{
|
||||
name: "STH",
|
||||
title: `${name}: STH Realized Cap`,
|
||||
bottom: [line({ metric: pattern.realizedCap.sth, name, color, unit: Unit.usd })],
|
||||
},
|
||||
title: `${name}: Realized Cap`,
|
||||
bottom: [
|
||||
line({ series: pattern.realizedCap.all, name: "Total", unit: Unit.usd }),
|
||||
line({ series: pattern.realizedCap.sth, name: "STH", color: colors.term.short, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "NUPL",
|
||||
title: `${name}: NUPL`,
|
||||
bottom: [line({ metric: pattern.nupl.ratio, name, color, unit: Unit.ratio })],
|
||||
bottom: [line({ series: pattern.nupl.ratio, name, color, unit: Unit.ratio })],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -679,7 +671,7 @@ function groupedBucketCharts(list, titlePrefix) {
|
||||
title: `${titlePrefix}: Supply Change`,
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
list.map(({ name, color, pattern }) =>
|
||||
baseline({ metric: pattern.supply.all.delta.absolute[w.key], name: `${name} ${w.name}`, color, unit: Unit.sats }),
|
||||
baseline({ series: pattern.supply.all.delta.absolute[w.key], name: `${name} ${w.name}`, color, unit: Unit.sats }),
|
||||
),
|
||||
),
|
||||
},
|
||||
@@ -687,7 +679,7 @@ function groupedBucketCharts(list, titlePrefix) {
|
||||
name: w.name,
|
||||
title: `${titlePrefix}: Supply Change ${w.name}`,
|
||||
bottom: list.map(({ name, color, pattern }) =>
|
||||
baseline({ metric: pattern.supply.all.delta.absolute[w.key], name, color, unit: Unit.sats }),
|
||||
baseline({ series: pattern.supply.all.delta.absolute[w.key], name, color, unit: Unit.sats }),
|
||||
),
|
||||
})),
|
||||
],
|
||||
@@ -724,14 +716,14 @@ function groupedBucketCharts(list, titlePrefix) {
|
||||
name: "All",
|
||||
title: `${titlePrefix}: Realized Cap`,
|
||||
bottom: list.map(({ name, color, pattern }) =>
|
||||
line({ metric: pattern.realizedCap.all, name, color, unit: Unit.usd }),
|
||||
line({ series: pattern.realizedCap.all, name, color, unit: Unit.usd }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "STH",
|
||||
title: `${titlePrefix}: STH Realized Cap`,
|
||||
bottom: list.map(({ name, color, pattern }) =>
|
||||
line({ metric: pattern.realizedCap.sth, name, color, unit: Unit.usd }),
|
||||
line({ series: pattern.realizedCap.sth, name, color, unit: Unit.usd }),
|
||||
),
|
||||
},
|
||||
],
|
||||
@@ -740,7 +732,7 @@ function groupedBucketCharts(list, titlePrefix) {
|
||||
name: "NUPL",
|
||||
title: `${titlePrefix}: NUPL`,
|
||||
bottom: list.map(({ name, color, pattern }) =>
|
||||
line({ metric: pattern.nupl.ratio, name, color, unit: Unit.ratio }),
|
||||
line({ series: pattern.nupl.ratio, name, color, unit: Unit.ratio }),
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Unit } from "../../utils/units.js";
|
||||
/**
|
||||
* Create prices section for cohorts with full ratio patterns
|
||||
* (CohortAll, CohortFull, CohortLongTerm)
|
||||
* @param {{ cohort: CohortAll | CohortFull | CohortLongTerm, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortAll | CohortFull | CohortLongTerm, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createPricesSectionFull({ cohort, title }) {
|
||||
@@ -33,10 +33,10 @@ export function createPricesSectionFull({ cohort, title }) {
|
||||
name: "Compare",
|
||||
title: title("Prices"),
|
||||
top: [
|
||||
price({ metric: tree.realized.price, name: "Realized", color: colors.realized }),
|
||||
price({ metric: tree.realized.investor.price, name: "Investor", color: colors.investor }),
|
||||
price({ metric: tree.realized.investor.upperPriceBand, name: "I²/R", color: colors.stat.max, style: 2, defaultActive: false }),
|
||||
price({ metric: tree.realized.investor.lowerPriceBand, name: "R²/I", color: colors.stat.min, style: 2, defaultActive: false }),
|
||||
price({ series: tree.realized.price, name: "Realized", color: colors.realized }),
|
||||
price({ series: tree.realized.investor.price, name: "Investor", color: colors.investor }),
|
||||
price({ series: tree.realized.investor.upperPriceBand, name: "I²/R", color: colors.stat.max, style: 2, defaultActive: false }),
|
||||
price({ series: tree.realized.investor.lowerPriceBand, name: "R²/I", color: colors.stat.min, style: 2, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -67,7 +67,7 @@ export function createPricesSectionFull({ cohort, title }) {
|
||||
/**
|
||||
* Create prices section for cohorts with basic ratio patterns only
|
||||
* (CohortWithAdjusted, CohortBasic, CohortAddress, CohortWithoutRelative)
|
||||
* @param {{ cohort: CohortWithAdjusted | CohortBasic | CohortAddress | CohortWithoutRelative | CohortAgeRange, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortWithAdjusted | CohortBasic | CohortAddress | CohortWithoutRelative | CohortAgeRange, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createPricesSectionBasic({ cohort, title }) {
|
||||
@@ -81,14 +81,14 @@ export function createPricesSectionBasic({ cohort, title }) {
|
||||
{
|
||||
name: "Price",
|
||||
title: title("Realized Price"),
|
||||
top: [price({ metric: tree.realized.price, name: "Realized", color })],
|
||||
top: [price({ series: tree.realized.price, name: "Realized", color })],
|
||||
},
|
||||
{
|
||||
name: "MVRV",
|
||||
title: title("MVRV"),
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: tree.realized.mvrv,
|
||||
series: tree.realized.mvrv,
|
||||
name: "MVRV",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
@@ -100,7 +100,7 @@ export function createPricesSectionBasic({ cohort, title }) {
|
||||
title: title("Realized Price Ratio"),
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: tree.realized.price.ratio,
|
||||
series: tree.realized.price.ratio,
|
||||
name: "Price Ratio",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
@@ -115,7 +115,7 @@ export function createPricesSectionBasic({ cohort, title }) {
|
||||
|
||||
/**
|
||||
* Create prices section for grouped cohorts
|
||||
* @param {{ list: readonly CohortObject[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly CohortObject[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedPricesSection({ list, all, title }) {
|
||||
@@ -129,7 +129,7 @@ export function createGroupedPricesSection({ list, all, title }) {
|
||||
name: "Price",
|
||||
title: title("Realized Price"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ metric: tree.realized.price, name, color }),
|
||||
price({ series: tree.realized.price, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -137,7 +137,7 @@ export function createGroupedPricesSection({ list, all, title }) {
|
||||
title: title("MVRV"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
baseline({
|
||||
metric: tree.realized.mvrv,
|
||||
series: tree.realized.mvrv,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.ratio,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@ function createSingleRealizedCapSeries(cohort) {
|
||||
const { color, tree } = cohort;
|
||||
return [
|
||||
line({
|
||||
metric: tree.realized.cap.usd,
|
||||
series: tree.realized.cap.usd,
|
||||
name: "Realized Cap",
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
@@ -33,7 +33,7 @@ function createSingleRealizedCapSeries(cohort) {
|
||||
/**
|
||||
* Create valuation section for cohorts with full ratio patterns
|
||||
* (CohortAll, CohortFull, CohortWithPercentiles)
|
||||
* @param {{ cohort: CohortAll | CohortFull | CohortLongTerm, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortAll | CohortFull | CohortLongTerm, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createValuationSectionFull({ cohort, title }) {
|
||||
@@ -77,7 +77,7 @@ export function createValuationSectionFull({ cohort, title }) {
|
||||
/**
|
||||
* Create valuation section for cohorts with basic ratio patterns
|
||||
* (CohortWithAdjusted, CohortBasic, CohortAddress, CohortWithoutRelative)
|
||||
* @param {{ cohort: CohortWithAdjusted | CohortBasic | CohortAddress | CohortWithoutRelative, title: (metric: string) => string }} args
|
||||
* @param {{ cohort: CohortWithAdjusted | CohortBasic | CohortAddress | CohortWithoutRelative, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createValuationSection({ cohort, title }) {
|
||||
@@ -102,7 +102,7 @@ export function createValuationSection({ cohort, title }) {
|
||||
title: title("MVRV"),
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: tree.realized.mvrv,
|
||||
series: tree.realized.mvrv,
|
||||
name: "MVRV",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
@@ -114,7 +114,7 @@ export function createValuationSection({ cohort, title }) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedValuationSection({ list, all, title }) {
|
||||
@@ -126,7 +126,7 @@ export function createGroupedValuationSection({ list, all, title }) {
|
||||
title: title("Realized Cap"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({
|
||||
metric: tree.realized.cap.usd,
|
||||
series: tree.realized.cap.usd,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
@@ -142,7 +142,7 @@ export function createGroupedValuationSection({ list, all, title }) {
|
||||
name: w.name,
|
||||
title: title(`Realized Cap Change (${w.name})`),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
baseline({ metric: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }),
|
||||
baseline({ series: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
@@ -163,7 +163,7 @@ export function createGroupedValuationSection({ list, all, title }) {
|
||||
title: title("MVRV"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
baseline({
|
||||
metric: tree.realized.mvrv,
|
||||
series: tree.realized.mvrv,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.ratio,
|
||||
@@ -176,7 +176,7 @@ export function createGroupedValuationSection({ list, all, title }) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ list: readonly (CohortAll | CohortFull | CohortLongTerm)[], all: CohortAll, title: (metric: string) => string }} args
|
||||
* @param {{ list: readonly (CohortAll | CohortFull | CohortLongTerm)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedValuationSectionWithOwnMarketCap({
|
||||
@@ -194,7 +194,7 @@ export function createGroupedValuationSectionWithOwnMarketCap({
|
||||
name: "USD",
|
||||
title: title("Realized Cap"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({ metric: tree.realized.cap.usd, name, color, unit: Unit.usd }),
|
||||
line({ series: tree.realized.cap.usd, name, color, unit: Unit.usd }),
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -215,7 +215,7 @@ export function createGroupedValuationSectionWithOwnMarketCap({
|
||||
name: w.name,
|
||||
title: title(`Realized Cap Change (${w.name})`),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
baseline({ metric: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }),
|
||||
baseline({ series: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
@@ -236,7 +236,7 @@ export function createGroupedValuationSectionWithOwnMarketCap({
|
||||
title: title("MVRV"),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
baseline({
|
||||
metric: tree.realized.mvrv,
|
||||
series: tree.realized.mvrv,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.ratio,
|
||||
|
||||
@@ -122,32 +122,32 @@ export function initOptions() {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const blueprint = arr[i];
|
||||
|
||||
// Check for undefined metric
|
||||
if (!blueprint.metric) {
|
||||
throw new Error(`Blueprint has undefined metric: ${blueprint.title}`);
|
||||
// Check for undefined series
|
||||
if (!blueprint.series) {
|
||||
throw new Error(`Blueprint has undefined series: ${blueprint.title}`);
|
||||
}
|
||||
|
||||
// Check for price pattern blueprint (has usd/sats sub-metrics)
|
||||
// Check for price pattern blueprint (has usd/sats sub-series)
|
||||
// Use unknown cast for safe property access check
|
||||
const maybePriceMetric =
|
||||
/** @type {{ usd?: AnyMetricPattern, sats?: AnyMetricPattern }} */ (
|
||||
/** @type {unknown} */ (blueprint.metric)
|
||||
const maybePriceSeries =
|
||||
/** @type {{ usd?: AnySeriesPattern, sats?: AnySeriesPattern }} */ (
|
||||
/** @type {unknown} */ (blueprint.series)
|
||||
);
|
||||
if (maybePriceMetric.usd?.by && maybePriceMetric.sats?.by) {
|
||||
const { usd, sats } = maybePriceMetric;
|
||||
if (maybePriceSeries.usd?.by && maybePriceSeries.sats?.by) {
|
||||
const { usd, sats } = maybePriceSeries;
|
||||
if (!usdArr) map.set(Unit.usd, (usdArr = []));
|
||||
usdArr.push({ ...blueprint, metric: usd, unit: Unit.usd });
|
||||
usdArr.push({ ...blueprint, series: usd, unit: Unit.usd });
|
||||
|
||||
if (!satsArr) map.set(Unit.sats, (satsArr = []));
|
||||
satsArr.push({ ...blueprint, metric: sats, unit: Unit.sats });
|
||||
satsArr.push({ ...blueprint, series: sats, unit: Unit.sats });
|
||||
continue;
|
||||
}
|
||||
|
||||
// After continue, we know this is a regular metric blueprint
|
||||
// After continue, we know this is a regular series blueprint
|
||||
const regularBlueprint = /** @type {AnyFetchedSeriesBlueprint} */ (
|
||||
blueprint
|
||||
);
|
||||
const metric = regularBlueprint.metric;
|
||||
const s = regularBlueprint.series;
|
||||
const unit = regularBlueprint.unit;
|
||||
if (!unit) continue;
|
||||
|
||||
@@ -163,7 +163,7 @@ export function initOptions() {
|
||||
priceSet.add(regularBlueprint.options?.baseValue?.price ?? 0);
|
||||
} else if (!type || type === "Line") {
|
||||
// Check if manual price line - avoid Object.values() array allocation
|
||||
const by = metric.by;
|
||||
const by = s.by;
|
||||
for (const k in by) {
|
||||
if (by[/** @type {Index} */ (k)]?.path?.includes("constant_")) {
|
||||
priceLines.get(unit)?.delete(parseFloat(regularBlueprint.title));
|
||||
@@ -178,9 +178,9 @@ export function initOptions() {
|
||||
const arr = map.get(unit);
|
||||
if (!arr) continue;
|
||||
for (const baseValue of values) {
|
||||
const metric = getConstant(brk.metrics.constants, baseValue);
|
||||
const s = getConstant(brk.series.constants, baseValue);
|
||||
arr.push({
|
||||
metric,
|
||||
series: s,
|
||||
title: `${baseValue}`,
|
||||
color: colors.gray,
|
||||
unit,
|
||||
@@ -371,7 +371,7 @@ export function initOptions() {
|
||||
return { nodes, count: totalCount };
|
||||
}
|
||||
|
||||
logUnused(brk.metrics, partialOptions);
|
||||
logUnused(brk.series, partialOptions);
|
||||
const { nodes: processedTree } = processPartialTree(partialOptions);
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,7 @@ const YEARS_2010S = /** @type {const} */ ([2019, 2018, 2017, 2016, 2015]);
|
||||
const periodName = (key) => periodIdToName(key.slice(1), true);
|
||||
|
||||
/**
|
||||
* @typedef {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} PercentRatioPattern
|
||||
* @typedef {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} PercentRatioPattern
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -55,8 +55,8 @@ const periodName = (key) => periodIdToName(key.slice(1), true);
|
||||
* @typedef {Object} BaseEntryItem
|
||||
* @property {string} name - Display name
|
||||
* @property {Color} color - Item color
|
||||
* @property {AnyPricePattern} costBasis - Cost basis metric
|
||||
* @property {PercentRatioPattern} returns - Returns metric
|
||||
* @property {AnyPricePattern} costBasis - Cost basis series
|
||||
* @property {PercentRatioPattern} returns - Returns series
|
||||
* @property {AnyValuePattern} stack - Stack pattern
|
||||
*/
|
||||
|
||||
@@ -90,7 +90,7 @@ function buildYearEntry(dca, year, i) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createInvestingSection() {
|
||||
const { market } = brk.metrics;
|
||||
const { market } = brk.series;
|
||||
const { dca, lookback, returns } = market;
|
||||
|
||||
return {
|
||||
@@ -111,7 +111,7 @@ export function createInvestingSection() {
|
||||
*/
|
||||
function createCompareFolder(context, items) {
|
||||
const topPane = items.map(({ name, color, costBasis }) =>
|
||||
price({ metric: costBasis, name, color }),
|
||||
price({ series: costBasis, name, color }),
|
||||
);
|
||||
return {
|
||||
name: "Compare",
|
||||
@@ -152,7 +152,7 @@ function createCompareFolder(context, items) {
|
||||
*/
|
||||
function createSingleEntryTree(item, returnsBottom) {
|
||||
const { name, titlePrefix = name, color, costBasis, stack } = item;
|
||||
const top = [price({ metric: costBasis, name: "Cost Basis", color })];
|
||||
const top = [price({ series: costBasis, name: "Cost Basis", color })];
|
||||
return {
|
||||
name,
|
||||
tree: [
|
||||
@@ -203,11 +203,11 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
|
||||
/** @param {AllPeriodKey} key */
|
||||
const topPane = (key) => [
|
||||
price({
|
||||
metric: dca.period.costBasis[key],
|
||||
series: dca.period.costBasis[key],
|
||||
name: "DCA",
|
||||
color: colors.profit,
|
||||
}),
|
||||
price({ metric: lookback[key], name: "Lump Sum", color: colors.bitcoin }),
|
||||
price({ series: lookback[key], name: "Lump Sum", color: colors.bitcoin }),
|
||||
];
|
||||
|
||||
/** @param {string} name @param {AllPeriodKey} key */
|
||||
|
||||
@@ -21,13 +21,13 @@ import { periodIdToName } from "./utils.js";
|
||||
* @typedef {Object} Period
|
||||
* @property {string} id
|
||||
* @property {Color} color
|
||||
* @property {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} returns
|
||||
* @property {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} returns
|
||||
* @property {AnyPricePattern} lookback
|
||||
* @property {boolean} [defaultActive]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Period & { cagr: { percent: AnyMetricPattern, ratio: AnyMetricPattern } }} PeriodWithCagr
|
||||
* @typedef {Period & { cagr: { percent: AnySeriesPattern, ratio: AnySeriesPattern } }} PeriodWithCagr
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -39,13 +39,13 @@ import { periodIdToName } from "./utils.js";
|
||||
|
||||
/**
|
||||
* Create index (percent) + ratio line pair from a BpsPercentRatioPattern
|
||||
* @param {{ pattern: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, name: string, color?: Color, defaultActive?: boolean }} args
|
||||
* @param {{ pattern: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, name: string, color?: Color, defaultActive?: boolean }} args
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function indexRatio({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
line({ metric: pattern.percent, name, color, defaultActive, unit: Unit.index }),
|
||||
line({ metric: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
line({ series: pattern.percent, name, color, defaultActive, unit: Unit.index }),
|
||||
line({ series: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ function createMaSubSection(label, averages) {
|
||||
name: "Compare",
|
||||
title: `Price ${label}s`,
|
||||
top: averages.map((a) =>
|
||||
price({ metric: a.ratio, name: a.id, color: a.color }),
|
||||
price({ series: a.ratio, name: a.id, color: a.color }),
|
||||
),
|
||||
},
|
||||
...common.map(toFolder),
|
||||
@@ -97,16 +97,16 @@ function createMaSubSection(label, averages) {
|
||||
* @param {string} name
|
||||
* @param {string} title
|
||||
* @param {Unit} unit
|
||||
* @param {{ _1w: AnyMetricPattern, _1m: AnyMetricPattern, _1y: AnyMetricPattern }} metrics
|
||||
* @param {{ _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }} patterns
|
||||
*/
|
||||
function volatilityChart(name, title, unit, metrics) {
|
||||
function volatilityChart(name, title, unit, patterns) {
|
||||
return {
|
||||
name,
|
||||
title,
|
||||
bottom: [
|
||||
line({ metric: metrics._1w, name: "1w", color: colors.time._1w, unit }),
|
||||
line({ metric: metrics._1m, name: "1m", color: colors.time._1m, unit }),
|
||||
line({ metric: metrics._1y, name: "1y", color: colors.time._1y, unit }),
|
||||
line({ series: patterns._1w, name: "1w", color: colors.time._1w, unit }),
|
||||
line({ series: patterns._1m, name: "1m", color: colors.time._1m, unit }),
|
||||
line({ series: patterns._1y, name: "1y", color: colors.time._1y, unit }),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -182,13 +182,13 @@ function historicalSubSection(name, periods) {
|
||||
name: "Compare",
|
||||
title: `${name} Historical`,
|
||||
top: periods.map((p) =>
|
||||
price({ metric: p.lookback, name: p.id, color: p.color }),
|
||||
price({ series: p.lookback, name: p.id, color: p.color }),
|
||||
),
|
||||
},
|
||||
...periods.map((p) => ({
|
||||
name: periodIdToName(p.id, true),
|
||||
title: `${periodIdToName(p.id, true)} Ago`,
|
||||
top: [price({ metric: p.lookback, name: "Price" })],
|
||||
top: [price({ series: p.lookback, name: "Price" })],
|
||||
})),
|
||||
],
|
||||
};
|
||||
@@ -199,7 +199,7 @@ function historicalSubSection(name, periods) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createMarketSection() {
|
||||
const { market, supply, cohorts, prices, indicators } = brk.metrics;
|
||||
const { market, supply, cohorts, prices, indicators } = brk.series;
|
||||
const {
|
||||
movingAverage: ma,
|
||||
ath,
|
||||
@@ -385,7 +385,7 @@ export function createMarketSection() {
|
||||
title: "Sats per Dollar",
|
||||
bottom: [
|
||||
line({
|
||||
metric: prices.spot.sats,
|
||||
series: prices.spot.sats,
|
||||
name: "Sats/$",
|
||||
unit: Unit.sats,
|
||||
}),
|
||||
@@ -400,7 +400,7 @@ export function createMarketSection() {
|
||||
title: "Market Capitalization",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.marketCap.usd,
|
||||
series: supply.marketCap.usd,
|
||||
name: "Market Cap",
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
@@ -411,7 +411,7 @@ export function createMarketSection() {
|
||||
title: "Realized Capitalization",
|
||||
bottom: [
|
||||
line({
|
||||
metric: cohorts.utxo.all.realized.cap.usd,
|
||||
series: cohorts.utxo.all.realized.cap.usd,
|
||||
name: "Realized Cap",
|
||||
color: colors.realized,
|
||||
unit: Unit.usd,
|
||||
@@ -428,7 +428,7 @@ export function createMarketSection() {
|
||||
color: colors.bitcoin,
|
||||
}),
|
||||
baseline({
|
||||
metric: supply.marketMinusRealizedCapGrowthRate._24h,
|
||||
series: supply.marketMinusRealizedCapGrowthRate._24h,
|
||||
name: "Market - Realized",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
@@ -443,7 +443,7 @@ export function createMarketSection() {
|
||||
{
|
||||
name: "Drawdown",
|
||||
title: "ATH Drawdown",
|
||||
top: [price({ metric: ath.high, name: "ATH" })],
|
||||
top: [price({ series: ath.high, name: "ATH" })],
|
||||
bottom: percentRatio({
|
||||
pattern: ath.drawdown,
|
||||
name: "Drawdown",
|
||||
@@ -453,26 +453,26 @@ export function createMarketSection() {
|
||||
{
|
||||
name: "Time Since",
|
||||
title: "Time Since ATH",
|
||||
top: [price({ metric: ath.high, name: "ATH" })],
|
||||
top: [price({ series: ath.high, name: "ATH" })],
|
||||
bottom: [
|
||||
line({
|
||||
metric: ath.daysSince,
|
||||
series: ath.daysSince,
|
||||
name: "Since",
|
||||
unit: Unit.days,
|
||||
}),
|
||||
line({
|
||||
metric: ath.yearsSince,
|
||||
series: ath.yearsSince,
|
||||
name: "Since",
|
||||
unit: Unit.years,
|
||||
}),
|
||||
line({
|
||||
metric: ath.maxDaysBetween,
|
||||
series: ath.maxDaysBetween,
|
||||
name: "Max",
|
||||
color: colors.loss,
|
||||
unit: Unit.days,
|
||||
}),
|
||||
line({
|
||||
metric: ath.maxYearsBetween,
|
||||
series: ath.maxYearsBetween,
|
||||
name: "Max",
|
||||
color: colors.loss,
|
||||
unit: Unit.years,
|
||||
@@ -515,13 +515,13 @@ export function createMarketSection() {
|
||||
title: "True Range",
|
||||
bottom: [
|
||||
line({
|
||||
metric: range.trueRange,
|
||||
series: range.trueRange,
|
||||
name: "Daily",
|
||||
color: colors.time._24h,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: range.trueRangeSum2w,
|
||||
series: range.trueRangeSum2w,
|
||||
name: "2w Sum",
|
||||
color: colors.time._1w,
|
||||
unit: Unit.usd,
|
||||
@@ -555,12 +555,12 @@ export function createMarketSection() {
|
||||
title: "SMA vs EMA Comparison",
|
||||
top: smaVsEma.flatMap((p) => [
|
||||
price({
|
||||
metric: p.sma,
|
||||
series: p.sma,
|
||||
name: `${p.id} SMA`,
|
||||
color: p.color,
|
||||
}),
|
||||
price({
|
||||
metric: p.ema,
|
||||
series: p.ema,
|
||||
name: `${p.id} EMA`,
|
||||
color: p.color,
|
||||
style: 1,
|
||||
@@ -571,9 +571,9 @@ export function createMarketSection() {
|
||||
name: p.name,
|
||||
title: `${p.name} SMA vs EMA`,
|
||||
top: [
|
||||
price({ metric: p.sma, name: "SMA", color: p.color }),
|
||||
price({ series: p.sma, name: "SMA", color: p.color }),
|
||||
price({
|
||||
metric: p.ema,
|
||||
series: p.ema,
|
||||
name: "EMA",
|
||||
color: p.color,
|
||||
style: 1,
|
||||
@@ -622,13 +622,13 @@ export function createMarketSection() {
|
||||
title: `${p.name} MinMax`,
|
||||
top: [
|
||||
price({
|
||||
metric: p.max,
|
||||
series: p.max,
|
||||
name: "Max",
|
||||
key: "price-max",
|
||||
color: colors.stat.max,
|
||||
}),
|
||||
price({
|
||||
metric: p.min,
|
||||
series: p.min,
|
||||
name: "Min",
|
||||
key: "price-min",
|
||||
color: colors.stat.min,
|
||||
@@ -641,17 +641,17 @@ export function createMarketSection() {
|
||||
title: "Mayer Multiple",
|
||||
top: [
|
||||
price({
|
||||
metric: ma.sma._200d,
|
||||
series: ma.sma._200d,
|
||||
name: "200d SMA",
|
||||
color: colors.indicator.main,
|
||||
}),
|
||||
price({
|
||||
metric: ma.sma._200d.x24,
|
||||
series: ma.sma._200d.x24,
|
||||
name: "200d SMA x2.4",
|
||||
color: colors.indicator.upper,
|
||||
}),
|
||||
price({
|
||||
metric: ma.sma._200d.x08,
|
||||
series: ma.sma._200d.x08,
|
||||
name: "200d SMA x0.8",
|
||||
color: colors.indicator.lower,
|
||||
}),
|
||||
@@ -698,10 +698,10 @@ export function createMarketSection() {
|
||||
name: "Components",
|
||||
title: `RSI Components (${w.name})`,
|
||||
bottom: [
|
||||
line({ metric: rsi.averageGain, name: "Avg Gain", color: colors.profit, unit: Unit.usd }),
|
||||
line({ metric: rsi.averageLoss, name: "Avg Loss", color: colors.loss, unit: Unit.usd }),
|
||||
line({ metric: rsi.gains, name: "Gains", color: colors.profit, defaultActive: false, unit: Unit.usd }),
|
||||
line({ metric: rsi.losses, name: "Losses", color: colors.loss, defaultActive: false, unit: Unit.usd }),
|
||||
line({ series: rsi.averageGain, name: "Avg Gain", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: rsi.averageLoss, name: "Avg Loss", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: rsi.gains, name: "Gains", color: colors.profit, defaultActive: false, unit: Unit.usd }),
|
||||
line({ series: rsi.losses, name: "Losses", color: colors.loss, defaultActive: false, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -753,16 +753,16 @@ export function createMarketSection() {
|
||||
name: "Compare",
|
||||
title: "MACD Comparison",
|
||||
bottom: ROLLING_WINDOWS.map((w) =>
|
||||
line({ metric: technical.macd[w.key].line, name: w.name, color: w.color, unit: Unit.usd }),
|
||||
line({ series: technical.macd[w.key].line, name: w.name, color: w.color, unit: Unit.usd }),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `MACD (${w.name})`,
|
||||
bottom: [
|
||||
line({ metric: technical.macd[w.key].line, name: "MACD", color: colors.indicator.fast, unit: Unit.usd }),
|
||||
line({ metric: technical.macd[w.key].signal, name: "Signal", color: colors.indicator.slow, unit: Unit.usd }),
|
||||
histogram({ metric: technical.macd[w.key].histogram, name: "Histogram", unit: Unit.usd }),
|
||||
line({ series: technical.macd[w.key].line, name: "MACD", color: colors.indicator.fast, unit: Unit.usd }),
|
||||
line({ series: technical.macd[w.key].signal, name: "Signal", color: colors.indicator.slow, unit: Unit.usd }),
|
||||
histogram({ series: technical.macd[w.key].histogram, name: "Histogram", unit: Unit.usd }),
|
||||
],
|
||||
})),
|
||||
],
|
||||
@@ -778,7 +778,7 @@ export function createMarketSection() {
|
||||
title: "Historical Comparison",
|
||||
top: [...shortPeriods, ...longPeriods].map((p) =>
|
||||
price({
|
||||
metric: p.lookback,
|
||||
series: p.lookback,
|
||||
name: p.id,
|
||||
color: p.color,
|
||||
defaultActive: p.defaultActive,
|
||||
@@ -795,7 +795,7 @@ export function createMarketSection() {
|
||||
title: "Dollar Cost Average Sats/Day",
|
||||
bottom: [
|
||||
line({
|
||||
metric: dca.satsPerDay,
|
||||
series: dca.satsPerDay,
|
||||
name: "Sats/Day",
|
||||
unit: Unit.sats,
|
||||
}),
|
||||
@@ -810,19 +810,19 @@ export function createMarketSection() {
|
||||
title: "Pi Cycle",
|
||||
top: [
|
||||
price({
|
||||
metric: ma.sma._111d,
|
||||
series: ma.sma._111d,
|
||||
name: "111d SMA",
|
||||
color: colors.indicator.upper,
|
||||
}),
|
||||
price({
|
||||
metric: ma.sma._350d.x2,
|
||||
series: ma.sma._350d.x2,
|
||||
name: "350d SMA x2",
|
||||
color: colors.indicator.lower,
|
||||
}),
|
||||
],
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: technical.piCycle.ratio,
|
||||
series: technical.piCycle.ratio,
|
||||
name: "Pi Cycle",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
@@ -834,7 +834,7 @@ export function createMarketSection() {
|
||||
title: "Puell Multiple",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.puellMultiple.ratio,
|
||||
series: indicators.puellMultiple.ratio,
|
||||
name: "Puell",
|
||||
color: colors.usd,
|
||||
unit: Unit.ratio,
|
||||
@@ -846,7 +846,7 @@ export function createMarketSection() {
|
||||
title: "NVT Ratio",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.nvt.ratio,
|
||||
series: indicators.nvt.ratio,
|
||||
name: "NVT",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
@@ -867,7 +867,7 @@ export function createMarketSection() {
|
||||
title: "RHODL Ratio",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.rhodlRatio.ratio,
|
||||
series: indicators.rhodlRatio.ratio,
|
||||
name: "RHODL",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
@@ -879,7 +879,7 @@ export function createMarketSection() {
|
||||
title: "Thermocap Multiple",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.thermocapMultiple.ratio,
|
||||
series: indicators.thermocapMultiple.ratio,
|
||||
name: "Thermocap",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
@@ -891,7 +891,7 @@ export function createMarketSection() {
|
||||
title: "Stock-to-Flow",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.stockToFlow,
|
||||
series: indicators.stockToFlow,
|
||||
name: "S2F",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
@@ -903,13 +903,13 @@ export function createMarketSection() {
|
||||
title: "Dormancy",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.dormancy.supplyAdjusted,
|
||||
series: indicators.dormancy.supplyAdjusted,
|
||||
name: "Supply Adjusted",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: indicators.dormancy.flow,
|
||||
series: indicators.dormancy.flow,
|
||||
name: "Flow",
|
||||
color: colors.usd,
|
||||
unit: Unit.ratio,
|
||||
@@ -922,7 +922,7 @@ export function createMarketSection() {
|
||||
title: "Seller Exhaustion Constant",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.sellerExhaustionConstant,
|
||||
series: indicators.sellerExhaustionConstant,
|
||||
name: "SEC",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
@@ -934,7 +934,7 @@ export function createMarketSection() {
|
||||
title: "Coindays Destroyed (Supply Adjusted)",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.coindaysDestroyedSupplyAdjusted,
|
||||
series: indicators.coindaysDestroyedSupplyAdjusted,
|
||||
name: "CDD SA",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
@@ -946,7 +946,7 @@ export function createMarketSection() {
|
||||
title: "Coinyears Destroyed (Supply Adjusted)",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.coinyearsDestroyedSupplyAdjusted,
|
||||
series: indicators.coinyearsDestroyedSupplyAdjusted,
|
||||
name: "CYD SA",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.ratio,
|
||||
|
||||
@@ -56,7 +56,7 @@ const ANTPOOL_AND_FRIENDS_IDS = /** @type {const} */ ([
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createMiningSection() {
|
||||
const { blocks, pools, mining } = brk.metrics;
|
||||
const { blocks, pools, mining } = brk.series;
|
||||
|
||||
// Pre-compute pool entries with resolved names
|
||||
const majorPoolData = entries(pools.major).map(([id, pool]) => ({
|
||||
@@ -101,7 +101,7 @@ export function createMiningSection() {
|
||||
title: `Blocks Mined: ${name}`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pool.blocksMined.base,
|
||||
series: pool.blocksMined.base,
|
||||
name: "base",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -113,7 +113,7 @@ export function createMiningSection() {
|
||||
title: `Blocks Mined: ${name} (Total)`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pool.blocksMined.cumulative,
|
||||
series: pool.blocksMined.cumulative,
|
||||
name: "all-time",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -180,7 +180,7 @@ export function createMiningSection() {
|
||||
title: `Blocks Mined: ${name}`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pool.blocksMined.base,
|
||||
series: pool.blocksMined.base,
|
||||
name: "base",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -192,7 +192,7 @@ export function createMiningSection() {
|
||||
title: `Blocks Mined: ${name} (Total)`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pool.blocksMined.cumulative,
|
||||
series: pool.blocksMined.cumulative,
|
||||
name: "all-time",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -215,46 +215,46 @@ export function createMiningSection() {
|
||||
title: "Network Hashrate",
|
||||
bottom: [
|
||||
dots({
|
||||
metric: mining.hashrate.rate.base,
|
||||
series: mining.hashrate.rate.base,
|
||||
name: "Hashrate",
|
||||
unit: Unit.hashRate,
|
||||
}),
|
||||
line({
|
||||
metric: mining.hashrate.rate.sma._1w,
|
||||
series: mining.hashrate.rate.sma._1w,
|
||||
name: "1w SMA",
|
||||
color: colors.time._1w,
|
||||
unit: Unit.hashRate,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: mining.hashrate.rate.sma._1m,
|
||||
series: mining.hashrate.rate.sma._1m,
|
||||
name: "1m SMA",
|
||||
color: colors.time._1m,
|
||||
unit: Unit.hashRate,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: mining.hashrate.rate.sma._2m,
|
||||
series: mining.hashrate.rate.sma._2m,
|
||||
name: "2m SMA",
|
||||
color: colors.indicator.main,
|
||||
unit: Unit.hashRate,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: mining.hashrate.rate.sma._1y,
|
||||
series: mining.hashrate.rate.sma._1y,
|
||||
name: "1y SMA",
|
||||
color: colors.time._1y,
|
||||
unit: Unit.hashRate,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dotted({
|
||||
metric: blocks.difficulty.asHash,
|
||||
series: blocks.difficulty.asHash,
|
||||
name: "Difficulty",
|
||||
color: colors.default,
|
||||
unit: Unit.hashRate,
|
||||
}),
|
||||
line({
|
||||
metric: mining.hashrate.rate.ath,
|
||||
series: mining.hashrate.rate.ath,
|
||||
name: "ATH",
|
||||
color: colors.loss,
|
||||
unit: Unit.hashRate,
|
||||
@@ -267,13 +267,13 @@ export function createMiningSection() {
|
||||
title: "Network Hashrate ATH",
|
||||
bottom: [
|
||||
line({
|
||||
metric: mining.hashrate.rate.ath,
|
||||
series: mining.hashrate.rate.ath,
|
||||
name: "ATH",
|
||||
color: colors.loss,
|
||||
unit: Unit.hashRate,
|
||||
}),
|
||||
dots({
|
||||
metric: mining.hashrate.rate.base,
|
||||
series: mining.hashrate.rate.base,
|
||||
name: "Hashrate",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.hashRate,
|
||||
@@ -301,7 +301,7 @@ export function createMiningSection() {
|
||||
title: "Mining Difficulty",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.difficulty.value,
|
||||
series: blocks.difficulty.value,
|
||||
name: "Difficulty",
|
||||
unit: Unit.difficulty,
|
||||
}),
|
||||
@@ -312,7 +312,7 @@ export function createMiningSection() {
|
||||
title: "Difficulty Epoch",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.difficulty.epoch,
|
||||
series: blocks.difficulty.epoch,
|
||||
name: "Epoch",
|
||||
unit: Unit.epoch,
|
||||
}),
|
||||
@@ -323,7 +323,7 @@ export function createMiningSection() {
|
||||
title: "Difficulty Adjustment",
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: blocks.difficulty.adjustment.percent,
|
||||
series: blocks.difficulty.adjustment.percent,
|
||||
name: "Change",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
@@ -334,12 +334,12 @@ export function createMiningSection() {
|
||||
title: "Next Difficulty Adjustment",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.difficulty.blocksBeforeNext,
|
||||
series: blocks.difficulty.blocksBeforeNext,
|
||||
name: "Remaining",
|
||||
unit: Unit.blocks,
|
||||
}),
|
||||
line({
|
||||
metric: blocks.difficulty.daysBeforeNext,
|
||||
series: blocks.difficulty.daysBeforeNext,
|
||||
name: "Remaining",
|
||||
unit: Unit.days,
|
||||
}),
|
||||
@@ -480,7 +480,7 @@ export function createMiningSection() {
|
||||
name: "sum",
|
||||
}),
|
||||
line({
|
||||
metric: mining.rewards.subsidy.sma1y.usd,
|
||||
series: mining.rewards.subsidy.sma1y.usd,
|
||||
name: "1y SMA",
|
||||
color: colors.time._1y,
|
||||
unit: Unit.usd,
|
||||
@@ -650,13 +650,13 @@ export function createMiningSection() {
|
||||
name: "Compare",
|
||||
title: "Fee-to-Subsidy Ratio",
|
||||
bottom: ROLLING_WINDOWS.map((w) =>
|
||||
line({ metric: mining.rewards.fees.ratioMultiple[w.key].ratio, name: w.name, color: w.color, unit: Unit.ratio }),
|
||||
line({ series: mining.rewards.fees.ratioMultiple[w.key].ratio, name: w.name, color: w.color, unit: Unit.ratio }),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `Fee-to-Subsidy Ratio (${w.name})`,
|
||||
bottom: [line({ metric: mining.rewards.fees.ratioMultiple[w.key].ratio, name: w.name, color: w.color, unit: Unit.ratio })],
|
||||
bottom: [line({ series: mining.rewards.fees.ratioMultiple[w.key].ratio, name: w.name, color: w.color, unit: Unit.ratio })],
|
||||
})),
|
||||
],
|
||||
},
|
||||
@@ -712,25 +712,25 @@ export function createMiningSection() {
|
||||
title: "Hash Price",
|
||||
bottom: [
|
||||
line({
|
||||
metric: mining.hashrate.price.ths,
|
||||
series: mining.hashrate.price.ths,
|
||||
name: "TH/s",
|
||||
color: colors.usd,
|
||||
unit: Unit.usdPerThsPerDay,
|
||||
}),
|
||||
line({
|
||||
metric: mining.hashrate.price.phs,
|
||||
series: mining.hashrate.price.phs,
|
||||
name: "PH/s",
|
||||
color: colors.usd,
|
||||
unit: Unit.usdPerPhsPerDay,
|
||||
}),
|
||||
dotted({
|
||||
metric: mining.hashrate.price.thsMin,
|
||||
series: mining.hashrate.price.thsMin,
|
||||
name: "TH/s Min",
|
||||
color: colors.stat.min,
|
||||
unit: Unit.usdPerThsPerDay,
|
||||
}),
|
||||
dotted({
|
||||
metric: mining.hashrate.price.phsMin,
|
||||
series: mining.hashrate.price.phsMin,
|
||||
name: "PH/s Min",
|
||||
color: colors.stat.min,
|
||||
unit: Unit.usdPerPhsPerDay,
|
||||
@@ -742,25 +742,25 @@ export function createMiningSection() {
|
||||
title: "Hash Value",
|
||||
bottom: [
|
||||
line({
|
||||
metric: mining.hashrate.value.ths,
|
||||
series: mining.hashrate.value.ths,
|
||||
name: "TH/s",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.satsPerThsPerDay,
|
||||
}),
|
||||
line({
|
||||
metric: mining.hashrate.value.phs,
|
||||
series: mining.hashrate.value.phs,
|
||||
name: "PH/s",
|
||||
color: colors.bitcoin,
|
||||
unit: Unit.satsPerPhsPerDay,
|
||||
}),
|
||||
dotted({
|
||||
metric: mining.hashrate.value.thsMin,
|
||||
series: mining.hashrate.value.thsMin,
|
||||
name: "TH/s Min",
|
||||
color: colors.stat.min,
|
||||
unit: Unit.satsPerThsPerDay,
|
||||
}),
|
||||
dotted({
|
||||
metric: mining.hashrate.value.phsMin,
|
||||
series: mining.hashrate.value.phsMin,
|
||||
name: "PH/s Min",
|
||||
color: colors.stat.min,
|
||||
unit: Unit.satsPerPhsPerDay,
|
||||
@@ -787,12 +787,12 @@ export function createMiningSection() {
|
||||
title: "Next Halving",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.halving.blocksBeforeNext,
|
||||
series: blocks.halving.blocksBeforeNext,
|
||||
name: "Remaining",
|
||||
unit: Unit.blocks,
|
||||
}),
|
||||
line({
|
||||
metric: blocks.halving.daysBeforeNext,
|
||||
series: blocks.halving.daysBeforeNext,
|
||||
name: "Remaining",
|
||||
unit: Unit.days,
|
||||
}),
|
||||
@@ -803,7 +803,7 @@ export function createMiningSection() {
|
||||
title: "Halving Epoch",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.halving.epoch,
|
||||
series: blocks.halving.epoch,
|
||||
name: "Epoch",
|
||||
unit: Unit.epoch,
|
||||
}),
|
||||
@@ -836,7 +836,7 @@ export function createMiningSection() {
|
||||
title: "Blocks Mined: Major Pools (1m)",
|
||||
bottom: featuredPools.map((p, i) =>
|
||||
line({
|
||||
metric: p.pool.blocksMined.sum._1m,
|
||||
series: p.pool.blocksMined.sum._1m,
|
||||
name: p.name,
|
||||
color: colors.at(i, featuredPools.length),
|
||||
unit: Unit.count,
|
||||
@@ -877,7 +877,7 @@ export function createMiningSection() {
|
||||
title: "Blocks Mined: AntPool & Friends (1m)",
|
||||
bottom: antpoolFriends.map((p, i) =>
|
||||
line({
|
||||
metric: p.pool.blocksMined.sum._1m,
|
||||
series: p.pool.blocksMined.sum._1m,
|
||||
name: p.name,
|
||||
color: colors.at(i, antpoolFriends.length),
|
||||
unit: Unit.count,
|
||||
|
||||
@@ -38,7 +38,7 @@ export function createNetworkSection() {
|
||||
supply,
|
||||
addresses,
|
||||
cohorts,
|
||||
} = brk.metrics;
|
||||
} = brk.series;
|
||||
|
||||
const st = colors.scriptType;
|
||||
|
||||
@@ -123,46 +123,46 @@ export function createNetworkSection() {
|
||||
name: "Funded",
|
||||
title: "Address Count by Type",
|
||||
/** @param {AddressableType} t */
|
||||
getMetric: (t) => addresses.funded[t],
|
||||
getSeries: (t) => addresses.funded[t],
|
||||
},
|
||||
{
|
||||
name: "Empty",
|
||||
title: "Empty Address Count by Type",
|
||||
/** @param {AddressableType} t */
|
||||
getMetric: (t) => addresses.empty[t],
|
||||
getSeries: (t) => addresses.empty[t],
|
||||
},
|
||||
{
|
||||
name: "Total",
|
||||
title: "Total Address Count by Type",
|
||||
/** @param {AddressableType} t */
|
||||
getMetric: (t) => addresses.total[t],
|
||||
getSeries: (t) => addresses.total[t],
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* Create address metrics tree for a given type key
|
||||
* Create address series tree for a given type key
|
||||
* @param {AddressableType | "all"} key
|
||||
* @param {string} titlePrefix
|
||||
*/
|
||||
const createAddressMetricsTree = (key, titlePrefix) => [
|
||||
const createAddressSeriesTree = (key, titlePrefix) => [
|
||||
{
|
||||
name: "Count",
|
||||
title: `${titlePrefix}Address Count`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: addresses.funded[key],
|
||||
series: addresses.funded[key],
|
||||
name: "Funded",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
line({
|
||||
metric: addresses.empty[key],
|
||||
series: addresses.empty[key],
|
||||
name: "Empty",
|
||||
color: colors.gray,
|
||||
unit: Unit.count,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: addresses.total[key],
|
||||
series: addresses.total[key],
|
||||
name: "Total",
|
||||
color: colors.default,
|
||||
unit: Unit.count,
|
||||
@@ -189,7 +189,7 @@ export function createNetworkSection() {
|
||||
name: "Sum",
|
||||
title: t,
|
||||
bottom: [
|
||||
line({ metric: p.base, name: "base", unit: Unit.count }),
|
||||
line({ series: p.base, name: "base", unit: Unit.count }),
|
||||
],
|
||||
},
|
||||
rollingWindowsTree({
|
||||
@@ -202,7 +202,7 @@ export function createNetworkSection() {
|
||||
title: `${t} (Total)`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: p.cumulative,
|
||||
series: p.cumulative,
|
||||
name: "all-time",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -219,12 +219,12 @@ export function createNetworkSection() {
|
||||
title: `${titlePrefix}Reactivated Addresses per Block`,
|
||||
bottom: [
|
||||
dots({
|
||||
metric: addresses.activity[key].reactivated.height,
|
||||
series: addresses.activity[key].reactivated.height,
|
||||
name: "base",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
line({
|
||||
metric: addresses.activity[key].reactivated._24h,
|
||||
series: addresses.activity[key].reactivated._24h,
|
||||
name: "24h avg",
|
||||
color: colors.stat.avg,
|
||||
unit: Unit.count,
|
||||
@@ -254,12 +254,12 @@ export function createNetworkSection() {
|
||||
title: `${titlePrefix}${t.title}`,
|
||||
bottom: [
|
||||
dots({
|
||||
metric: addresses.activity[key][t.key].height,
|
||||
series: addresses.activity[key][t.key].height,
|
||||
name: "base",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
line({
|
||||
metric: addresses.activity[key][t.key]._24h,
|
||||
series: addresses.activity[key][t.key]._24h,
|
||||
name: "24h avg",
|
||||
color: colors.stat.avg,
|
||||
unit: Unit.count,
|
||||
@@ -292,7 +292,7 @@ export function createNetworkSection() {
|
||||
title: `${groupName} ${c.title}`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: c.getMetric(t.key),
|
||||
series: c.getSeries(t.key),
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -305,13 +305,13 @@ export function createNetworkSection() {
|
||||
title: `${groupName} New Address Count`,
|
||||
bottom: types.flatMap((t) => [
|
||||
line({
|
||||
metric: addresses.new[t.key].base,
|
||||
series: addresses.new[t.key].base,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
}),
|
||||
line({
|
||||
metric: addresses.new[t.key].sum._24h,
|
||||
series: addresses.new[t.key].sum._24h,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -326,7 +326,7 @@ export function createNetworkSection() {
|
||||
title: `${groupName} Reactivated Addresses per Block`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key].reactivated.height,
|
||||
series: addresses.activity[t.key].reactivated.height,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -338,7 +338,7 @@ export function createNetworkSection() {
|
||||
title: `${groupName} Reactivated Addresses (${w.name})`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key].reactivated[w.key],
|
||||
series: addresses.activity[t.key].reactivated[w.key],
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -371,7 +371,7 @@ export function createNetworkSection() {
|
||||
title: `${groupName} ${tr.compareTitle}`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key][tr.key].height,
|
||||
series: addresses.activity[t.key][tr.key].height,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -383,7 +383,7 @@ export function createNetworkSection() {
|
||||
title: `${groupName} ${tr.compareTitle} (${w.name})`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key][tr.key][w.key],
|
||||
series: addresses.activity[t.key][tr.key][w.key],
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -423,7 +423,7 @@ export function createNetworkSection() {
|
||||
title: `${groupName} Output Count`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: /** @type {CountPattern<number>} */ (scripts.count[t.key])
|
||||
series: /** @type {CountPattern<number>} */ (scripts.count[t.key])
|
||||
.sum._24h,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
@@ -436,7 +436,7 @@ export function createNetworkSection() {
|
||||
title: `${groupName} Output Count (Total)`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: /** @type {CountPattern<number>} */ (scripts.count[t.key])
|
||||
series: /** @type {CountPattern<number>} */ (scripts.count[t.key])
|
||||
.cumulative,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
@@ -478,7 +478,7 @@ export function createNetworkSection() {
|
||||
title: "Market Cap",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.marketCap.usd,
|
||||
series: supply.marketCap.usd,
|
||||
name: "Market Cap",
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
@@ -758,7 +758,7 @@ export function createNetworkSection() {
|
||||
bottom: entries(transactions.versions).map(
|
||||
([v, data], i, arr) =>
|
||||
line({
|
||||
metric: data.base,
|
||||
series: data.base,
|
||||
name: v,
|
||||
color: colors.at(i, arr.length),
|
||||
unit: Unit.count,
|
||||
@@ -775,7 +775,7 @@ export function createNetworkSection() {
|
||||
([v, data], i, arr) =>
|
||||
ROLLING_WINDOWS.map((w) =>
|
||||
line({
|
||||
metric: data.sum[w.key],
|
||||
series: data.sum[w.key],
|
||||
name: `${v} ${w.name}`,
|
||||
color: colors.at(i, arr.length),
|
||||
unit: Unit.count,
|
||||
@@ -789,7 +789,7 @@ export function createNetworkSection() {
|
||||
bottom: entries(transactions.versions).map(
|
||||
([v, data], i, arr) =>
|
||||
line({
|
||||
metric: data.sum[w.key],
|
||||
series: data.sum[w.key],
|
||||
name: v,
|
||||
color: colors.at(i, arr.length),
|
||||
unit: Unit.count,
|
||||
@@ -804,7 +804,7 @@ export function createNetworkSection() {
|
||||
bottom: entries(transactions.versions).map(
|
||||
([v, data], i, arr) =>
|
||||
line({
|
||||
metric: data.cumulative,
|
||||
series: data.cumulative,
|
||||
name: v,
|
||||
color: colors.at(i, arr.length),
|
||||
unit: Unit.count,
|
||||
@@ -818,12 +818,12 @@ export function createNetworkSection() {
|
||||
title: "Transaction Velocity",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.velocity.native,
|
||||
series: supply.velocity.native,
|
||||
name: "BTC",
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: supply.velocity.fiat,
|
||||
series: supply.velocity.fiat,
|
||||
name: "USD",
|
||||
color: colors.usd,
|
||||
unit: Unit.ratio,
|
||||
@@ -845,12 +845,12 @@ export function createNetworkSection() {
|
||||
title: "Block Count",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.count.total.base,
|
||||
series: blocks.count.total.base,
|
||||
name: "base",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
line({
|
||||
metric: blocks.count.target,
|
||||
series: blocks.count.target,
|
||||
name: "Target",
|
||||
color: colors.gray,
|
||||
unit: Unit.count,
|
||||
@@ -868,7 +868,7 @@ export function createNetworkSection() {
|
||||
title: "Block Count (Total)",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.count.total.cumulative,
|
||||
series: blocks.count.total.cumulative,
|
||||
name: "all-time",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -884,12 +884,12 @@ export function createNetworkSection() {
|
||||
title: "Block Interval",
|
||||
bottom: [
|
||||
dots({
|
||||
metric: blocks.interval.height,
|
||||
series: blocks.interval.height,
|
||||
name: "base",
|
||||
unit: Unit.secs,
|
||||
}),
|
||||
line({
|
||||
metric: blocks.interval._24h,
|
||||
series: blocks.interval._24h,
|
||||
name: "24h avg",
|
||||
color: colors.stat.avg,
|
||||
unit: Unit.secs,
|
||||
@@ -912,7 +912,7 @@ export function createNetworkSection() {
|
||||
title: "Block Size",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.size.total,
|
||||
series: blocks.size.total,
|
||||
name: "base",
|
||||
unit: Unit.bytes,
|
||||
}),
|
||||
@@ -934,7 +934,7 @@ export function createNetworkSection() {
|
||||
title: "Block Size (Total)",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.size.cumulative,
|
||||
series: blocks.size.cumulative,
|
||||
name: "all-time",
|
||||
unit: Unit.bytes,
|
||||
}),
|
||||
@@ -950,7 +950,7 @@ export function createNetworkSection() {
|
||||
title: "Block Weight",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.weight.raw,
|
||||
series: blocks.weight.raw,
|
||||
name: "base",
|
||||
unit: Unit.wu,
|
||||
}),
|
||||
@@ -972,7 +972,7 @@ export function createNetworkSection() {
|
||||
title: "Block Weight (Total)",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.weight.cumulative,
|
||||
series: blocks.weight.cumulative,
|
||||
name: "all-time",
|
||||
unit: Unit.wu,
|
||||
}),
|
||||
@@ -988,7 +988,7 @@ export function createNetworkSection() {
|
||||
title: "Block vBytes",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.vbytes.base,
|
||||
series: blocks.vbytes.base,
|
||||
name: "base",
|
||||
unit: Unit.vb,
|
||||
}),
|
||||
@@ -1010,7 +1010,7 @@ export function createNetworkSection() {
|
||||
title: "Block vBytes (Total)",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.vbytes.cumulative,
|
||||
series: blocks.vbytes.cumulative,
|
||||
name: "all-time",
|
||||
unit: Unit.vb,
|
||||
}),
|
||||
@@ -1034,7 +1034,7 @@ export function createNetworkSection() {
|
||||
title: "Mining Difficulty",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.difficulty.value,
|
||||
series: blocks.difficulty.value,
|
||||
name: "Difficulty",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -1062,7 +1062,7 @@ export function createNetworkSection() {
|
||||
title: "UTXO Count",
|
||||
bottom: [
|
||||
line({
|
||||
metric: outputs.count.unspent,
|
||||
series: outputs.count.unspent,
|
||||
name: "Count",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
@@ -1073,7 +1073,7 @@ export function createNetworkSection() {
|
||||
title: "UTXO Count 30d Change",
|
||||
bottom: [
|
||||
baseline({
|
||||
metric:
|
||||
series:
|
||||
cohorts.utxo.all.outputs.unspentCount.delta.absolute._1m,
|
||||
name: "30d Change",
|
||||
unit: Unit.count,
|
||||
@@ -1085,13 +1085,13 @@ export function createNetworkSection() {
|
||||
title: "UTXO Flow",
|
||||
bottom: [
|
||||
line({
|
||||
metric: outputs.count.total.sum,
|
||||
series: outputs.count.total.sum,
|
||||
name: "Created",
|
||||
color: colors.entity.output,
|
||||
unit: Unit.count,
|
||||
}),
|
||||
line({
|
||||
metric: inputs.count.sum,
|
||||
series: inputs.count.sum,
|
||||
name: "Spent",
|
||||
color: colors.entity.input,
|
||||
unit: Unit.count,
|
||||
@@ -1121,19 +1121,19 @@ export function createNetworkSection() {
|
||||
title: "Activity Rate",
|
||||
bottom: [
|
||||
dots({
|
||||
metric: transactions.volume.txPerSec,
|
||||
series: transactions.volume.txPerSec,
|
||||
name: "TX/sec",
|
||||
color: colors.entity.tx,
|
||||
unit: Unit.perSec,
|
||||
}),
|
||||
dots({
|
||||
metric: transactions.volume.inputsPerSec,
|
||||
series: transactions.volume.inputsPerSec,
|
||||
name: "Inputs/sec",
|
||||
color: colors.entity.input,
|
||||
unit: Unit.perSec,
|
||||
}),
|
||||
dots({
|
||||
metric: transactions.volume.outputsPerSec,
|
||||
series: transactions.volume.outputsPerSec,
|
||||
name: "Outputs/sec",
|
||||
color: colors.entity.output,
|
||||
unit: Unit.perSec,
|
||||
@@ -1145,8 +1145,8 @@ export function createNetworkSection() {
|
||||
{
|
||||
name: "Addresses",
|
||||
tree: [
|
||||
// Overview - global metrics for all addresses
|
||||
{ name: "Overview", tree: createAddressMetricsTree("all", "") },
|
||||
// Overview - global series for all addresses
|
||||
{ name: "Overview", tree: createAddressSeriesTree("all", "") },
|
||||
|
||||
// Top-level Compare - all types
|
||||
{
|
||||
@@ -1159,7 +1159,7 @@ export function createNetworkSection() {
|
||||
title: c.title,
|
||||
bottom: addressTypes.map((t) =>
|
||||
line({
|
||||
metric: c.getMetric(t.key),
|
||||
series: c.getSeries(t.key),
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -1173,14 +1173,14 @@ export function createNetworkSection() {
|
||||
title: "New Address Count by Type",
|
||||
bottom: addressTypes.flatMap((t) => [
|
||||
line({
|
||||
metric: addresses.new[t.key].base,
|
||||
series: addresses.new[t.key].base,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
defaultActive: t.defaultActive,
|
||||
}),
|
||||
line({
|
||||
metric: addresses.new[t.key].sum._24h,
|
||||
series: addresses.new[t.key].sum._24h,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -1196,7 +1196,7 @@ export function createNetworkSection() {
|
||||
title: "Reactivated Addresses per Block by Type",
|
||||
bottom: addressTypes.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key].reactivated.height,
|
||||
series: addresses.activity[t.key].reactivated.height,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -1209,7 +1209,7 @@ export function createNetworkSection() {
|
||||
title: `Reactivated Addresses by Type (${w.name})`,
|
||||
bottom: addressTypes.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key].reactivated[w.key],
|
||||
series: addresses.activity[t.key].reactivated[w.key],
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -1244,7 +1244,7 @@ export function createNetworkSection() {
|
||||
title: tr.compareTitle,
|
||||
bottom: addressTypes.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key][tr.key].height,
|
||||
series: addresses.activity[t.key][tr.key].height,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -1257,7 +1257,7 @@ export function createNetworkSection() {
|
||||
title: `${tr.compareTitle} (${w.name})`,
|
||||
bottom: addressTypes.map((t) =>
|
||||
line({
|
||||
metric: addresses.activity[t.key][tr.key][w.key],
|
||||
series: addresses.activity[t.key][tr.key][w.key],
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -1278,7 +1278,7 @@ export function createNetworkSection() {
|
||||
createAddressCompare("Legacy", legacyAddresses),
|
||||
...legacyAddresses.map((t) => ({
|
||||
name: t.name,
|
||||
tree: createAddressMetricsTree(t.key, `${t.name} `),
|
||||
tree: createAddressSeriesTree(t.key, `${t.name} `),
|
||||
})),
|
||||
],
|
||||
},
|
||||
@@ -1290,7 +1290,7 @@ export function createNetworkSection() {
|
||||
createAddressCompare("SegWit", segwitAddresses),
|
||||
...segwitAddresses.map((t) => ({
|
||||
name: t.name,
|
||||
tree: createAddressMetricsTree(t.key, `${t.name} `),
|
||||
tree: createAddressSeriesTree(t.key, `${t.name} `),
|
||||
})),
|
||||
],
|
||||
},
|
||||
@@ -1302,7 +1302,7 @@ export function createNetworkSection() {
|
||||
createAddressCompare("Taproot", taprootAddresses),
|
||||
...taprootAddresses.map((t) => ({
|
||||
name: t.name,
|
||||
tree: createAddressMetricsTree(t.key, `${t.name} `),
|
||||
tree: createAddressSeriesTree(t.key, `${t.name} `),
|
||||
})),
|
||||
],
|
||||
},
|
||||
@@ -1325,7 +1325,7 @@ export function createNetworkSection() {
|
||||
title: "Output Count by Script Type",
|
||||
bottom: scriptTypes.map((t) =>
|
||||
line({
|
||||
metric: /** @type {CountPattern<number>} */ (
|
||||
series: /** @type {CountPattern<number>} */ (
|
||||
scripts.count[t.key]
|
||||
).sum._24h,
|
||||
name: t.name,
|
||||
@@ -1340,7 +1340,7 @@ export function createNetworkSection() {
|
||||
title: "Output Count by Script Type (Total)",
|
||||
bottom: scriptTypes.map((t) =>
|
||||
line({
|
||||
metric: scripts.count[t.key].cumulative,
|
||||
series: scripts.count[t.key].cumulative,
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.count,
|
||||
@@ -1440,25 +1440,25 @@ export function createNetworkSection() {
|
||||
title: "Script Adoption",
|
||||
bottom: [
|
||||
line({
|
||||
metric: scripts.adoption.segwit.percent,
|
||||
series: scripts.adoption.segwit.percent,
|
||||
name: "SegWit",
|
||||
color: colors.segwit,
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.segwit.ratio,
|
||||
series: scripts.adoption.segwit.ratio,
|
||||
name: "SegWit",
|
||||
color: colors.segwit,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.taproot.percent,
|
||||
series: scripts.adoption.taproot.percent,
|
||||
name: "Taproot",
|
||||
color: taprootAddresses[1].color,
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.taproot.ratio,
|
||||
series: scripts.adoption.taproot.ratio,
|
||||
name: "Taproot",
|
||||
color: taprootAddresses[1].color,
|
||||
unit: Unit.ratio,
|
||||
@@ -1470,12 +1470,12 @@ export function createNetworkSection() {
|
||||
title: "SegWit Adoption",
|
||||
bottom: [
|
||||
line({
|
||||
metric: scripts.adoption.segwit.percent,
|
||||
series: scripts.adoption.segwit.percent,
|
||||
name: "Adoption",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.segwit.ratio,
|
||||
series: scripts.adoption.segwit.ratio,
|
||||
name: "Adoption",
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
@@ -1486,12 +1486,12 @@ export function createNetworkSection() {
|
||||
title: "Taproot Adoption",
|
||||
bottom: [
|
||||
line({
|
||||
metric: scripts.adoption.taproot.percent,
|
||||
series: scripts.adoption.taproot.percent,
|
||||
name: "Adoption",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.taproot.ratio,
|
||||
series: scripts.adoption.taproot.ratio,
|
||||
name: "Adoption",
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
|
||||
@@ -18,11 +18,11 @@ export const ROLLING_WINDOWS = [
|
||||
];
|
||||
|
||||
/**
|
||||
* Extract a metric from each rolling window via a mapping function
|
||||
* Extract a series from each rolling window via a mapping function
|
||||
* @template T
|
||||
* @param {{ _24h: T, _1w: T, _1m: T, _1y: T }} windows
|
||||
* @param {(v: T) => AnyMetricPattern} extract
|
||||
* @returns {{ _24h: AnyMetricPattern, _1w: AnyMetricPattern, _1m: AnyMetricPattern, _1y: AnyMetricPattern }}
|
||||
* @param {(v: T) => AnySeriesPattern} extract
|
||||
* @returns {{ _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }}
|
||||
*/
|
||||
export function mapWindows(windows, extract) {
|
||||
return {
|
||||
@@ -40,7 +40,7 @@ export function mapWindows(windows, extract) {
|
||||
/**
|
||||
* Create a price series for the top pane (auto-expands to USD + sats versions)
|
||||
* @param {Object} args
|
||||
* @param {AnyPricePattern} args.metric - Price pattern with usd and sats
|
||||
* @param {AnyPricePattern} args.series - Price pattern with usd and sats
|
||||
* @param {string} args.name
|
||||
* @param {string} [args.key]
|
||||
* @param {LineStyle} [args.style]
|
||||
@@ -50,7 +50,7 @@ export function mapWindows(windows, extract) {
|
||||
* @returns {FetchedPriceSeriesBlueprint}
|
||||
*/
|
||||
export function price({
|
||||
metric,
|
||||
series,
|
||||
name,
|
||||
key,
|
||||
style,
|
||||
@@ -59,7 +59,7 @@ export function price({
|
||||
options,
|
||||
}) {
|
||||
return {
|
||||
metric,
|
||||
series,
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
@@ -86,49 +86,49 @@ function percentileSeries(pattern, unit, title) {
|
||||
const { stat } = colors;
|
||||
return [
|
||||
dots({
|
||||
metric: pattern.max,
|
||||
series: pattern.max,
|
||||
name: `${title} max`.trim(),
|
||||
color: stat.max,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.min,
|
||||
series: pattern.min,
|
||||
name: `${title} min`.trim(),
|
||||
color: stat.min,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.median,
|
||||
series: pattern.median,
|
||||
name: `${title} median`.trim(),
|
||||
color: stat.median,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct75,
|
||||
series: pattern.pct75,
|
||||
name: `${title} pct75`.trim(),
|
||||
color: stat.pct75,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct25,
|
||||
series: pattern.pct25,
|
||||
name: `${title} pct25`.trim(),
|
||||
color: stat.pct25,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct90,
|
||||
series: pattern.pct90,
|
||||
name: `${title} pct90`.trim(),
|
||||
color: stat.pct90,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct10,
|
||||
series: pattern.pct10,
|
||||
name: `${title} pct10`.trim(),
|
||||
color: stat.pct10,
|
||||
unit,
|
||||
@@ -140,7 +140,7 @@ function percentileSeries(pattern, unit, title) {
|
||||
/**
|
||||
* Create a Line series
|
||||
* @param {Object} args
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.series
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
@@ -151,7 +151,7 @@ function percentileSeries(pattern, unit, title) {
|
||||
* @returns {FetchedLineSeriesBlueprint}
|
||||
*/
|
||||
export function line({
|
||||
metric,
|
||||
series,
|
||||
name,
|
||||
key,
|
||||
style,
|
||||
@@ -161,7 +161,7 @@ export function line({
|
||||
options,
|
||||
}) {
|
||||
return {
|
||||
metric,
|
||||
series,
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
@@ -195,7 +195,7 @@ export function sparseDotted(args) {
|
||||
/**
|
||||
* Create a Dots series (line with only point markers visible)
|
||||
* @param {Object} args
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.series
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
@@ -205,7 +205,7 @@ export function sparseDotted(args) {
|
||||
* @returns {FetchedDotsSeriesBlueprint}
|
||||
*/
|
||||
export function dots({
|
||||
metric,
|
||||
series,
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
@@ -215,7 +215,7 @@ export function dots({
|
||||
}) {
|
||||
return {
|
||||
type: /** @type {const} */ ("Dots"),
|
||||
metric,
|
||||
series,
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
@@ -228,7 +228,7 @@ export function dots({
|
||||
/**
|
||||
* Create a Candlestick series
|
||||
* @param {Object} args
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.series
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
@@ -238,7 +238,7 @@ export function dots({
|
||||
* @returns {FetchedCandlestickSeriesBlueprint}
|
||||
*/
|
||||
export function candlestick({
|
||||
metric,
|
||||
series,
|
||||
name,
|
||||
key,
|
||||
defaultActive,
|
||||
@@ -247,7 +247,7 @@ export function candlestick({
|
||||
}) {
|
||||
return {
|
||||
type: /** @type {const} */ ("Candlestick"),
|
||||
metric,
|
||||
series,
|
||||
title: name,
|
||||
key,
|
||||
unit,
|
||||
@@ -259,7 +259,7 @@ export function candlestick({
|
||||
/**
|
||||
* Create a Baseline series
|
||||
* @param {Object} args
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.series
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
@@ -271,7 +271,7 @@ export function candlestick({
|
||||
* @returns {FetchedBaselineSeriesBlueprint}
|
||||
*/
|
||||
export function baseline({
|
||||
metric,
|
||||
series,
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
@@ -284,7 +284,7 @@ export function baseline({
|
||||
const isTuple = Array.isArray(color);
|
||||
return {
|
||||
type: /** @type {const} */ ("Baseline"),
|
||||
metric,
|
||||
series,
|
||||
title: name,
|
||||
key,
|
||||
color: isTuple ? undefined : color,
|
||||
@@ -313,7 +313,7 @@ export function dottedBaseline(args) {
|
||||
/**
|
||||
* Baseline series rendered as dots (points only, no line)
|
||||
* @param {Object} args
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.series
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key]
|
||||
@@ -324,7 +324,7 @@ export function dottedBaseline(args) {
|
||||
* @returns {FetchedDotsBaselineSeriesBlueprint}
|
||||
*/
|
||||
export function dotsBaseline({
|
||||
metric,
|
||||
series,
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
@@ -336,7 +336,7 @@ export function dotsBaseline({
|
||||
const isTuple = Array.isArray(color);
|
||||
return {
|
||||
type: /** @type {const} */ ("DotsBaseline"),
|
||||
metric,
|
||||
series,
|
||||
title: name,
|
||||
key,
|
||||
color: isTuple ? undefined : color,
|
||||
@@ -355,7 +355,7 @@ export function dotsBaseline({
|
||||
/**
|
||||
* Create a Histogram series
|
||||
* @param {Object} args
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {AnySeriesPattern} args.series
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
@@ -365,7 +365,7 @@ export function dotsBaseline({
|
||||
* @returns {FetchedHistogramSeriesBlueprint}
|
||||
*/
|
||||
export function histogram({
|
||||
metric,
|
||||
series,
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
@@ -375,7 +375,7 @@ export function histogram({
|
||||
}) {
|
||||
return {
|
||||
type: /** @type {const} */ ("Histogram"),
|
||||
metric,
|
||||
series,
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
@@ -388,7 +388,7 @@ export function histogram({
|
||||
/**
|
||||
* Create series from an AverageHeightMaxMedianMinP10P25P75P90Pattern (height + rolling stats)
|
||||
* @param {Object} args
|
||||
* @param {{ height: AnyMetricPattern } & Record<string, any>} args.pattern - Pattern with .height and rolling stats (p10/p25/p75/p90 as _1y24h30d7dPattern)
|
||||
* @param {{ height: AnySeriesPattern } & 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]
|
||||
@@ -408,13 +408,13 @@ export function fromBaseStatsPattern({
|
||||
const stats = statsAtWindow(pattern, window);
|
||||
return [
|
||||
dots({
|
||||
metric: pattern.height,
|
||||
series: pattern.height,
|
||||
name: title || "base",
|
||||
color: baseColor,
|
||||
unit,
|
||||
}),
|
||||
dots({
|
||||
metric: stats.average,
|
||||
series: stats.average,
|
||||
name: `${title} avg`.trim(),
|
||||
color: stat.avg,
|
||||
unit,
|
||||
@@ -425,10 +425,10 @@ export function fromBaseStatsPattern({
|
||||
}
|
||||
|
||||
/**
|
||||
* Create series from a flat stats pattern (average + pct percentiles as single metrics)
|
||||
* Create series from a flat stats pattern (average + pct percentiles as single series)
|
||||
* Use statsAtWindow() to extract from patterns with _1y24h30d7dPattern stats
|
||||
* @param {Object} args
|
||||
* @param {{ average: AnyMetricPattern, median: AnyMetricPattern, max: AnyMetricPattern, min: AnyMetricPattern, pct75: AnyMetricPattern, pct25: AnyMetricPattern, pct90: AnyMetricPattern, pct10: AnyMetricPattern }} args.pattern
|
||||
* @param {{ average: AnySeriesPattern, median: AnySeriesPattern, max: AnySeriesPattern, min: AnySeriesPattern, pct75: AnySeriesPattern, pct25: AnySeriesPattern, pct90: AnySeriesPattern, pct10: AnySeriesPattern }} args.pattern
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.title]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
@@ -437,7 +437,7 @@ export function fromStatsPattern({ pattern, unit, title = "" }) {
|
||||
return [
|
||||
{
|
||||
type: "Dots",
|
||||
metric: pattern.average,
|
||||
series: pattern.average,
|
||||
title: `${title} avg`.trim(),
|
||||
unit,
|
||||
},
|
||||
@@ -466,10 +466,10 @@ export function statsAtWindow(pattern, window) {
|
||||
/**
|
||||
* Create a Rolling folder tree from a _1m1w1y24hPattern (4 rolling windows)
|
||||
* @param {Object} args
|
||||
* @param {{ _24h: AnyMetricPattern, _1w: AnyMetricPattern, _1m: AnyMetricPattern, _1y: AnyMetricPattern }} args.windows
|
||||
* @param {{ _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }} args.windows
|
||||
* @param {string} args.title
|
||||
* @param {Unit} args.unit
|
||||
* @param {(args: {metric: AnyMetricPattern, name: string, color: Color, unit: Unit}) => AnyFetchedSeriesBlueprint} [args.series]
|
||||
* @param {(args: {series: AnySeriesPattern, name: string, color: Color, unit: Unit}) => AnyFetchedSeriesBlueprint} [args.series]
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function rollingWindowsTree({ windows, title, unit, series = line }) {
|
||||
@@ -481,7 +481,7 @@ export function rollingWindowsTree({ windows, title, unit, series = line }) {
|
||||
title: `${title} Rolling`,
|
||||
bottom: ROLLING_WINDOWS.map((w) =>
|
||||
series({
|
||||
metric: windows[w.key],
|
||||
series: windows[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
unit,
|
||||
@@ -493,7 +493,7 @@ export function rollingWindowsTree({ windows, title, unit, series = line }) {
|
||||
title: `${title} ${w.name}`,
|
||||
bottom: [
|
||||
series({
|
||||
metric: windows[w.key],
|
||||
series: windows[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
unit,
|
||||
@@ -508,7 +508,7 @@ export function rollingWindowsTree({ windows, title, unit, series = line }) {
|
||||
* Create a Distribution folder tree with stats at each rolling window (24h/7d/30d/1y)
|
||||
* @param {Object} args
|
||||
* @param {Record<string, any>} args.pattern - Pattern with pct10/pct25/... and average/median/... as _1y24h30d7dPattern
|
||||
* @param {AnyMetricPattern} [args.base] - Optional base metric to show as dots on each chart
|
||||
* @param {AnySeriesPattern} [args.base] - Optional base series to show as dots on each chart
|
||||
* @param {string} args.title
|
||||
* @param {Unit} args.unit
|
||||
* @returns {PartialOptionsGroup}
|
||||
@@ -520,7 +520,7 @@ export function distributionWindowsTree({ pattern, base, title, unit }) {
|
||||
name: w.name,
|
||||
title: `${title} Distribution (${w.name})`,
|
||||
bottom: [
|
||||
...(base ? [line({ metric: base, name: "base", unit })] : []),
|
||||
...(base ? [line({ series: base, name: "base", unit })] : []),
|
||||
...fromStatsPattern({
|
||||
pattern: statsAtWindow(pattern, w.key),
|
||||
unit,
|
||||
@@ -579,19 +579,19 @@ export const distributionBtcSatsUsd = (slot) => [
|
||||
export function fromSupplyPattern({ pattern, title, color }) {
|
||||
return [
|
||||
{
|
||||
metric: pattern.btc,
|
||||
series: pattern.btc,
|
||||
title,
|
||||
color,
|
||||
unit: Unit.btc,
|
||||
},
|
||||
{
|
||||
metric: pattern.sats,
|
||||
series: pattern.sats,
|
||||
title,
|
||||
color,
|
||||
unit: Unit.sats,
|
||||
},
|
||||
{
|
||||
metric: pattern.usd,
|
||||
series: pattern.usd,
|
||||
title,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
@@ -606,7 +606,7 @@ export function fromSupplyPattern({ pattern, title, color }) {
|
||||
/**
|
||||
* Create percent + ratio series from a BpsPercentRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} args.pattern
|
||||
* @param {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} args.pattern
|
||||
* @param {string} args.name
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -614,15 +614,15 @@ export function fromSupplyPattern({ pattern, title, color }) {
|
||||
*/
|
||||
export function percentRatio({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
line({ metric: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
line({ metric: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
line({ series: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
line({ series: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create percent + ratio dots series from a BpsPercentRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} args.pattern
|
||||
* @param {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} args.pattern
|
||||
* @param {string} args.name
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -630,15 +630,15 @@ export function percentRatio({ pattern, name, color, defaultActive }) {
|
||||
*/
|
||||
export function percentRatioDots({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
dots({ metric: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
dots({ metric: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
dots({ series: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
dots({ series: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create percent + ratio baseline series from a BpsPercentRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} args.pattern
|
||||
* @param {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} args.pattern
|
||||
* @param {string} args.name
|
||||
* @param {Color | [Color, Color]} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -646,17 +646,17 @@ export function percentRatioDots({ pattern, name, color, defaultActive }) {
|
||||
*/
|
||||
export function percentRatioBaseline({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
baseline({ metric: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
baseline({ metric: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
baseline({ series: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
baseline({ series: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Rolling folder tree where each window is a BpsPercentRatioPattern (percent + ratio)
|
||||
* @param {Object} args
|
||||
* @param {{ _24h: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1w: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1m: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1y: { percent: AnyMetricPattern, ratio: AnyMetricPattern } }} args.windows
|
||||
* @param {{ _24h: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, _1w: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, _1m: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, _1y: { percent: AnySeriesPattern, ratio: AnySeriesPattern } }} args.windows
|
||||
* @param {string} args.title
|
||||
* @param {(args: {pattern: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, name: string, color: Color}) => AnyFetchedSeriesBlueprint[]} [args.series]
|
||||
* @param {(args: {pattern: { percent: AnySeriesPattern, ratio: AnySeriesPattern }, name: string, color: Color}) => AnyFetchedSeriesBlueprint[]} [args.series]
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function rollingPercentRatioTree({ windows, title, series = percentRatio }) {
|
||||
@@ -693,51 +693,51 @@ export function rollingPercentRatioTree({ windows, title, series = percentRatio
|
||||
function distributionSeries(pattern, unit) {
|
||||
const { stat } = colors;
|
||||
return [
|
||||
dots({ metric: pattern.average, name: "avg", color: stat.avg, unit }),
|
||||
dots({ series: pattern.average, name: "avg", color: stat.avg, unit }),
|
||||
dots({
|
||||
metric: pattern.median,
|
||||
series: pattern.median,
|
||||
name: "median",
|
||||
color: stat.median,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.max,
|
||||
series: pattern.max,
|
||||
name: "max",
|
||||
color: stat.max,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.min,
|
||||
series: pattern.min,
|
||||
name: "min",
|
||||
color: stat.min,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct75,
|
||||
series: pattern.pct75,
|
||||
name: "pct75",
|
||||
color: stat.pct75,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct25,
|
||||
series: pattern.pct25,
|
||||
name: "pct25",
|
||||
color: stat.pct25,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct90,
|
||||
series: pattern.pct90,
|
||||
name: "pct90",
|
||||
color: stat.pct90,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
}),
|
||||
dots({
|
||||
metric: pattern.pct10,
|
||||
series: pattern.pct10,
|
||||
name: "pct10",
|
||||
color: stat.pct10,
|
||||
unit,
|
||||
@@ -747,32 +747,32 @@ function distributionSeries(pattern, unit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create btc/sats/usd series from metrics
|
||||
* Create btc/sats/usd series from patterns
|
||||
* @param {Object} args
|
||||
* @param {{ btc: AnyMetricPattern, sats: AnyMetricPattern, usd: AnyMetricPattern }} args.metrics
|
||||
* @param {{ btc: AnySeriesPattern, sats: AnySeriesPattern, usd: AnySeriesPattern }} args.patterns
|
||||
* @param {string} args.name
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function btcSatsUsdSeries({ metrics, name, color, defaultActive }) {
|
||||
function btcSatsUsdSeries({ patterns, name, color, defaultActive }) {
|
||||
return [
|
||||
{
|
||||
metric: metrics.btc,
|
||||
series: patterns.btc,
|
||||
title: name,
|
||||
color,
|
||||
unit: Unit.btc,
|
||||
defaultActive,
|
||||
},
|
||||
{
|
||||
metric: metrics.sats,
|
||||
series: patterns.sats,
|
||||
title: name,
|
||||
color,
|
||||
unit: Unit.sats,
|
||||
defaultActive,
|
||||
},
|
||||
{
|
||||
metric: metrics.usd,
|
||||
series: patterns.usd,
|
||||
title: name,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
@@ -804,14 +804,14 @@ export function chartsFromFull({
|
||||
{
|
||||
name: "Sum",
|
||||
title,
|
||||
bottom: [{ metric: pattern.base, title: "base", unit }],
|
||||
bottom: [{ series: pattern.base, title: "base", unit }],
|
||||
},
|
||||
rollingWindowsTree({ windows: pattern.sum, title, unit }),
|
||||
distributionWindowsTree({ pattern, title: distTitle, unit }),
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: `${title} (Total)`,
|
||||
bottom: [{ metric: pattern.cumulative, title: "all-time", unit }],
|
||||
bottom: [{ series: pattern.cumulative, title: "all-time", unit }],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -850,7 +850,7 @@ export function chartsFromSum({
|
||||
{
|
||||
name: "Sum",
|
||||
title,
|
||||
bottom: [{ metric: pattern.sum, title: "sum", color: stat.sum, unit }],
|
||||
bottom: [{ series: pattern.sum, title: "sum", color: stat.sum, unit }],
|
||||
},
|
||||
rollingWindowsTree({ windows: pattern.rolling.sum, title, unit }),
|
||||
distributionWindowsTree({ pattern: pattern.rolling, title: distTitle, unit }),
|
||||
@@ -862,7 +862,7 @@ export function chartsFromSum({
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: `${title} (Total)`,
|
||||
bottom: [{ metric: pattern.cumulative, title: "all-time", unit }],
|
||||
bottom: [{ series: pattern.cumulative, title: "all-time", unit }],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -915,13 +915,13 @@ export function chartsFromCount({ pattern, title, unit, color }) {
|
||||
{
|
||||
name: "Base",
|
||||
title,
|
||||
bottom: [{ metric: pattern.base, title: "base", color, unit }],
|
||||
bottom: [{ series: pattern.base, title: "base", color, unit }],
|
||||
},
|
||||
rollingWindowsTree({ windows: pattern.sum, title, unit }),
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: `${title} (Total)`,
|
||||
bottom: [{ metric: pattern.cumulative, title: "all-time", color, unit }],
|
||||
bottom: [{ series: pattern.cumulative, title: "all-time", color, unit }],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -939,9 +939,9 @@ export function chartsFromValueFull({ pattern, title }) {
|
||||
name: "Sum",
|
||||
title,
|
||||
bottom: [
|
||||
...btcSatsUsdSeries({ metrics: pattern.base, name: "sum" }),
|
||||
...btcSatsUsdSeries({ patterns: pattern.base, name: "sum" }),
|
||||
...btcSatsUsdSeries({
|
||||
metrics: pattern.sum._24h,
|
||||
patterns: pattern.sum._24h,
|
||||
name: "24h sum",
|
||||
defaultActive: false,
|
||||
}),
|
||||
@@ -951,7 +951,7 @@ export function chartsFromValueFull({ pattern, title }) {
|
||||
name: "Cumulative",
|
||||
title: `${title} (Total)`,
|
||||
bottom: btcSatsUsdSeries({
|
||||
metrics: pattern.cumulative,
|
||||
patterns: pattern.cumulative,
|
||||
name: "all-time",
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -72,10 +72,10 @@ export function flatMapCohortsWithAll(list, all, fn) {
|
||||
/**
|
||||
* Create a title formatter for chart titles
|
||||
* @param {string} [cohortTitle]
|
||||
* @returns {(metric: string) => string}
|
||||
* @returns {(name: string) => string}
|
||||
*/
|
||||
export const formatCohortTitle = (cohortTitle) => (metric) =>
|
||||
cohortTitle ? `${metric}: ${cohortTitle}` : metric;
|
||||
export const formatCohortTitle = (cohortTitle) => (name) =>
|
||||
cohortTitle ? `${name}: ${cohortTitle}` : name;
|
||||
|
||||
/**
|
||||
* Create sats/btc/usd line series from a pattern with .sats/.btc/.usd
|
||||
@@ -90,7 +90,7 @@ export const formatCohortTitle = (cohortTitle) => (metric) =>
|
||||
export function satsBtcUsd({ pattern, name, color, defaultActive, style }) {
|
||||
return [
|
||||
line({
|
||||
metric: pattern.btc,
|
||||
series: pattern.btc,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.btc,
|
||||
@@ -98,7 +98,7 @@ export function satsBtcUsd({ pattern, name, color, defaultActive, style }) {
|
||||
style,
|
||||
}),
|
||||
line({
|
||||
metric: pattern.sats,
|
||||
series: pattern.sats,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.sats,
|
||||
@@ -106,7 +106,7 @@ export function satsBtcUsd({ pattern, name, color, defaultActive, style }) {
|
||||
style,
|
||||
}),
|
||||
line({
|
||||
metric: pattern.usd,
|
||||
series: pattern.usd,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
@@ -119,7 +119,7 @@ export function satsBtcUsd({ pattern, name, color, defaultActive, style }) {
|
||||
/**
|
||||
* Create sats/btc/usd baseline series from a value pattern
|
||||
* @param {Object} args
|
||||
* @param {{ btc: AnyMetricPattern, sats: AnyMetricPattern, usd: AnyMetricPattern }} args.pattern
|
||||
* @param {{ btc: AnySeriesPattern, sats: AnySeriesPattern, usd: AnySeriesPattern }} args.pattern
|
||||
* @param {string} args.name
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -128,21 +128,21 @@ export function satsBtcUsd({ pattern, name, color, defaultActive, style }) {
|
||||
export function satsBtcUsdBaseline({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
baseline({
|
||||
metric: pattern.btc,
|
||||
series: pattern.btc,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.btc,
|
||||
defaultActive,
|
||||
}),
|
||||
baseline({
|
||||
metric: pattern.sats,
|
||||
series: pattern.sats,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.sats,
|
||||
defaultActive,
|
||||
}),
|
||||
baseline({
|
||||
metric: pattern.usd,
|
||||
series: pattern.usd,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
@@ -271,7 +271,7 @@ export function satsBtcUsdFullTree({ pattern, name, title, color }) {
|
||||
/**
|
||||
* Create Price + Ratio charts from a simple price pattern (BpsCentsRatioSatsUsdPattern)
|
||||
* @param {Object} args
|
||||
* @param {AnyPricePattern & { ratio: AnyMetricPattern }} args.pattern
|
||||
* @param {AnyPricePattern & { ratio: AnySeriesPattern }} args.pattern
|
||||
* @param {string} args.title
|
||||
* @param {string} args.legend
|
||||
* @param {Color} [args.color]
|
||||
@@ -282,15 +282,15 @@ export function simplePriceRatioTree({ pattern, title, legend, color }) {
|
||||
{
|
||||
name: "Price",
|
||||
title,
|
||||
top: [price({ metric: pattern, name: legend, color })],
|
||||
top: [price({ series: pattern, name: legend, color })],
|
||||
},
|
||||
{
|
||||
name: "Ratio",
|
||||
title: `${title} Ratio`,
|
||||
top: [price({ metric: pattern, name: legend, color })],
|
||||
top: [price({ series: pattern, name: legend, color })],
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: pattern.ratio,
|
||||
series: pattern.ratio,
|
||||
name: "Ratio",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
@@ -339,11 +339,11 @@ export function priceRatioPercentilesTree({
|
||||
name: "Price",
|
||||
title,
|
||||
top: [
|
||||
price({ metric: pattern, name: legend, color }),
|
||||
price({ series: pattern, name: legend, color }),
|
||||
...(priceReferences ?? []),
|
||||
...pctUsd.map(({ name, prop, color }) =>
|
||||
price({
|
||||
metric: prop,
|
||||
series: prop,
|
||||
name,
|
||||
color,
|
||||
defaultActive: false,
|
||||
@@ -356,10 +356,10 @@ export function priceRatioPercentilesTree({
|
||||
name: "Ratio",
|
||||
title: `${title} Ratio`,
|
||||
top: [
|
||||
price({ metric: pattern, name: legend, color }),
|
||||
price({ series: pattern, name: legend, color }),
|
||||
...pctUsd.map(({ name, prop, color }) =>
|
||||
price({
|
||||
metric: prop,
|
||||
series: prop,
|
||||
name,
|
||||
color,
|
||||
defaultActive: false,
|
||||
@@ -369,14 +369,14 @@ export function priceRatioPercentilesTree({
|
||||
],
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: pattern.ratio,
|
||||
series: pattern.ratio,
|
||||
name: "Ratio",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
}),
|
||||
...pctRatio.map(({ name, prop, color }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
series: prop,
|
||||
name,
|
||||
color,
|
||||
defaultActive: false,
|
||||
@@ -507,7 +507,7 @@ export function sdBandsUsd(sd) {
|
||||
/**
|
||||
* Build SD band mappings (ratio) from an SD pattern
|
||||
* @param {Ratio1ySdPattern} sd
|
||||
* @param {AnyMetricPattern} smaRatio
|
||||
* @param {AnySeriesPattern} smaRatio
|
||||
*/
|
||||
export function sdBandsRatio(sd, smaRatio) {
|
||||
return /** @type {const} */ ([
|
||||
@@ -533,19 +533,19 @@ export function sdBandsRatio(sd, smaRatio) {
|
||||
*/
|
||||
export function ratioSmas(ratio) {
|
||||
return [
|
||||
{ name: "1w SMA", metric: ratio.sma._1w.ratio },
|
||||
{ name: "1m SMA", metric: ratio.sma._1m.ratio },
|
||||
{ name: "1y SMA", metric: ratio.sma._1y.ratio },
|
||||
{ name: "2y SMA", metric: ratio.sma._2y.ratio },
|
||||
{ name: "4y SMA", metric: ratio.sma._4y.ratio },
|
||||
{ name: "All SMA", metric: ratio.sma.all.ratio, color: colors.time.all },
|
||||
{ name: "1w SMA", series: ratio.sma._1w.ratio },
|
||||
{ name: "1m SMA", series: ratio.sma._1m.ratio },
|
||||
{ name: "1y SMA", series: ratio.sma._1y.ratio },
|
||||
{ name: "2y SMA", series: ratio.sma._2y.ratio },
|
||||
{ name: "4y SMA", series: ratio.sma._4y.ratio },
|
||||
{ name: "All SMA", series: ratio.sma.all.ratio, color: colors.time.all },
|
||||
].map((s, i, arr) => ({ color: colors.at(i, arr.length), ...s }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create ratio chart from ActivePriceRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {(metric: string) => string} args.title
|
||||
* @param {(name: string) => string} args.title
|
||||
* @param {AnyPricePattern} args.pricePattern - The price pattern to show in top pane
|
||||
* @param {AnyRatioPattern} args.ratio - The ratio pattern
|
||||
* @param {Color} args.color
|
||||
@@ -557,10 +557,10 @@ export function createRatioChart({ title, pricePattern, ratio, color, name }) {
|
||||
name: name ?? "ratio",
|
||||
title: title(name ?? "Ratio"),
|
||||
top: [
|
||||
price({ metric: pricePattern, name: "Price", color }),
|
||||
price({ series: pricePattern, name: "Price", color }),
|
||||
...percentileUsdMap(ratio).map(({ name, prop, color }) =>
|
||||
price({
|
||||
metric: prop,
|
||||
series: prop,
|
||||
name,
|
||||
color,
|
||||
defaultActive: false,
|
||||
@@ -570,17 +570,17 @@ export function createRatioChart({ title, pricePattern, ratio, color, name }) {
|
||||
],
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: ratio.ratio,
|
||||
series: ratio.ratio,
|
||||
name: "Ratio",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
}),
|
||||
...ratioSmas(ratio).map(({ name, metric, color }) =>
|
||||
line({ metric, name, color, unit: Unit.ratio, defaultActive: false }),
|
||||
...ratioSmas(ratio).map(({ name, series, color }) =>
|
||||
line({ series, name, color, unit: Unit.ratio, defaultActive: false }),
|
||||
),
|
||||
...percentileMap(ratio).map(({ name, prop, color }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
series: prop,
|
||||
name,
|
||||
color,
|
||||
defaultActive: false,
|
||||
@@ -595,7 +595,7 @@ export function createRatioChart({ title, pricePattern, ratio, color, name }) {
|
||||
/**
|
||||
* Create ZScores folder from ActivePriceRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {(suffix: string) => string} args.formatTitle - Function that takes metric suffix and returns full title
|
||||
* @param {(suffix: string) => string} args.formatTitle - Function that takes series suffix and returns full title
|
||||
* @param {string} args.legend
|
||||
* @param {AnyPricePattern} args.pricePattern - The price pattern to show in top pane
|
||||
* @param {AnyRatioPattern} args.ratio - The ratio pattern
|
||||
@@ -625,10 +625,10 @@ export function createZScoresFolder({
|
||||
name: "Compare",
|
||||
title: formatTitle("Z-Scores"),
|
||||
top: [
|
||||
price({ metric: pricePattern, name: legend, color }),
|
||||
price({ series: pricePattern, name: legend, color }),
|
||||
...zscorePeriods.map((p) =>
|
||||
price({
|
||||
metric: p.sd._0sd,
|
||||
series: p.sd._0sd,
|
||||
name: `${p.name} 0σ`,
|
||||
color: p.color,
|
||||
defaultActive: false,
|
||||
@@ -638,7 +638,7 @@ export function createZScoresFolder({
|
||||
bottom: [
|
||||
...zscorePeriods.reverse().map((p) =>
|
||||
line({
|
||||
metric: p.sd.zscore,
|
||||
series: p.sd.zscore,
|
||||
name: p.name,
|
||||
color: p.color,
|
||||
unit: Unit.sd,
|
||||
@@ -653,7 +653,7 @@ export function createZScoresFolder({
|
||||
},
|
||||
...sdPats.map(({ nameAddon, titleAddon, sd, smaRatio }) => {
|
||||
const prefix = titleAddon ? `${titleAddon} ` : "";
|
||||
const topPrice = price({ metric: pricePattern, name: legend, color });
|
||||
const topPrice = price({ series: pricePattern, name: legend, color });
|
||||
return {
|
||||
name: nameAddon,
|
||||
tree: [
|
||||
@@ -665,7 +665,7 @@ export function createZScoresFolder({
|
||||
...sdBandsUsd(sd).map(
|
||||
({ name: bandName, prop, color: bandColor }) =>
|
||||
price({
|
||||
metric: prop,
|
||||
series: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
defaultActive: false,
|
||||
@@ -674,7 +674,7 @@ export function createZScoresFolder({
|
||||
],
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: sd.zscore,
|
||||
series: sd.zscore,
|
||||
name: "Z-Score",
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
@@ -694,7 +694,7 @@ export function createZScoresFolder({
|
||||
top: [topPrice],
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: ratio.ratio,
|
||||
series: ratio.ratio,
|
||||
name: "Ratio",
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
@@ -702,7 +702,7 @@ export function createZScoresFolder({
|
||||
...sdBandsRatio(sd, smaRatio).map(
|
||||
({ name: bandName, prop, color: bandColor }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
series: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
unit: Unit.ratio,
|
||||
@@ -717,7 +717,7 @@ export function createZScoresFolder({
|
||||
top: [topPrice],
|
||||
bottom: [
|
||||
line({
|
||||
metric: sd.sd,
|
||||
series: sd.sd,
|
||||
name: "Volatility",
|
||||
color: colors.gray,
|
||||
unit: Unit.percentage,
|
||||
@@ -733,7 +733,7 @@ export function createZScoresFolder({
|
||||
|
||||
/**
|
||||
* Create price + ratio + z-scores charts - flat array
|
||||
* Unified helper for averages, distribution, and other price-based metrics
|
||||
* Unified helper for averages, distribution, and other price-based series
|
||||
* @param {Object} args
|
||||
* @param {string} args.context - Context string for ratio/z-scores titles (e.g., "1 Week SMA", "STH")
|
||||
* @param {string} args.legend - Legend name for the price series
|
||||
@@ -761,7 +761,7 @@ export function createPriceRatioCharts({
|
||||
name: "Price",
|
||||
title: priceTitle ?? context,
|
||||
top: [
|
||||
price({ metric: pricePattern, name: legend, color }),
|
||||
price({ series: pricePattern, name: legend, color }),
|
||||
...(priceReferences ?? []),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
*
|
||||
* @typedef {Object} PriceSeriesBlueprintSpecific
|
||||
* @property {"Price"} type
|
||||
* @property {AnyMetricPattern} ohlcMetric - OHLC metric for candlestick (>= 1h indexes)
|
||||
* @property {AnySeriesPattern} ohlcSeries - OHLC series for candlestick (>= 1h indexes)
|
||||
* @property {[Color, Color]} [colors]
|
||||
* @property {CandlestickSeriesPartialOptions} [options]
|
||||
* @typedef {BaseSeriesBlueprint & PriceSeriesBlueprintSpecific} PriceSeriesBlueprint
|
||||
@@ -53,7 +53,7 @@
|
||||
*
|
||||
* @typedef {AnySeriesBlueprint["type"]} SeriesType
|
||||
*
|
||||
* @typedef {{ metric: AnyMetricPattern, unit?: Unit }} FetchedAnySeriesOptions
|
||||
* @typedef {{ series: AnySeriesPattern, unit?: Unit }} FetchedAnySeriesOptions
|
||||
*
|
||||
* @typedef {BaselineSeriesBlueprint & FetchedAnySeriesOptions} FetchedBaselineSeriesBlueprint
|
||||
* @typedef {CandlestickSeriesBlueprint & FetchedAnySeriesOptions} FetchedCandlestickSeriesBlueprint
|
||||
@@ -63,14 +63,14 @@
|
||||
* @typedef {DotsBaselineSeriesBlueprint & FetchedAnySeriesOptions} FetchedDotsBaselineSeriesBlueprint
|
||||
* @typedef {AnySeriesBlueprint & FetchedAnySeriesOptions} AnyFetchedSeriesBlueprint
|
||||
*
|
||||
* Any pattern with usd and sats sub-metrics (auto-expands to USD + sats)
|
||||
* @typedef {{ usd: AnyMetricPattern, sats: AnyMetricPattern }} AnyPricePattern
|
||||
* Any pattern with usd and sats sub-series (auto-expands to USD + sats)
|
||||
* @typedef {{ usd: AnySeriesPattern, sats: AnySeriesPattern }} AnyPricePattern
|
||||
*
|
||||
* Any pattern with sats, btc, and usd sub-metrics (value patterns like stack)
|
||||
* @typedef {{ sats: AnyMetricPattern, btc: AnyMetricPattern, usd: AnyMetricPattern }} AnyValuePattern
|
||||
* Any pattern with sats, btc, and usd sub-series (value patterns like stack)
|
||||
* @typedef {{ sats: AnySeriesPattern, btc: AnySeriesPattern, usd: AnySeriesPattern }} AnyValuePattern
|
||||
*
|
||||
* Top pane price series - requires a price pattern with usd/sats, auto-expands to USD + sats
|
||||
* @typedef {{ metric: AnyPricePattern }} FetchedPriceSeriesOptions
|
||||
* @typedef {{ series: AnyPricePattern }} FetchedPriceSeriesOptions
|
||||
* @typedef {LineSeriesBlueprint & FetchedPriceSeriesOptions} FetchedPriceSeriesBlueprint
|
||||
*
|
||||
* @typedef {Object} PartialOption
|
||||
|
||||
@@ -2,8 +2,8 @@ import { localhost } from "../utils/env.js";
|
||||
import { INDEX_LABEL } from "../utils/serde.js";
|
||||
|
||||
/**
|
||||
* Check if a metric pattern has at least one chartable index
|
||||
* @param {AnyMetricPattern} node
|
||||
* Check if a series pattern has at least one chartable index
|
||||
* @param {AnySeriesPattern} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasChartableIndex(node) {
|
||||
@@ -12,16 +12,16 @@ function hasChartableIndex(node) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk a metrics tree and collect all chartable metric patterns
|
||||
* Walk a series tree and collect all chartable series patterns
|
||||
* @param {TreeNode | null | undefined} node
|
||||
* @param {Map<AnyMetricPattern, string[]>} map
|
||||
* @param {Map<AnySeriesPattern, string[]>} map
|
||||
* @param {string[]} path
|
||||
*/
|
||||
function walkMetrics(node, map, path) {
|
||||
function walkSeries(node, map, path) {
|
||||
if (node && "by" in node) {
|
||||
const metricNode = /** @type {AnyMetricPattern} */ (node);
|
||||
if (!hasChartableIndex(metricNode)) return;
|
||||
map.set(metricNode, path);
|
||||
const seriesNode = /** @type {AnySeriesPattern} */ (node);
|
||||
if (!hasChartableIndex(seriesNode)) return;
|
||||
map.set(seriesNode, path);
|
||||
} else if (node && typeof node === "object") {
|
||||
for (const [key, value] of Object.entries(node)) {
|
||||
const kn = key.toLowerCase();
|
||||
@@ -56,7 +56,7 @@ function walkMetrics(node, map, path) {
|
||||
kn.endsWith("indexes")
|
||||
)
|
||||
continue;
|
||||
walkMetrics(/** @type {TreeNode | null | undefined} */ (value), map, [
|
||||
walkSeries(/** @type {TreeNode | null | undefined} */ (value), map, [
|
||||
...path,
|
||||
key,
|
||||
]);
|
||||
@@ -65,9 +65,9 @@ function walkMetrics(node, map, path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk partial options tree and delete referenced metrics from the map
|
||||
* Walk partial options tree and delete referenced series from the map
|
||||
* @param {PartialOptionsTree} options
|
||||
* @param {Map<AnyMetricPattern, string[]>} map
|
||||
* @param {Map<AnySeriesPattern, string[]>} map
|
||||
*/
|
||||
function walkOptions(options, map) {
|
||||
for (const node of options) {
|
||||
@@ -82,40 +82,40 @@ function walkOptions(options, map) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Map<AnyMetricPattern, string[]>} map
|
||||
* @param {Map<AnySeriesPattern, string[]>} map
|
||||
* @param {(AnyFetchedSeriesBlueprint | FetchedPriceSeriesBlueprint)[]} [arr]
|
||||
*/
|
||||
function markUsedBlueprints(map, arr) {
|
||||
if (!arr) return;
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const metric = arr[i].metric;
|
||||
if (!metric) continue;
|
||||
const maybePriceMetric =
|
||||
/** @type {{ usd?: AnyMetricPattern, sats?: AnyMetricPattern }} */ (
|
||||
/** @type {unknown} */ (metric)
|
||||
const s = arr[i].series;
|
||||
if (!s) continue;
|
||||
const maybePriceSeries =
|
||||
/** @type {{ usd?: AnySeriesPattern, sats?: AnySeriesPattern }} */ (
|
||||
/** @type {unknown} */ (s)
|
||||
);
|
||||
if (maybePriceMetric.usd?.by && maybePriceMetric.sats?.by) {
|
||||
map.delete(maybePriceMetric.usd);
|
||||
map.delete(maybePriceMetric.sats);
|
||||
if (maybePriceSeries.usd?.by && maybePriceSeries.sats?.by) {
|
||||
map.delete(maybePriceSeries.usd);
|
||||
map.delete(maybePriceSeries.sats);
|
||||
} else {
|
||||
map.delete(/** @type {AnyMetricPattern} */ (metric));
|
||||
map.delete(/** @type {AnySeriesPattern} */ (s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log unused metrics to console (localhost only)
|
||||
* @param {TreeNode} metricsTree
|
||||
* Log unused series to console (localhost only)
|
||||
* @param {TreeNode} seriesTree
|
||||
* @param {PartialOptionsTree} partialOptions
|
||||
*/
|
||||
export function logUnused(metricsTree, partialOptions) {
|
||||
export function logUnused(seriesTree, partialOptions) {
|
||||
if (!localhost) return;
|
||||
|
||||
console.log(extractTreeStructure(partialOptions));
|
||||
|
||||
/** @type {Map<AnyMetricPattern, string[]>} */
|
||||
/** @type {Map<AnySeriesPattern, string[]>} */
|
||||
const all = new Map();
|
||||
walkMetrics(metricsTree, all, []);
|
||||
walkSeries(seriesTree, all, []);
|
||||
walkOptions(partialOptions, all);
|
||||
|
||||
if (!all.size) return;
|
||||
@@ -135,7 +135,7 @@ export function logUnused(metricsTree, partialOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Unused metrics:", { count: all.size, tree });
|
||||
console.log("Unused series:", { count: all.size, tree });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,10 +154,10 @@ export function extractTreeStructure(options) {
|
||||
/** @type {Record<string, string[]>} */
|
||||
const grouped = {};
|
||||
for (const s of series) {
|
||||
const metric = /** @type {AnyMetricPattern | AnyPricePattern} */ (
|
||||
s.metric
|
||||
const pattern = /** @type {AnySeriesPattern | AnyPricePattern} */ (
|
||||
s.series
|
||||
);
|
||||
if (isTop && "usd" in metric && "sats" in metric) {
|
||||
if (isTop && "usd" in pattern && "sats" in pattern) {
|
||||
const title = s.title || s.key || "unnamed";
|
||||
(grouped["USD"] ??= []).push(title);
|
||||
(grouped["sats"] ??= []).push(title);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// import { randomFromArray } from "../utils/array.js";
|
||||
// import { createButtonElement, createHeader, createSelect } from "../utils/dom.js";
|
||||
// import { tableElement } from "../utils/elements.js";
|
||||
// import { serdeMetrics, serdeString } from "../utils/serde.js";
|
||||
// import { serdeSeries, serdeString } from "../utils/serde.js";
|
||||
// import { resetParams } from "../utils/url.js";
|
||||
|
||||
// export function init() {
|
||||
@@ -45,7 +45,7 @@
|
||||
// // * @param {Resources} args.resources
|
||||
// // */
|
||||
// // function createTable({ brk, signals, option, resources }) {
|
||||
// // const indexToMetrics = createIndexToMetrics(metricToIndexes);
|
||||
// // const indexToSeries = createIndexToMetrics(seriesToIndexes);
|
||||
|
||||
// // const serializedIndexes = createSerializedIndexes();
|
||||
// // /** @type {SerializedIndex} */
|
||||
@@ -78,17 +78,17 @@
|
||||
// // resetParams(option);
|
||||
// // }
|
||||
|
||||
// // const possibleMetrics = indexToMetrics[index];
|
||||
// // const possibleSeries = indexToSeries[index];
|
||||
|
||||
// // const columns = signals.createSignal(/** @type {Metric[]} */ ([]), {
|
||||
// // equals: false,
|
||||
// // save: {
|
||||
// // ...serdeMetrics,
|
||||
// // ...serdeSeries,
|
||||
// // keyPrefix: `table-${serializedIndex()}`,
|
||||
// // key: `columns`,
|
||||
// // },
|
||||
// // });
|
||||
// // columns.set((l) => l.filter((id) => possibleMetrics.includes(id)));
|
||||
// // columns.set((l) => l.filter((id) => possibleSeries.includes(id)));
|
||||
|
||||
// // signals.createEffect(columns, (columns) => {
|
||||
// // console.log(columns);
|
||||
@@ -204,35 +204,35 @@
|
||||
// // const owner = signals.getOwner();
|
||||
|
||||
// // /**
|
||||
// // * @param {Metric} metric
|
||||
// // * @param {Series} s
|
||||
// // * @param {number} [_colIndex]
|
||||
// // */
|
||||
// // function addCol(metric, _colIndex = columns().length) {
|
||||
// // function addCol(s, _colIndex = columns().length) {
|
||||
// // signals.runWithOwner(owner, () => {
|
||||
// // /** @type {VoidFunction | undefined} */
|
||||
// // let dispose;
|
||||
// // signals.createRoot((_dispose) => {
|
||||
// // dispose = _dispose;
|
||||
|
||||
// // const metricOption = signals.createSignal({
|
||||
// // name: metric,
|
||||
// // value: metric,
|
||||
// // const seriesOption = signals.createSignal({
|
||||
// // name: s,
|
||||
// // value: s,
|
||||
// // });
|
||||
// // const { select } = createSelect({
|
||||
// // list: possibleMetrics.map((metric) => ({
|
||||
// // name: metric,
|
||||
// // value: metric,
|
||||
// // list: possibleSeries.map((s) => ({
|
||||
// // name: s,
|
||||
// // value: s,
|
||||
// // })),
|
||||
// // signal: metricOption,
|
||||
// // signal: seriesOption,
|
||||
// // });
|
||||
|
||||
// // signals.createEffect(metricOption, (metricOption) => {
|
||||
// // select.style.width = `${21 + 7.25 * metricOption.name.length}px`;
|
||||
// // signals.createEffect(seriesOption, (seriesOption) => {
|
||||
// // select.style.width = `${21 + 7.25 * seriesOption.name.length}px`;
|
||||
// // });
|
||||
|
||||
// // if (_colIndex === columns().length) {
|
||||
// // columns.set((l) => {
|
||||
// // l.push(metric);
|
||||
// // l.push(s);
|
||||
// // return l;
|
||||
// // });
|
||||
// // }
|
||||
@@ -282,7 +282,7 @@
|
||||
|
||||
// // const th = addThCol({
|
||||
// // select,
|
||||
// // unit: serdeUnit.deserialize(metric),
|
||||
// // unit: serdeUnit.deserialize(s),
|
||||
// // onLeft: createMoveColumnFunction(false),
|
||||
// // onRight: createMoveColumnFunction(true),
|
||||
// // onRemove: () => {
|
||||
@@ -314,23 +314,23 @@
|
||||
// // }
|
||||
|
||||
// // signals.createEffect(
|
||||
// // () => metricOption().name,
|
||||
// // (metric, prevMetric) => {
|
||||
// // const unit = serdeUnit.deserialize(metric);
|
||||
// // () => seriesOption().name,
|
||||
// // (s, prevSeries) => {
|
||||
// // const unit = serdeUnit.deserialize(s);
|
||||
// // th.setUnit(unit);
|
||||
|
||||
// // const vec = resources.getOrCreate(index, metric);
|
||||
// // const vec = resources.getOrCreate(index, s);
|
||||
|
||||
// // vec.fetch({ from, to });
|
||||
|
||||
// // const fetchedKey = resources.genFetchedKey({ from, to });
|
||||
|
||||
// // columns.set((l) => {
|
||||
// // const i = l.indexOf(prevMetric ?? metric);
|
||||
// // const i = l.indexOf(prevSeries ?? s);
|
||||
// // if (i === -1) {
|
||||
// // l.push(metric);
|
||||
// // l.push(s);
|
||||
// // } else {
|
||||
// // l[i] = metric;
|
||||
// // l[i] = s;
|
||||
// // }
|
||||
// // return l;
|
||||
// // });
|
||||
@@ -355,7 +355,7 @@
|
||||
// // },
|
||||
// // );
|
||||
|
||||
// // return () => metric;
|
||||
// // return () => s;
|
||||
// // },
|
||||
// // );
|
||||
// // });
|
||||
@@ -367,10 +367,10 @@
|
||||
// // });
|
||||
// // }
|
||||
|
||||
// // columns().forEach((metric, colIndex) => addCol(metric, colIndex));
|
||||
// // columns().forEach((s, colIndex) => addCol(s, colIndex));
|
||||
|
||||
// // obj.addRandomCol = function () {
|
||||
// // addCol(randomFromArray(possibleMetrics));
|
||||
// // addCol(randomFromArray(possibleSeries));
|
||||
// // };
|
||||
|
||||
// // return () => index;
|
||||
@@ -380,24 +380,24 @@
|
||||
// // }
|
||||
|
||||
// /**
|
||||
// * @param {MetricToIndexes} metricToIndexes
|
||||
// * @param {SeriesToIndexes} seriesToIndexes
|
||||
// */
|
||||
// function createIndexToMetrics(metricToIndexes) {
|
||||
// // const indexToMetrics = Object.entries(metricToIndexes).reduce(
|
||||
// function createIndexToMetrics(seriesToIndexes) {
|
||||
// // const indexToSeries = Object.entries(seriesToIndexes).reduce(
|
||||
// // (arr, [_id, indexes]) => {
|
||||
// // const id = /** @type {Metric} */ (_id);
|
||||
// // const id = /** @type {Series} */ (_id);
|
||||
// // indexes.forEach((i) => {
|
||||
// // arr[i] ??= [];
|
||||
// // arr[i].push(id);
|
||||
// // });
|
||||
// // return arr;
|
||||
// // },
|
||||
// // /** @type {Metric[][]} */ (Array.from({ length: 24 })),
|
||||
// // /** @type {Series[][]} */ (Array.from({ length: 24 })),
|
||||
// // );
|
||||
// // indexToMetrics.forEach((arr) => {
|
||||
// // indexToSeries.forEach((arr) => {
|
||||
// // arr.sort();
|
||||
// // });
|
||||
// // return indexToMetrics;
|
||||
// // return indexToSeries;
|
||||
// }
|
||||
|
||||
// /**
|
||||
|
||||
@@ -40,14 +40,14 @@ export function init() {
|
||||
/** @type {Map<Unit, AnyFetchedSeriesBlueprint[]>} */
|
||||
const result = new Map();
|
||||
|
||||
const { ohlc, spot } = brk.metrics.prices;
|
||||
const { ohlc, spot } = brk.series.prices;
|
||||
|
||||
result.set(Unit.usd, [
|
||||
/** @type {AnyFetchedSeriesBlueprint} */ ({
|
||||
type: "Price",
|
||||
title: "Price",
|
||||
metric: spot.usd,
|
||||
ohlcMetric: ohlc.usd,
|
||||
series: spot.usd,
|
||||
ohlcSeries: ohlc.usd,
|
||||
}),
|
||||
...(optionTop.get(Unit.usd) ?? []),
|
||||
]);
|
||||
@@ -56,8 +56,8 @@ export function init() {
|
||||
/** @type {AnyFetchedSeriesBlueprint} */ ({
|
||||
type: "Price",
|
||||
title: "Price",
|
||||
metric: spot.sats,
|
||||
ohlcMetric: ohlc.sats,
|
||||
series: spot.sats,
|
||||
ohlcSeries: ohlc.sats,
|
||||
colors: /** @type {const} */ ([colors.bi.p1[1], colors.bi.p1[0]]),
|
||||
}),
|
||||
...(optionTop.get(Unit.sats) ?? []),
|
||||
@@ -143,10 +143,10 @@ function computeChoices(opt) {
|
||||
[Array.from(opt.top().values()), Array.from(opt.bottom().values())]
|
||||
.flat(2)
|
||||
.filter((blueprint) => {
|
||||
const path = Object.values(blueprint.metric.by)[0]?.path ?? "";
|
||||
const path = Object.values(blueprint.series.by)[0]?.path ?? "";
|
||||
return !path.includes("constant_");
|
||||
})
|
||||
.flatMap((blueprint) => blueprint.metric.indexes()),
|
||||
.flatMap((blueprint) => blueprint.series.indexes()),
|
||||
);
|
||||
|
||||
const groups = ALL_GROUPS
|
||||
|
||||
+24
-24
@@ -2,7 +2,7 @@
|
||||
* @import { IChartApi, ISeriesApi as _ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData as _BaselineData, HistogramData as _HistogramData, SeriesType as LCSeriesType, IPaneApi, LineSeriesPartialOptions as _LineSeriesPartialOptions, HistogramSeriesPartialOptions as _HistogramSeriesPartialOptions, BaselineSeriesPartialOptions as _BaselineSeriesPartialOptions, CandlestickSeriesPartialOptions as _CandlestickSeriesPartialOptions, WhitespaceData, DeepPartial, ChartOptions, Time, LineData as _LineData, createChart as CreateLCChart, LineStyle, createSeriesMarkers as CreateSeriesMarkers, SeriesMarker, ISeriesMarkersPluginApi } from './modules/lightweight-charts/5.1.0/dist/typings.js'
|
||||
*
|
||||
* @import * as Brk from "./modules/brk-client/index.js"
|
||||
* @import { BrkClient, Index, Metric, MetricData } from "./modules/brk-client/index.js"
|
||||
* @import { BrkClient, Index, Series as BrkSeries, SeriesData } from "./modules/brk-client/index.js"
|
||||
*
|
||||
* @import { Options } from './options/full.js'
|
||||
*
|
||||
@@ -30,17 +30,17 @@
|
||||
* @typedef {SeriesMarker<Time>} TimeSeriesMarker
|
||||
*
|
||||
* Brk tree types (stable across regenerations)
|
||||
* @typedef {Brk.MetricsTree_Cohorts_Utxo} UtxoCohortTree
|
||||
* @typedef {Brk.MetricsTree_Cohorts_Address} AddressCohortTree
|
||||
* @typedef {Brk.MetricsTree_Cohorts_Utxo_All} AllUtxoPattern
|
||||
* @typedef {Brk.MetricsTree_Cohorts_Utxo_Sth} ShortTermPattern
|
||||
* @typedef {Brk.MetricsTree_Cohorts_Utxo_Lth} LongTermPattern
|
||||
* @typedef {Brk.MetricsTree_Cohorts_Utxo_All_Unrealized} AllRelativePattern
|
||||
* @typedef {Brk.SeriesTree_Cohorts_Utxo} UtxoCohortTree
|
||||
* @typedef {Brk.SeriesTree_Cohorts_Address} AddressCohortTree
|
||||
* @typedef {Brk.SeriesTree_Cohorts_Utxo_All} AllUtxoPattern
|
||||
* @typedef {Brk.SeriesTree_Cohorts_Utxo_Sth} ShortTermPattern
|
||||
* @typedef {Brk.SeriesTree_Cohorts_Utxo_Lth} LongTermPattern
|
||||
* @typedef {Brk.SeriesTree_Cohorts_Utxo_All_Unrealized} AllRelativePattern
|
||||
* @typedef {keyof Brk.BtcCentsSatsUsdPattern} BtcSatsUsdKey
|
||||
* @typedef {Brk.BtcCentsSatsUsdPattern} SupplyPattern
|
||||
* @typedef {Brk.AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern} BlockSizePattern
|
||||
* @typedef {keyof Brk.MetricsTree_Cohorts_Utxo_Type} SpendableType
|
||||
* @typedef {keyof Brk.MetricsTree_Addresses_Raw} AddressableType
|
||||
* @typedef {keyof Brk.SeriesTree_Cohorts_Utxo_Type} SpendableType
|
||||
* @typedef {keyof Brk.SeriesTree_Addresses_Raw} AddressableType
|
||||
*
|
||||
* Brk pattern types (using new pattern names)
|
||||
* @typedef {Brk.ActivityOutputsRealizedSupplyUnrealizedPattern} MaxAgePattern
|
||||
@@ -68,15 +68,15 @@
|
||||
* @typedef {Brk.AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern} RollingWindowSlot
|
||||
* AnyValuePatternType: union of all value pattern types
|
||||
* @typedef {Brk.BaseCumulativeSumPattern4 | Brk.BaseCumulativeSumPattern<number> | Brk.BaseCumulativeRelPattern} AnyValuePatternType
|
||||
* @typedef {Brk.AnyMetricPattern} AnyMetricPattern
|
||||
* @typedef {Brk.AnySeriesPattern} AnySeriesPattern
|
||||
* @typedef {Brk.CentsSatsUsdPattern} ActivePricePattern
|
||||
* @typedef {Brk.AnyMetricEndpointBuilder} AnyMetricEndpoint
|
||||
* @typedef {Brk.AnyMetricData} AnyMetricData
|
||||
* @typedef {Brk.AnySeriesEndpointBuilder} AnySeriesEndpoint
|
||||
* @typedef {Brk.AnySeriesData} AnySeriesData
|
||||
* @typedef {Brk.AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3} AddrCountPattern
|
||||
* Relative patterns by capability:
|
||||
* - BasicRelativePattern: minimal relative (investedCapitalIn*Pct, supplyIn*RelToOwnSupply only)
|
||||
* - GlobalRelativePattern: has RelToMarketCap metrics (netUnrealizedPnlRelToMarketCap, etc)
|
||||
* - OwnRelativePattern: has RelToOwnMarketCap metrics (netUnrealizedPnlRelToOwnMarketCap, etc)
|
||||
* - GlobalRelativePattern: has RelToMarketCap series (netUnrealizedPnlRelToMarketCap, etc)
|
||||
* - OwnRelativePattern: has RelToOwnMarketCap series (netUnrealizedPnlRelToOwnMarketCap, etc)
|
||||
* - FullRelativePattern: has BOTH RelToMarketCap AND RelToOwnMarketCap
|
||||
* @typedef {Brk.LossNetNuplProfitPattern} BasicRelativePattern
|
||||
* @typedef {Brk.LossNetNuplProfitPattern} GlobalRelativePattern
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Brk.MetricEndpointBuilder<T>} MetricEndpoint
|
||||
* @typedef {Brk.SeriesEndpointBuilder<T>} SeriesEndpoint
|
||||
*/
|
||||
/**
|
||||
* Stats pattern: average, min, max, percentiles (height-only indexes, NO base)
|
||||
@@ -132,8 +132,8 @@
|
||||
* @typedef {FullStatsPattern | BtcFullStatsPattern} AnyStatsPattern
|
||||
*/
|
||||
/**
|
||||
* Distribution stats: 8 metric fields (average, min, max, median, pct10/25/75/90)
|
||||
* @typedef {{ average: AnyMetricPattern, min: AnyMetricPattern, max: AnyMetricPattern, median: AnyMetricPattern, pct10: AnyMetricPattern, pct25: AnyMetricPattern, pct75: AnyMetricPattern, pct90: AnyMetricPattern }} DistributionStats
|
||||
* Distribution stats: 8 series fields (average, min, max, median, pct10/25/75/90)
|
||||
* @typedef {{ average: AnySeriesPattern, min: AnySeriesPattern, max: AnySeriesPattern, median: AnySeriesPattern, pct10: AnySeriesPattern, pct25: AnySeriesPattern, pct75: AnySeriesPattern, pct90: AnySeriesPattern }} DistributionStats
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -144,9 +144,9 @@
|
||||
* @typedef {keyof PoolIdToPoolName} PoolId
|
||||
*
|
||||
* Tree branch types
|
||||
* @typedef {Brk.MetricsTree_Market} Market
|
||||
* @typedef {Brk.MetricsTree_Market_MovingAverage} MarketMovingAverage
|
||||
* @typedef {Brk.MetricsTree_Market_Dca} MarketDca
|
||||
* @typedef {Brk.SeriesTree_Market} Market
|
||||
* @typedef {Brk.SeriesTree_Market_MovingAverage} MarketMovingAverage
|
||||
* @typedef {Brk.SeriesTree_Market_Dca} MarketDca
|
||||
* @typedef {Brk._10y2y3y4y5y6y8yPattern} PeriodCagrPattern
|
||||
* Full stats pattern union (both generic and non-generic variants)
|
||||
* @typedef {FullStatsPattern | BtcFullStatsPattern} AnyFullStatsPattern
|
||||
@@ -199,14 +199,14 @@
|
||||
* Cohorts with RealizedWithExtras (realizedCapRelToOwnMarketCap + realizedProfitToLossRatio)
|
||||
* @typedef {CohortAll | CohortFull | CohortWithPercentiles} CohortWithRealizedExtras
|
||||
*
|
||||
* Cohorts with circulating supply relative metrics (supplyRelToCirculatingSupply etc.)
|
||||
* Cohorts with circulating supply relative series (supplyRelToCirculatingSupply etc.)
|
||||
* These have GlobalRelativePattern or FullRelativePattern (same as RelativeWithMarketCap/RelativeWithNupl)
|
||||
* @typedef {CohortFull | CohortLongTerm | CohortWithAdjusted | CohortBasicWithMarketCap} UtxoCohortWithCirculatingSupplyRelative
|
||||
*
|
||||
* Address cohorts with circulating supply relative metrics (all address amount cohorts have these)
|
||||
* Address cohorts with circulating supply relative series (all address amount cohorts have these)
|
||||
* @typedef {AddressCohortObject} AddressCohortWithCirculatingSupplyRelative
|
||||
*
|
||||
* All cohorts with circulating supply relative metrics
|
||||
* All cohorts with circulating supply relative series
|
||||
* @typedef {UtxoCohortWithCirculatingSupplyRelative | AddressCohortWithCirculatingSupplyRelative} CohortWithCirculatingSupplyRelative
|
||||
*
|
||||
* Delta patterns with absolute + rate rolling windows
|
||||
@@ -218,6 +218,6 @@
|
||||
* @typedef {Brk.BpsPriceRatioPattern} InvestorPercentileEntry
|
||||
*
|
||||
* Generic tree node type for walking
|
||||
* @typedef {AnyMetricPattern | Record<string, unknown>} TreeNode
|
||||
* @typedef {AnySeriesPattern | Record<string, unknown>} TreeNode
|
||||
*
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user