global: snapshot part 9

This commit is contained in:
nym21
2026-03-21 10:37:27 +01:00
parent 147a3c7593
commit b807b50a64
6 changed files with 273 additions and 167 deletions

View File

@@ -19,6 +19,7 @@ import {
ROLLING_WINDOWS,
} from "../series.js";
import {
satsBtcUsd,
satsBtcUsdFullTree,
mapCohortsWithAll,
flatMapCohortsWithAll,
@@ -298,13 +299,8 @@ export function createGroupedActivitySectionMinimal({ list, all, title }) {
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Volume (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({
series: tree.activity.transferVolume.sum[w.key].sats,
name,
color,
unit: Unit.sats,
}),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.sum[w.key], name, color }),
),
})),
};
@@ -369,34 +365,51 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
tree: [
{
name: "Volume",
title: title("Sent Volume"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({
series: tree.activity.transferVolume.sum._24h.sats,
name,
color,
unit: Unit.sats,
}),
]),
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Sent Volume (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.sum[w.key], name, color }),
),
})),
},
{
name: "Sent In Profit",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Sent In Profit (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.inProfit.sum[w.key], name, color }),
),
})),
},
{
name: "Sent In Loss",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Sent In Loss (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.inLoss.sum[w.key], name, color }),
),
})),
},
{
name: "Dormancy",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Dormancy (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.activity.dormancy[w.key], name, color, unit: Unit.days }),
),
})),
},
{
name: "SOPR",
tree: [
...groupedSoprCharts(
list,
all,
(c) => c.tree.realized.sopr.ratio,
title,
),
...groupedSoprCharts(list, all, (c) => c.tree.realized.sopr.ratio, title),
{
name: "Adjusted",
tree: groupedSoprCharts(
list,
all,
(c) => c.tree.realized.sopr.adjusted.ratio,
title,
"Adjusted ",
),
tree: groupedSoprCharts(list, all, (c) => c.tree.realized.sopr.adjusted.ratio, title, "Adjusted "),
},
],
},
@@ -417,15 +430,13 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
},
{
name: "Coindays Destroyed",
title: title("Coindays Destroyed"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({
series: tree.activity.coindaysDestroyed.sum._24h,
name,
color,
unit: Unit.coindays,
}),
]),
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Coindays Destroyed (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.activity.coindaysDestroyed.sum[w.key], name, color, unit: Unit.coindays }),
),
})),
},
],
};
@@ -442,26 +453,47 @@ export function createGroupedActivitySection({ list, all, title }) {
tree: [
{
name: "Volume",
title: title("Sent Volume"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({
series: tree.activity.transferVolume.sum._24h.sats,
name,
color,
unit: Unit.sats,
}),
]),
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Sent Volume (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.sum[w.key], name, color }),
),
})),
},
{
name: "Sent In Profit",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Sent In Profit (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.inProfit.sum[w.key], name, color }),
),
})),
},
{
name: "Sent In Loss",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Sent In Loss (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.inLoss.sum[w.key], name, color }),
),
})),
},
{
name: "Dormancy",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Dormancy (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.activity.dormancy[w.key], name, color, unit: Unit.days }),
),
})),
},
{
name: "SOPR",
tree: [
...groupedSoprCharts(
list,
all,
(c) => c.tree.realized.sopr.ratio,
title,
),
],
tree: groupedSoprCharts(list, all, (c) => c.tree.realized.sopr.ratio, title),
},
{
name: "Sell Side Risk",
@@ -480,15 +512,13 @@ export function createGroupedActivitySection({ list, all, title }) {
},
{
name: "Coindays Destroyed",
title: title("Coindays Destroyed"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({
series: tree.activity.coindaysDestroyed.sum._24h,
name,
color,
unit: Unit.coindays,
}),
]),
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Coindays Destroyed (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.activity.coindaysDestroyed.sum[w.key], name, color, unit: Unit.coindays }),
),
})),
},
],
};
@@ -505,15 +535,13 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) {
tree: [
{
name: "Volume",
title: title("Sent Volume"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({
series: tree.activity.transferVolume.sum._24h.sats,
name,
color,
unit: Unit.sats,
}),
]),
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Sent Volume (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
satsBtcUsd({ pattern: tree.activity.transferVolume.sum[w.key], name, color }),
),
})),
},
{
name: "SOPR",
@@ -530,15 +558,13 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) {
},
{
name: "Coindays Destroyed",
title: title("Coindays Destroyed"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({
series: tree.activity.coindaysDestroyed.sum._24h,
name,
color,
unit: Unit.coindays,
}),
]),
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Coindays Destroyed (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.activity.coindaysDestroyed.sum[w.key], name, color, unit: Unit.coindays }),
),
})),
},
],
};

View File

@@ -137,6 +137,13 @@ function groupedWeightFolder({ list, all, getAvgPrice, getInProfit, getInLoss, g
{
name: "Average",
tree: [
{
name: "All",
title: title(`${avgTitle} Comparison`),
top: mapCohortsWithAll(list, all, (c) =>
price({ series: getAvgPrice(c), name: c.name, color: c.color }),
),
},
{
name: "In Profit",
title: title(`Cost Basis In Profit (${weightLabel})`),

View File

@@ -52,6 +52,7 @@ import {
createPricesSectionFull,
createPricesSectionBasic,
createGroupedPricesSection,
createGroupedPricesSectionFull,
} from "./prices.js";
import {
createCostBasisSectionWithPercentiles,
@@ -342,7 +343,7 @@ export function createGroupedCohortFolderFull({
tree: [
...createGroupedHoldingsSectionWithRelative({ list, all, title }),
createGroupedValuationSectionWithOwnMarketCap({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedPricesSectionFull({ list, all, title }),
createGroupedCostBasisSectionWithPercentiles({ list, all, title }),
createGroupedProfitabilitySectionWithNupl({ list, all, title }),
createGroupedActivitySectionWithAdjusted({ list, all, title }),
@@ -392,8 +393,8 @@ export function createGroupedCohortFolderWithNupl({
name: name || "all",
tree: [
...createGroupedHoldingsSectionWithRelative({ list, all, title }),
createGroupedValuationSection({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedValuationSectionWithOwnMarketCap({ list, all, title }),
createGroupedPricesSectionFull({ list, all, title }),
createGroupedCostBasisSectionWithPercentiles({ list, all, title }),
createGroupedProfitabilitySectionWithNupl({ list, all, title }),
createGroupedActivitySection({ list, all, title }),
@@ -417,7 +418,7 @@ export function createGroupedCohortFolderLongTerm({
tree: [
...createGroupedHoldingsSectionWithRelative({ list, all, title }),
createGroupedValuationSectionWithOwnMarketCap({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedPricesSectionFull({ list, all, title }),
createGroupedCostBasisSectionWithPercentiles({ list, all, title }),
createGroupedProfitabilitySectionLongTerm({ list, all, title }),
createGroupedActivitySection({ list, all, title }),

View File

@@ -116,31 +116,65 @@ export function createPricesSectionBasic({ cohort, title }) {
* @param {{ list: readonly CohortObject[], all: CohortAll, title: (name: string) => string }} args
* @returns {PartialOptionsGroup}
*/
/**
* @param {readonly CohortObject[]} list
* @param {CohortAll} all
* @param {(name: string) => string} title
* @returns {PartialOptionsTree}
*/
function groupedRealizedPriceItems(list, all, title) {
return [
{
name: "Realized",
tree: [
{
name: "Price",
title: title("Realized Price"),
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
price({ series: tree.realized.price, name, color }),
),
},
{
name: "Ratio",
title: title("MVRV"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.mvrv, name, color, unit: Unit.ratio, base: 1 }),
),
},
],
},
];
}
/** @param {{ list: readonly CohortObject[], all: CohortAll, title: (name: string) => string }} args */
export function createGroupedPricesSection({ list, all, title }) {
return {
name: "Prices",
tree: groupedRealizedPriceItems(list, all, title),
};
}
/** @param {{ list: readonly (CohortAll | CohortFull | CohortLongTerm)[], all: CohortAll, title: (name: string) => string }} args */
export function createGroupedPricesSectionFull({ list, all, title }) {
return {
name: "Prices",
tree: [
...groupedRealizedPriceItems(list, all, title),
{
name: "Realized",
name: "Investor",
tree: [
{
name: "Price",
title: title("Realized Price"),
title: title("Investor Price"),
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
price({ series: tree.realized.price, name, color }),
price({ series: tree.realized.investor.price, name, color }),
),
},
{
name: "Ratio",
title: title("MVRV"),
title: title("Investor Price Ratio"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({
series: tree.realized.mvrv,
name,
color,
unit: Unit.ratio,
base: 1,
}),
baseline({ series: tree.realized.investor.price.ratio, name, color, unit: Unit.ratio, base: 1 }),
),
},
],

View File

@@ -718,25 +718,6 @@ function groupedRealizedPnlSum(list, all, title) {
* @param {(name: string) => string} title
* @returns {PartialOptionsTree}
*/
function groupedRealizedPnlSumFull(list, all, title) {
return [
...groupedRealizedPnlSum(list, all, title),
{
name: "Total",
title: title("Total Realized P&L"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.grossPnl.cumulative.usd, name, color, unit: Unit.usd }),
),
},
{
name: "P/L Ratio",
title: title("Realized Profit/Loss Ratio"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.profitToLossRatio._1y, name, color, unit: Unit.ratio, base: 1 }),
),
},
];
}
/**
* Grouped rolling realized charts (basic — profit/loss sums only)
@@ -768,28 +749,6 @@ function groupedRollingRealizedCharts(list, all, title) {
];
}
/**
* Grouped rolling realized with P/L ratio (full cohorts)
* @param {readonly (CohortAll | CohortFull | CohortLongTerm)[]} list
* @param {CohortAll} all
* @param {(name: string) => string} title
* @returns {PartialOptionsTree}
*/
function groupedRollingRealizedChartsFull(list, all, title) {
return [
...groupedRollingRealizedCharts(list, all, title),
{
name: "P/L Ratio",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Realized P/L Ratio (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.profitToLossRatio[w.key], name, color, unit: Unit.ratio, base: 1 }),
),
})),
},
];
}
/**
* Grouped realized subfolder (basic)
@@ -834,14 +793,12 @@ function groupedRealizedSubfolder(list, all, title) {
* @param {readonly (CohortAll | CohortFull | CohortLongTerm)[]} list
* @param {CohortAll} all
* @param {(name: string) => string} title
* @returns {PartialOptionsGroup}
* @returns {PartialOptionsTree}
*/
function groupedRealizedNetPnlDeltaTree(list, all, title) {
return {
name: "Change",
tree: [
function groupedRealizedNetPnlDeltaItems(list, all, title) {
return [
{
name: "Absolute",
name: "Change",
tree: [
{
name: "Compare",
@@ -882,8 +839,7 @@ function groupedRealizedNetPnlDeltaTree(list, all, title) {
})),
],
},
],
};
];
}
/**
@@ -897,41 +853,108 @@ function groupedRealizedSubfolderFull(list, all, title) {
return {
name: "Realized",
tree: [
{ name: "P&L", tree: groupedRealizedPnlSumFull(list, all, title) },
{
name: "Net",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Net Realized P&L (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.netPnl.sum[w.key].usd, name, color, unit: Unit.usd }),
),
})),
},
groupedRealizedNetPnlDeltaTree(list, all, title),
{ name: "Rolling", tree: groupedRollingRealizedChartsFull(list, all, title) },
{
name: "Cumulative",
tree: [
...ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Net Realized P&L (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.netPnl.sum[w.key].usd, name, color, unit: Unit.usd }),
),
})),
{
name: "Profit",
name: "Cumulative",
title: title("Cumulative Net Realized P&L"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.netPnl.cumulative.usd, name, color, unit: Unit.usd }),
),
},
...groupedRealizedNetPnlDeltaItems(list, all, title),
],
},
{
name: "Profit",
tree: [
...ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Realized Profit (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.profit.sum[w.key].usd, name, color, unit: Unit.usd }),
),
})),
{
name: "Cumulative",
title: title("Cumulative Realized Profit"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.profit.cumulative.usd, name, color, unit: Unit.usd }),
),
},
],
},
{
name: "Loss",
tree: [
...ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Realized Loss (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.loss.sum[w.key].usd, name, color, unit: Unit.usd }),
),
})),
{
name: "Loss",
name: "Cumulative",
title: title("Cumulative Realized Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.loss.cumulative.usd, name, color, unit: Unit.usd }),
),
},
{
name: "Net",
title: title("Cumulative Net Realized P&L"),
],
},
{
name: "Gross",
tree: [
...ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Gross Realized P&L (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.netPnl.cumulative.usd, name, color, unit: Unit.usd }),
line({ series: tree.realized.grossPnl.sum[w.key].usd, name, color, unit: Unit.usd }),
),
})),
{
name: "Cumulative",
title: title("Cumulative Gross Realized P&L"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.grossPnl.cumulative.usd, name, color, unit: Unit.usd }),
),
},
],
},
{
name: "P/L Ratio",
tree: ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Realized P/L Ratio (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.profitToLossRatio[w.key], name, color, unit: Unit.ratio, base: 1 }),
),
})),
},
{
name: "Peak Regret",
tree: [
...ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Peak Regret (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.peakRegret.sum[w.key].usd, name, color, unit: Unit.usd }),
),
})),
{
name: "Cumulative",
title: title("Cumulative Peak Regret"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.realized.peakRegret.cumulative.usd, name, color, unit: Unit.usd }),
),
},
],
@@ -1234,7 +1257,8 @@ export function createGroupedProfitabilitySectionWithNupl({ list, all, title })
name: "Profitability",
tree: [
{ name: "Unrealized", tree: groupedUnrealizedWithMarketCap(list, all, title) },
groupedRealizedSubfolder(list, all, title),
groupedRealizedSubfolderFull(list, all, title),
groupedSentiment(list, all, title),
],
};
}

View File

@@ -95,7 +95,7 @@ export function createValuationSectionFull({ cohort, title }) {
line({ series: tree.unrealized.investedCapital.inLoss.usd, name: "In Loss", color: colors.loss, unit: Unit.usd }),
],
},
createRatioChart({ title, pricePattern: tree.realized.price, ratio: tree.realized.price, color, name: "MVRV" }),
{ name: "MVRV", title: title("MVRV"), bottom: [baseline({ series: tree.realized.mvrv, name: "MVRV", unit: Unit.ratio, base: 1 })] },
{ name: "% of Own Market Cap", title: title("Realized Cap (% of Own Market Cap)"), bottom: percentRatioBaseline({ pattern: tree.realized.cap.toOwnMcap, name: "Rel. to Own Market Cap", color }) },
...singleDeltaItems(tree, title),
],
@@ -158,6 +158,20 @@ export function createGroupedValuationSectionWithOwnMarketCap({ list, all, title
line({ series: tree.realized.cap.usd, name, color, unit: Unit.usd }),
),
},
{
name: "In Profit",
title: title("Invested Capital In Profit"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.investedCapital.inProfit.usd, name, color, unit: Unit.usd }),
),
},
{
name: "In Loss",
title: title("Invested Capital In Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.investedCapital.inLoss.usd, name, color, unit: Unit.usd }),
),
},
{
name: "% of Own Market Cap",
title: title("Realized Cap (% of Own Market Cap)"),