Files
2026-08-05 14:50:47 +02:00

603 lines
17 KiB
JavaScript

import { colors } from "../../../utils/colors.js";
import { brk } from "../../../utils/client.js";
import { Unit } from "../../../utils/units.js";
import {
dots,
line,
price,
multiSeriesTree,
percentRatioDots,
sumsAndAveragesCumulative,
} from "../../series.js";
import { ageRanges } from "../../age-ranges.js";
import { satsBtcUsd, simplePriceRatioTree } from "../../shared.js";
import {
createCointimeAgeRangeActivitySection,
createCointimeAgeRangeSupplySection,
} from "./age-range.js";
/**
* Create Cointime section
* @returns {PartialOptionsGroup}
*/
export function createCointimeSection() {
const { cohorts, supply, cointime: baseCointime } = brk.series;
const { cointime } = brk.series.frameworks;
const {
prices: cointimePrices,
cap,
activity,
supply: cointimeSupply,
adjusted,
reserveRisk,
value,
} = cointime;
const { all } = cohorts.utxo;
const cointimeAgeRanges = ageRanges.map(({ key, ...range }) => ({
...range,
tree: cointime.ageRange[key],
}));
const awakeCohorts = [
{ name: "All", color: colors.awake, tree: cointime },
{ name: "STH", color: colors.term.short, tree: cointime.sth },
{ name: "LTH", color: colors.term.long, tree: cointime.lth },
];
// Reference lines for cap comparisons
const capReferenceLines = /** @type {const} */ ([
{
series: all.realized.cap.usd,
name: "Realized",
color: colors.realized,
},
]);
/** @type {readonly { pattern: AnyPricePattern & { ratio: AnySeriesPattern }, name: string, title: (name: string) => string, color: Color, defaultActive: boolean }[]} */
const prices = [
{
pattern: cointimePrices.trueMarketMean,
name: "True Market Mean",
title: (name) => name,
color: colors.trueMarketMean,
defaultActive: true,
},
{
pattern: cointimePrices.vaulted,
name: "Vaulted",
title: (name) => `${name} Price`,
color: colors.vaulted,
defaultActive: true,
},
{
pattern: cointimePrices.active,
name: "Active",
title: (name) => `${name} Price`,
color: colors.active,
defaultActive: true,
},
{
pattern: cointimePrices.cointime,
name: "Cointime",
title: (name) => `${name} Price`,
color: colors.cointime,
defaultActive: true,
},
];
const caps = /** @type {const} */ ([
{
series: cap.vaulted.usd,
name: "Vaulted",
color: colors.vaulted,
defaultActive: true,
},
{
series: cap.active.usd,
name: "Active",
color: colors.active,
defaultActive: true,
},
{
series: cap.cointime.usd,
name: "Cointime",
color: colors.cointime,
defaultActive: true,
},
{
series: cap.investor.usd,
name: "Investor",
color: colors.investor,
defaultActive: false,
},
{
series: cap.thermo.usd,
name: "Thermo",
color: colors.thermo,
defaultActive: false,
},
]);
const supplyBreakdown = /** @type {const} */ ([
{ pattern: all.supply.total, name: "Total", color: colors.bitcoin },
{
pattern: cointimeSupply.vaulted,
name: "Vaulted",
color: colors.vaulted,
},
{
pattern: cointimeSupply.active,
name: "Active",
color: colors.active,
},
]);
const coinblocks = /** @type {const} */ ([
{
pattern: baseCointime.activity.coinblocksDestroyed,
name: "Destroyed",
title: "Coinblocks Destroyed",
color: colors.destroyed,
},
{
pattern: activity.coinblocksCreated,
name: "Created",
title: "Coinblocks Created",
color: colors.created,
},
{
pattern: activity.coinblocksStored,
name: "Stored",
title: "Coinblocks Stored",
color: colors.stored,
},
]);
// Colors aligned with coinblocks: Destroyed=red, Created=orange, Stored=green
const cointimeValues = /** @type {const} */ ([
{
pattern: value.created,
name: "Created",
title: "Cointime Value Created",
color: colors.created,
},
{
pattern: value.destroyed,
name: "Destroyed",
title: "Cointime Value Destroyed",
color: colors.destroyed,
},
{
pattern: value.stored,
name: "Stored",
title: "Cointime Value Stored",
color: colors.stored,
},
]);
const vocdd = /** @type {const} */ ({
pattern: value.vocdd,
name: "VOCDD",
title: "Value of Coin Days Destroyed",
color: colors.vocdd,
});
return {
name: "Cointime",
tree: [
{
name: "Price",
tree: [
{
name: "Compare",
title: "Cointime Prices",
top: [
price({
series: all.realized.price,
name: "Realized",
color: colors.realized,
}),
price({
series: all.realized.capitalized.price,
name: "Capitalized",
color: colors.capitalized,
}),
...prices.map(({ pattern, name, color, defaultActive }) =>
price({ series: pattern, name, color, defaultActive }),
),
...awakeCohorts.map(({ name, color, tree }) =>
price({
series: tree.awake.price,
name: name === "All" ? "Awake" : `${name} Awake`,
color,
}),
),
],
},
...prices.map(({ pattern, name, title, color }) => {
const [chart] = simplePriceRatioTree({
pattern,
title: title(name),
legend: name,
color,
});
return { ...chart, name };
}),
...awakeCohorts.map(({ name, color, tree }) => {
const awakeName = name === "All" ? "Awake" : `${name} Awake`;
const [chart] = simplePriceRatioTree({
pattern: tree.awake.price,
title: `${awakeName} Price`,
legend: awakeName,
color,
});
return { ...chart, name: awakeName };
}),
],
},
{
name: "Capitalization",
tree: [
{
name: "Compare",
title: "Cointime Caps",
bottom: [
...capReferenceLines.map(({ series, name, color }) =>
line({ series, name, color, unit: Unit.usd }),
),
...caps.map(({ series, name, color, defaultActive }) =>
line({ series, name, color, defaultActive, unit: Unit.usd }),
),
...awakeCohorts.map(({ name, color, tree }) =>
line({
series: tree.awake.cap.usd,
name: name === "All" ? "Awake" : `${name} Awake`,
color,
unit: Unit.usd,
}),
),
],
},
...caps.map(({ series, name, color }) => ({
name,
title: `${name} Cap`,
bottom: [
line({ series, name, color, unit: Unit.usd }),
...capReferenceLines.map((ref) =>
line({
series: ref.series,
name: ref.name,
color: ref.color,
unit: Unit.usd,
}),
),
],
})),
...awakeCohorts.map(({ name, color, tree }) => {
const awakeName = name === "All" ? "Awake" : `${name} Awake`;
return {
name: awakeName,
title: `${awakeName} Cap`,
bottom: [
line({
series: tree.awake.cap.usd,
name: awakeName,
color,
unit: Unit.usd,
}),
...capReferenceLines.map((ref) =>
line({
series: ref.series,
name: ref.name,
color: ref.color,
unit: Unit.usd,
}),
),
],
};
}),
],
},
{
name: "Supply",
tree: [
{
name: "Overview",
tree: [
{
name: "Active vs Vaulted",
title: "Active vs Vaulted Supply",
bottom: supplyBreakdown.flatMap(({ pattern, name, color }) =>
satsBtcUsd({ pattern, name, color }),
),
},
{
name: "Awake vs Dormant",
title: "Awake vs Dormant Supply",
bottom: [
...satsBtcUsd({
pattern: cointime.awake.supply,
name: "Awake",
color: colors.awake,
}),
...satsBtcUsd({
pattern: cointime.dormant.supply,
name: "Dormant",
color: colors.dormant,
}),
],
},
],
},
{
name: "By Holder Term",
tree: [
{
name: "Awake",
title: "Awake Supply by Holder Term",
bottom: awakeCohorts.flatMap(({ name, color, tree }) =>
satsBtcUsd({
pattern: tree.awake.supply,
name,
color,
}),
),
},
{
name: "Dormant",
title: "Dormant Supply by Holder Term",
bottom: awakeCohorts.flatMap(({ name, color, tree }) =>
satsBtcUsd({
pattern: tree.dormant.supply,
name,
color,
}),
),
},
],
},
createCointimeAgeRangeSupplySection(cointimeAgeRanges),
{
name: "In Loss",
tree: [
{
name: "Active",
title: "Active Supply in Loss",
bottom: [
line({
series: cointimeSupply.active.inLoss.share,
name: "Share",
color: colors.loss,
unit: Unit.ratio,
}),
],
},
{
name: "Awake by Holder Term",
title: "Awake Supply in Loss by Holder Term",
bottom: awakeCohorts.map(({ name, color, tree }) =>
line({
series: tree.awake.supply.inLoss.share,
name,
color,
unit: Unit.ratio,
}),
),
},
],
},
],
},
{
name: "Activity",
tree: [
{
name: "Overview",
title: "Liveliness & Vaultedness",
bottom: [
line({
series: activity.liveliness,
name: "Liveliness",
color: colors.liveliness,
unit: Unit.ratio,
}),
line({
series: activity.vaultedness,
name: "Vaultedness",
color: colors.vaulted,
unit: Unit.ratio,
}),
line({
series: activity.ratio,
name: "Liveliness / Vaultedness",
color: colors.activity,
unit: Unit.ratio,
defaultActive: false,
}),
],
},
{
name: "Coinblocks",
tree: [
{
name: "Compare",
tree: multiSeriesTree({
entries: coinblocks.map(({ pattern, name, color }) => ({
name,
color,
average: pattern.average,
sum: pattern.sum,
cumulative: pattern.cumulative,
})),
metric: "Coinblocks",
unit: Unit.coinblocks,
}),
},
...coinblocks.map(
({ pattern, name, title: metric, color }) => ({
name,
tree: sumsAndAveragesCumulative({
sum: pattern.sum,
average: pattern.average,
cumulative: pattern.cumulative,
metric,
unit: Unit.coinblocks,
color,
}),
}),
),
],
},
createCointimeAgeRangeActivitySection(cointimeAgeRanges),
],
},
{
name: "Economics",
tree: [
{
name: "Cointime Value",
tree: [
{
name: "Compare",
tree: multiSeriesTree({
entries: [
...cointimeValues.map(({ pattern, name, color }) => ({
name,
color,
average: pattern.average,
sum: pattern.sum,
cumulative: pattern.cumulative,
})),
{
name: vocdd.name,
color: vocdd.color,
average: vocdd.pattern.average,
sum: vocdd.pattern.sum,
cumulative: vocdd.pattern.cumulative,
},
],
metric: "Cointime Value",
unit: Unit.usd,
}),
},
...cointimeValues.map(
({ pattern, name, title: metric, color }) => ({
name,
tree: sumsAndAveragesCumulative({
sum: pattern.sum,
average: pattern.average,
cumulative: pattern.cumulative,
metric,
unit: Unit.usd,
color,
}),
}),
),
{
name: vocdd.name,
tree: sumsAndAveragesCumulative({
sum: vocdd.pattern.sum,
average: vocdd.pattern.average,
cumulative: vocdd.pattern.cumulative,
metric: vocdd.title,
unit: Unit.usd,
color: vocdd.color,
}),
},
],
},
{
name: "Indicators",
tree: [
{
name: "AVIV",
title: "AVIV Ratio",
bottom: [
line({
series: cap.aviv.ratio,
name: "AVIV",
unit: Unit.ratio,
}),
],
},
{
name: "Reserve Risk",
title: "Reserve Risk",
bottom: [
line({
series: reserveRisk.value,
name: "Ratio",
color: colors.reserveRisk,
unit: Unit.ratio,
}),
],
},
],
},
{
name: "Adjustments",
tree: [
{
name: "Inflation",
title: "Cointime-Adjusted Inflation",
bottom: [
dots({
series: supply.inflationRate.percent,
name: "Base",
color: colors.base,
unit: Unit.percentage,
}),
...percentRatioDots({
pattern: adjusted.inflationRate,
name: "Cointime-Adjusted",
color: colors.adjusted,
}),
],
},
{
name: "BTC Velocity",
title: "Cointime-Adjusted BTC Velocity",
bottom: [
line({
series: supply.velocity.native,
name: "Base",
color: colors.base,
unit: Unit.ratio,
}),
line({
series: adjusted.txVelocityNative,
name: "Cointime-Adjusted",
color: colors.adjusted,
unit: Unit.ratio,
}),
],
},
{
name: "USD Velocity",
title: "Cointime-Adjusted USD Velocity",
bottom: [
line({
series: supply.velocity.fiat,
name: "Base",
color: colors.thermo,
unit: Unit.ratio,
}),
line({
series: adjusted.txVelocityFiat,
name: "Cointime-Adjusted",
color: colors.vaulted,
unit: Unit.ratio,
}),
],
},
],
},
],
},
],
};
}