diff --git a/website/scripts/options/distribution/activity.js b/website/scripts/options/distribution/activity.js index 43b409372..ad968b67c 100644 --- a/website/scripts/options/distribution/activity.js +++ b/website/scripts/options/distribution/activity.js @@ -50,28 +50,61 @@ function volumeFolderWithProfitability(activity, color, title) { }), { name: "Profitability", - tree: ROLLING_WINDOWS.map((w) => ({ - name: w.name, - title: title(`Sent Volume Profitability (${w.title})`), - bottom: [ - ...satsBtcUsd({ - pattern: tv.inProfit.sum[w.key], - name: "In Profit", + tree: [ + ...ROLLING_WINDOWS.map((w) => ({ + name: w.name, + title: title(`Sent Volume Profitability (${w.title})`), + bottom: [ + ...satsBtcUsd({ + pattern: tv.inProfit.sum[w.key], + name: "In Profit", + color: colors.profit, + }), + ...satsBtcUsd({ + pattern: tv.inLoss.sum[w.key], + name: "In Loss", + color: colors.loss, + }), + ], + })), + { + name: "Cumulative", + title: title("Cumulative Sent Volume Profitability"), + bottom: [ + ...satsBtcUsd({ + pattern: tv.inProfit.cumulative, + name: "In Profit", + color: colors.profit, + }), + ...satsBtcUsd({ + pattern: tv.inLoss.cumulative, + name: "In Loss", + color: colors.loss, + }), + ], + }, + { + name: "In Profit", + tree: satsBtcUsdFullTree({ + pattern: tv.inProfit, + title: title("Sent In Profit"), color: colors.profit, }), - ...satsBtcUsd({ - pattern: tv.inLoss.sum[w.key], - name: "In Loss", + }, + { + name: "In Loss", + tree: satsBtcUsdFullTree({ + pattern: tv.inLoss, + title: title("Sent In Loss"), color: colors.loss, }), - ], - })), + }, + ], }, ], }; } - // ============================================================================ // Shared SOPR Helpers // ============================================================================ @@ -112,6 +145,36 @@ function singleRollingSoprTree(ratio, title, prefix = "") { ]; } +/** @returns {PartialOptionsTree} */ +function valueDestroyedTree(/** @type {CountPattern} */ valueDestroyed, /** @type {(name: string) => string} */ title) { + return chartsFromCount({ pattern: valueDestroyed, title: title("Value Destroyed"), unit: Unit.usd }); +} + +/** + * @param {CountPattern} valueDestroyed + * @param {(name: string) => string} title + * @returns {PartialOptionsGroup} + */ +function valueDestroyedFolder(valueDestroyed, title) { + return { name: "Value Destroyed", tree: valueDestroyedTree(valueDestroyed, title) }; +} + +/** + * @param {CountPattern} valueDestroyed + * @param {CountPattern} adjusted + * @param {(name: string) => string} title + * @returns {PartialOptionsGroup} + */ +function valueDestroyedFolderWithAdjusted(valueDestroyed, adjusted, title) { + return { + name: "Value Destroyed", + tree: [ + ...valueDestroyedTree(valueDestroyed, title), + { name: "Adjusted", tree: chartsFromCount({ pattern: adjusted, title: title("Adjusted Value Destroyed"), unit: Unit.usd }) }, + ], + }; +} + // ============================================================================ // Shared Sell Side Risk Helpers // ============================================================================ @@ -155,16 +218,36 @@ function singleSellSideRiskTree(sellSideRisk, title) { * @param {CohortAll | CohortFull | CohortLongTerm} cohort * @param {(name: string) => string} title * @param {PartialOptionsGroup} soprFolder + * @param {PartialOptionsGroup} valueDestroyedItem * @returns {PartialOptionsTree} */ -function singleFullActivityTree(cohort, title, soprFolder) { +function singleFullActivityTree(cohort, title, soprFolder, valueDestroyedItem) { const { tree, color } = cohort; return [ volumeFolderWithProfitability(tree.activity, color, title), soprFolder, - { name: "Coindays Destroyed", tree: chartsFromCount({ pattern: tree.activity.coindaysDestroyed, title: title("Coindays Destroyed"), unit: Unit.coindays, color }) }, - { name: "Dormancy", tree: averagesArray({ windows: tree.activity.dormancy, title: title("Dormancy"), unit: Unit.days }) }, - { name: "Sell Side Risk", tree: singleSellSideRiskTree(tree.realized.sellSideRiskRatio, title) }, + valueDestroyedItem, + { + name: "Coindays Destroyed", + tree: chartsFromCount({ + pattern: tree.activity.coindaysDestroyed, + title: title("Coindays Destroyed"), + unit: Unit.coindays, + color, + }), + }, + { + name: "Dormancy", + tree: averagesArray({ + windows: tree.activity.dormancy, + title: title("Dormancy"), + unit: Unit.days, + }), + }, + { + name: "Sell Side Risk", + tree: singleSellSideRiskTree(tree.realized.sellSideRiskRatio, title), + }, ]; } @@ -177,9 +260,12 @@ export function createActivitySectionWithAdjusted({ cohort, title }) { name: "SOPR", tree: [ ...singleRollingSoprTree(sopr.ratio, title), - { name: "Adjusted", tree: singleRollingSoprTree(sopr.adjusted.ratio, title, "Adjusted ") }, + { + name: "Adjusted", + tree: singleRollingSoprTree(sopr.adjusted.ratio, title, "Adjusted "), + }, ], - }), + }, valueDestroyedFolderWithAdjusted(sopr.valueDestroyed, sopr.adjusted.valueDestroyed, title)), }; } @@ -190,7 +276,7 @@ export function createActivitySection({ cohort, title }) { tree: singleFullActivityTree(cohort, title, { name: "SOPR", tree: singleRollingSoprTree(cohort.tree.realized.sopr.ratio, title), - }), + }, valueDestroyedFolder(cohort.tree.realized.sopr.valueDestroyed, title)), }; } @@ -207,15 +293,6 @@ export function createActivitySectionWithActivity({ cohort, title }) { name: "Activity", tree: [ volumeFolderWithProfitability(tree.activity, color, title), - { - name: "Coindays Destroyed", - tree: chartsFromCount({ - pattern: tree.activity.coindaysDestroyed, - title: title("Coindays Destroyed"), - unit: Unit.coindays, - color, - }), - }, { name: "SOPR", title: title("SOPR (24h)"), @@ -228,6 +305,16 @@ export function createActivitySectionWithActivity({ cohort, title }) { }), ], }, + valueDestroyedFolder(sopr.valueDestroyed, title), + { + name: "Coindays Destroyed", + tree: chartsFromCount({ + pattern: tree.activity.coindaysDestroyed, + title: title("Coindays Destroyed"), + unit: Unit.coindays, + color, + }), + }, ], }; } @@ -270,7 +357,43 @@ export function createGroupedActivitySectionMinimal({ list, all, title }) { } /** - * Grouped volume folder with In Profit/Loss subfolders + * Grouped profitability folder (compare + in profit + in loss) + * @template {{ name: string, color: Color }} T + * @template {{ name: string, color: Color }} A + * @param {readonly T[]} list + * @param {A} all + * @param {(name: string) => string} title + * @param {(c: T | A) => { sum: Record, cumulative: AnyValuePattern }} getInProfit + * @param {(c: T | A) => { sum: Record, cumulative: AnyValuePattern }} getInLoss + * @returns {PartialOptionsTree} + */ +function groupedProfitabilityArray(list, all, title, getInProfit, getInLoss) { + return [ + { + name: "In Profit", + tree: groupedWindowsCumulativeSatsBtcUsd({ + list, + all, + title, + metricTitle: "Sent In Profit", + getMetric: (c) => getInProfit(c), + }), + }, + { + name: "In Loss", + tree: groupedWindowsCumulativeSatsBtcUsd({ + list, + all, + title, + metricTitle: "Sent In Loss", + getMetric: (c) => getInLoss(c), + }), + }, + ]; +} + +/** + * Grouped volume folder with profitability subfolders * @template {{ name: string, color: Color }} T * @template {{ name: string, color: Color }} A * @param {readonly T[]} list @@ -283,9 +406,20 @@ function groupedVolumeFolder(list, all, title, getTransferVolume) { return { name: "Volume", tree: [ - ...groupedWindowsCumulativeSatsBtcUsd({ list, all, title, metricTitle: "Sent Volume", getMetric: (c) => getTransferVolume(c) }), - { name: "In Profit", tree: groupedWindowsCumulativeSatsBtcUsd({ list, all, title, metricTitle: "Sent In Profit", getMetric: (c) => getTransferVolume(c).inProfit }) }, - { name: "In Loss", tree: groupedWindowsCumulativeSatsBtcUsd({ list, all, title, metricTitle: "Sent In Loss", getMetric: (c) => getTransferVolume(c).inLoss }) }, + ...groupedWindowsCumulativeSatsBtcUsd({ + list, + all, + title, + metricTitle: "Sent Volume", + getMetric: (c) => getTransferVolume(c), + }), + ...groupedProfitabilityArray( + list, + all, + title, + (c) => getTransferVolume(c).inProfit, + (c) => getTransferVolume(c).inLoss, + ), ], }; } @@ -320,6 +454,57 @@ function groupedSoprCharts(list, all, getRatio, title, prefix = "") { })); } +/** + * @template {{ name: string, color: Color }} T + * @template {{ name: string, color: Color }} A + * @param {readonly T[]} list + * @param {A} all + * @param {(name: string) => string} title + * @param {(c: T | A) => CountPattern} getValueDestroyed + * @returns {PartialOptionsTree} + */ +function groupedValueDestroyedTree(list, all, title, getValueDestroyed) { + return groupedWindowsCumulative({ + list, all, title, metricTitle: "Value Destroyed", + getWindowSeries: (c, key) => getValueDestroyed(c).sum[key], + getCumulativeSeries: (c) => getValueDestroyed(c).cumulative, + seriesFn: line, unit: Unit.usd, + }); +} + +/** + * @template {{ name: string, color: Color }} T + * @template {{ name: string, color: Color }} A + * @param {readonly T[]} list + * @param {A} all + * @param {(name: string) => string} title + * @param {(c: T | A) => CountPattern} getValueDestroyed + * @returns {PartialOptionsGroup} + */ +function groupedValueDestroyedFolder(list, all, title, getValueDestroyed) { + return { name: "Value Destroyed", tree: groupedValueDestroyedTree(list, all, title, getValueDestroyed) }; +} + +/** + * @template {{ name: string, color: Color }} T + * @template {{ name: string, color: Color }} A + * @param {readonly T[]} list + * @param {A} all + * @param {(name: string) => string} title + * @param {(c: T | A) => CountPattern} getValueDestroyed + * @param {(c: T | A) => CountPattern} getAdjustedValueDestroyed + * @returns {PartialOptionsGroup} + */ +function groupedValueDestroyedFolderWithAdjusted(list, all, title, getValueDestroyed, getAdjustedValueDestroyed) { + return { + name: "Value Destroyed", + tree: [ + ...groupedValueDestroyedTree(list, all, title, getValueDestroyed), + { name: "Adjusted", tree: groupedValueDestroyedTree(list, all, title, getAdjustedValueDestroyed) }, + ], + }; +} + // ============================================================================ // Grouped Value/Flow Helpers // ============================================================================ @@ -345,12 +530,19 @@ function groupedSoprCharts(list, all, getRatio, title, prefix = "") { * @param {CohortAll} all * @param {(name: string) => string} title * @param {PartialOptionsGroup} soprFolder + * @param {PartialOptionsGroup} valueDestroyedItem * @returns {PartialOptionsTree} */ -function groupedFullActivityTree(list, all, title, soprFolder) { +function groupedFullActivityTree(list, all, title, soprFolder, valueDestroyedItem) { return [ - groupedVolumeFolder(list, all, title, (c) => c.tree.activity.transferVolume), + groupedVolumeFolder( + list, + all, + title, + (c) => c.tree.activity.transferVolume, + ), soprFolder, + valueDestroyedItem, ...groupedActivitySharedItems(list, all, title), ]; } @@ -362,10 +554,24 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) { tree: groupedFullActivityTree(list, all, title, { name: "SOPR", tree: [ - ...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 ") }, + ...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 ", + ), + }, ], - }), + }, groupedValueDestroyedFolderWithAdjusted(list, all, title, (c) => c.tree.realized.sopr.valueDestroyed, (c) => c.tree.realized.sopr.adjusted.valueDestroyed)), }; } @@ -375,8 +581,13 @@ export function createGroupedActivitySection({ list, all, title }) { name: "Activity", tree: groupedFullActivityTree(list, all, title, { name: "SOPR", - tree: groupedSoprCharts(list, all, (c) => c.tree.realized.sopr.ratio, title), - }), + tree: groupedSoprCharts( + list, + all, + (c) => c.tree.realized.sopr.ratio, + title, + ), + }, groupedValueDestroyedFolder(list, all, title, (c) => c.tree.realized.sopr.valueDestroyed)), }; } @@ -392,10 +603,15 @@ function groupedActivitySharedItems(list, all, title) { { name: "Coindays Destroyed", tree: groupedWindowsCumulative({ - list, all, title, metricTitle: "Coindays Destroyed", + list, + all, + title, + metricTitle: "Coindays Destroyed", getWindowSeries: (c, key) => c.tree.activity.coindaysDestroyed.sum[key], - getCumulativeSeries: (c) => c.tree.activity.coindaysDestroyed.cumulative, - seriesFn: line, unit: Unit.coindays, + getCumulativeSeries: (c) => + c.tree.activity.coindaysDestroyed.cumulative, + seriesFn: line, + unit: Unit.coindays, }), }, { @@ -404,7 +620,12 @@ function groupedActivitySharedItems(list, all, title) { 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 }), + line({ + series: tree.activity.dormancy[w.key], + name, + color, + unit: Unit.days, + }), ), })), }, @@ -414,14 +635,18 @@ function groupedActivitySharedItems(list, all, title) { name: w.name, title: title(`Sell Side Risk (${w.title})`), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => - line({ series: tree.realized.sellSideRiskRatio[w.key].ratio, name, color, unit: Unit.ratio }), + line({ + series: tree.realized.sellSideRiskRatio[w.key].ratio, + name, + color, + unit: Unit.ratio, + }), ), })), }, ]; } - /** * Grouped activity for cohorts with activity but basic realized (AgeRange/MaxAge) * @param {{ list: readonly (CohortAgeRange | CohortWithAdjusted)[], all: CohortAll, title: (name: string) => string }} args @@ -433,17 +658,26 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) { tree: [ { name: "Volume", - 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, - }), + 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, + }), + ), + })), + ...groupedProfitabilityArray( + list, + all, + title, + (c) => c.tree.activity.transferVolume.inProfit, + (c) => c.tree.activity.transferVolume.inLoss, ), - })), + ], }, { name: "SOPR", @@ -458,6 +692,7 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) { }), ), }, + groupedValueDestroyedFolder(list, all, title, (c) => c.tree.realized.sopr.valueDestroyed), { name: "Coindays Destroyed", tree: [ diff --git a/website/scripts/options/distribution/holdings.js b/website/scripts/options/distribution/holdings.js index 369af94fe..d8791e028 100644 --- a/website/scripts/options/distribution/holdings.js +++ b/website/scripts/options/distribution/holdings.js @@ -21,7 +21,7 @@ import { } from "../series.js"; import { satsBtcUsd, - mapCohorts, + flatMapCohorts, mapCohortsWithAll, flatMapCohortsWithAll, } from "../shared.js"; @@ -175,7 +175,7 @@ function profitabilityChart(supply, title) { } /** - * @param {{ toCirculating: { percent: AnySeriesPattern }, inProfit: { toCirculating: { percent: AnySeriesPattern } }, inLoss: { toCirculating: { percent: AnySeriesPattern } } }} supply + * @param {{ toCirculating: PercentRatioPattern, inProfit: { toCirculating: PercentRatioPattern }, inLoss: { toCirculating: PercentRatioPattern } }} supply * @param {(name: string) => string} title * @returns {PartialChartOption} */ @@ -184,9 +184,9 @@ function circulatingChart(supply, title) { name: "% of Circulating", title: title("Supply (% of Circulating)"), bottom: [ - line({ series: supply.toCirculating.percent, name: "Total", color: colors.default, unit: Unit.percentage }), - line({ series: supply.inProfit.toCirculating.percent, name: "In Profit", color: colors.profit, unit: Unit.percentage }), - line({ series: supply.inLoss.toCirculating.percent, name: "In Loss", color: colors.loss, unit: Unit.percentage }), + ...percentRatio({ pattern: supply.toCirculating, name: "Total", color: colors.default }), + ...percentRatio({ pattern: supply.inProfit.toCirculating, name: "In Profit", color: colors.profit }), + ...percentRatio({ pattern: supply.inLoss.toCirculating, name: "In Loss", color: colors.loss }), ], }; } @@ -539,7 +539,7 @@ export function createGroupedHoldingsSectionWithOwnSupply({ list, all, title }) tree: [ groupedSupplyTotal(list, all, title), ...groupedSupplyProfitLoss(list, all, title), - { name: "% of Circulating", title: title("Supply (% of Circulating)"), bottom: mapCohorts(list, ({ name, color, tree }) => line({ series: tree.supply.toCirculating.percent, name, color, unit: Unit.percentage })) }, + { name: "% of Circulating", title: title("Supply (% of Circulating)"), bottom: flatMapCohorts(list, ({ name, color, tree }) => percentRatio({ pattern: tree.supply.toCirculating, name, color })) }, ...groupedDeltaItems(list, all, (c) => c.tree.supply.delta, Unit.sats, title, "Supply"), ], }, @@ -560,7 +560,7 @@ export function createGroupedHoldingsSectionWithRelative({ list, all, title }) { tree: [ groupedSupplyTotal(list, all, title), ...groupedSupplyProfitLoss(list, all, title), - { name: "% of Circulating", title: title("Supply (% of Circulating)"), bottom: mapCohorts(list, ({ name, color, tree }) => line({ series: tree.supply.toCirculating.percent, name, color, unit: Unit.percentage })) }, + { name: "% of Circulating", title: title("Supply (% of Circulating)"), bottom: flatMapCohorts(list, ({ name, color, tree }) => percentRatio({ pattern: tree.supply.toCirculating, name, color })) }, { name: "% of Own Supply", title: title("Supply (% of Own)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.supply.inProfit.toOwn.percent, name, color, unit: Unit.percentage })) }, ...groupedDeltaItems(list, all, (c) => c.tree.supply.delta, Unit.sats, title, "Supply"), ], diff --git a/website/scripts/options/distribution/index.js b/website/scripts/options/distribution/index.js index 3515a558b..d1bf8a568 100644 --- a/website/scripts/options/distribution/index.js +++ b/website/scripts/options/distribution/index.js @@ -58,18 +58,15 @@ import { createGroupedCostBasisSectionWithPercentiles, } from "./cost-basis.js"; import { + createProfitabilitySection, createProfitabilitySectionAll, createProfitabilitySectionFull, - createProfitabilitySectionWithNupl, - createProfitabilitySectionWithInvestedCapitalPct, - createProfitabilitySectionBasicWithInvestedCapitalPct, - createProfitabilitySectionAddress, createProfitabilitySectionWithProfitLoss, + createProfitabilitySectionWithInvestedCapitalPct, createProfitabilitySectionLongTerm, createGroupedProfitabilitySection, createGroupedProfitabilitySectionWithNupl, createGroupedProfitabilitySectionWithInvestedCapitalPct, - createGroupedProfitabilitySectionBasicWithInvestedCapitalPct, } from "./profitability.js"; import { createActivitySection, @@ -161,7 +158,7 @@ export function createCohortFolderWithNupl(cohort) { createValuationSectionFull({ cohort, title }), createPricesSectionFull({ cohort, title }), createCostBasisSectionWithPercentiles({ cohort, title }), - createProfitabilitySectionWithNupl({ cohort, title }), + createProfitabilitySection({ cohort, title }), createActivitySection({ cohort, title }), ], }; @@ -237,30 +234,12 @@ export function createCohortFolderBasicWithMarketCap(cohort) { ...createHoldingsSection({ cohort, title }), createValuationSection({ cohort, title }), createPricesSectionBasic({ cohort, title }), - createProfitabilitySectionWithNupl({ cohort, title }), + createProfitabilitySection({ cohort, title }), createActivitySectionMinimal({ cohort, title }), ], }; } -/** - * Basic folder WITHOUT RelToMarketCap - * @param {CohortBasicWithoutMarketCap} cohort - * @returns {PartialOptionsGroup} - */ -export function createCohortFolderBasicWithoutMarketCap(cohort) { - const title = formatCohortTitle(cohort.name); - return { - name: cohort.name || "all", - tree: [ - ...createHoldingsSection({ cohort, title }), - createValuationSection({ cohort, title }), - createPricesSectionBasic({ cohort, title }), - createProfitabilitySectionBasicWithInvestedCapitalPct({ cohort, title }), - createActivitySectionMinimal({ cohort, title }), - ], - }; -} /** * Address folder: like basic but with address count @@ -275,7 +254,7 @@ export function createCohortFolderAddress(cohort) { ...createHoldingsSectionAddress({ cohort, title }), createValuationSection({ cohort, title }), createPricesSectionBasic({ cohort, title }), - createProfitabilitySectionAddress({ cohort, title }), + createProfitabilitySectionWithProfitLoss({ cohort, title }), createActivitySectionMinimal({ cohort, title }), ], }; @@ -313,7 +292,7 @@ export function createAddressCohortFolder(cohort) { ...createHoldingsSectionAddressAmount({ cohort, title }), createValuationSection({ cohort, title }), createPricesSectionBasic({ cohort, title }), - createProfitabilitySectionWithNupl({ cohort, title }), + createProfitabilitySection({ cohort, title }), createActivitySectionMinimal({ cohort, title }), ], }; @@ -458,32 +437,6 @@ export function createGroupedCohortFolderBasicWithMarketCap({ }; } -/** - * @param {CohortGroupBasicWithoutMarketCap} args - * @returns {PartialOptionsGroup} - */ -export function createGroupedCohortFolderBasicWithoutMarketCap({ - name, - title: groupTitle, - list, - all, -}) { - const title = formatCohortTitle(groupTitle); - return { - name: name || "all", - tree: [ - ...createGroupedHoldingsSection({ list, all, title }), - createGroupedValuationSection({ list, all, title }), - createGroupedPricesSection({ list, all, title }), - createGroupedProfitabilitySectionBasicWithInvestedCapitalPct({ - list, - all, - title, - }), - createGroupedActivitySectionMinimal({ list, all, title }), - ], - }; -} /** * @param {CohortGroupAddr} args @@ -502,7 +455,7 @@ export function createGroupedCohortFolderAddress({ ...createGroupedHoldingsSectionAddress({ list, all, title }), createGroupedValuationSection({ list, all, title }), createGroupedPricesSection({ list, all, title }), - createGroupedProfitabilitySectionBasicWithInvestedCapitalPct({ + createGroupedProfitabilitySection({ list, all, title, diff --git a/website/scripts/options/distribution/profitability.js b/website/scripts/options/distribution/profitability.js index 9074d04ab..88d3ad818 100644 --- a/website/scripts/options/distribution/profitability.js +++ b/website/scripts/options/distribution/profitability.js @@ -683,21 +683,11 @@ function realizedSubfolderBasic(r, title) { * @returns {PartialOptionsGroup} */ export function createProfitabilitySection({ cohort, title }) { - const { tree } = cohort; return { name: "Profitability", tree: [ - { - name: "Unrealized", - tree: [ - { - name: "NUPL", - title: title("NUPL"), - bottom: nuplSeries(tree.unrealized.nupl), - }, - ], - }, - realizedSubfolderBasic(tree.realized, title), + { name: "Unrealized", tree: [{ name: "NUPL", title: title("NUPL"), bottom: nuplSeries(cohort.tree.unrealized.nupl) }] }, + realizedSubfolderBasic(cohort.tree.realized, title), ], }; } @@ -792,30 +782,6 @@ export function createProfitabilitySectionFull({ cohort, title }) { }; } -/** - * Section with NUPL (basic cohorts with market cap — NuplPattern unrealized) - * @param {{ cohort: CohortBasicWithMarketCap, title: (name: string) => string }} args - * @returns {PartialOptionsGroup} - */ -export function createProfitabilitySectionWithNupl({ cohort, title }) { - const { tree } = cohort; - return { - name: "Profitability", - tree: [ - { - name: "Unrealized", - tree: [ - { - name: "NUPL", - title: title("NUPL"), - bottom: nuplSeries(tree.unrealized.nupl), - }, - ], - }, - realizedSubfolderBasic(tree.realized, title), - ], - }; -} /** * Section for LongTerm cohort @@ -859,78 +825,7 @@ export function createProfitabilitySectionWithInvestedCapitalPct({ }; } -/** - * Section with invested capital % but no unrealized relative (basic cohorts) - * @param {{ cohort: CohortBasicWithoutMarketCap, title: (name: string) => string }} args - * @returns {PartialOptionsGroup} - */ -export function createProfitabilitySectionBasicWithInvestedCapitalPct({ - cohort, - title, -}) { - const { tree } = cohort; - return { - name: "Profitability", - tree: [ - { - name: "Unrealized", - tree: [ - { - name: "NUPL", - title: title("NUPL"), - bottom: nuplSeries(tree.unrealized.nupl), - }, - ], - }, - realizedSubfolderBasic(tree.realized, title), - ], - }; -} -/** - * Section for CohortAddr (has unrealized profit/loss + NUPL, basic realized) - * @param {{ cohort: CohortAddr, title: (name: string) => string }} args - * @returns {PartialOptionsGroup} - */ -export function createProfitabilitySectionAddress({ cohort, title }) { - const u = cohort.tree.unrealized; - return { - name: "Profitability", - tree: [ - { - name: "Unrealized", - tree: [ - { name: "NUPL", title: title("NUPL"), bottom: nuplSeries(u.nupl) }, - { - name: "Profit", - title: title("Unrealized Profit"), - bottom: [ - line({ - series: u.profit.usd, - name: "Profit", - color: colors.profit, - unit: Unit.usd, - }), - ], - }, - { - name: "Loss", - title: title("Unrealized Loss"), - bottom: [ - line({ - series: u.loss.usd, - name: "Loss", - color: colors.loss, - unit: Unit.usd, - }), - ], - }, - ], - }, - realizedSubfolderBasic(cohort.tree.realized, title), - ], - }; -} // ============================================================================ // Grouped Cohort Helpers @@ -1324,24 +1219,6 @@ export function createGroupedProfitabilitySectionWithProfitLoss({ }; } -/** - * Grouped section with invested capital % (basic cohorts — uses NUPL only) - * @param {{ list: readonly CohortBasicWithoutMarketCap[], all: CohortAll, title: (name: string) => string }} args - * @returns {PartialOptionsGroup} - */ -export function createGroupedProfitabilitySectionBasicWithInvestedCapitalPct({ - list, - all, - title, -}) { - return { - name: "Profitability", - tree: [ - { name: "Unrealized", tree: groupedNuplCharts(list, all, title) }, - groupedRealizedSubfolder(list, all, title), - ], - }; -} /** * Grouped section for ageRange/maxAge cohorts diff --git a/website/scripts/options/distribution/valuation.js b/website/scripts/options/distribution/valuation.js index 3aaaa28ae..26430cf17 100644 --- a/website/scripts/options/distribution/valuation.js +++ b/website/scripts/options/distribution/valuation.js @@ -88,8 +88,8 @@ export function createValuationSectionFull({ cohort, title }) { ], }, { name: "MVRV", title: title("MVRV"), bottom: ratioBottomSeries(tree.realized.price) }, - { 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), + { 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 }) }, ], }; } diff --git a/website/scripts/options/partial.js b/website/scripts/options/partial.js index dbddc3e6a..4e18720ed 100644 --- a/website/scripts/options/partial.js +++ b/website/scripts/options/partial.js @@ -8,7 +8,6 @@ import { createCohortFolderLongTerm, createCohortFolderAgeRangeWithMatured, createCohortFolderBasicWithMarketCap, - createCohortFolderBasicWithoutMarketCap, createCohortFolderWithoutRelative, createCohortFolderAddress, createAddressCohortFolder, @@ -16,7 +15,6 @@ import { createGroupedCohortFolderWithNupl, createGroupedCohortFolderAgeRangeWithMatured, createGroupedCohortFolderBasicWithMarketCap, - createGroupedCohortFolderBasicWithoutMarketCap, createGroupedCohortFolderAddress, createGroupedAddressCohortFolder, createUtxoProfitabilitySection, @@ -160,14 +158,14 @@ export function createPartialOptions() { { name: "Range", tree: [ - createGroupedCohortFolderBasicWithoutMarketCap({ + createGroupedCohortFolderBasicWithMarketCap({ name: "Compare", title: "Amount Ranges", list: utxosAmountRange, all: cohortAll, }), ...utxosAmountRange.map( - createCohortFolderBasicWithoutMarketCap, + createCohortFolderBasicWithMarketCap, ), ], }, diff --git a/website/scripts/types.js b/website/scripts/types.js index c0185e6ca..7eb81313f 100644 --- a/website/scripts/types.js +++ b/website/scripts/types.js @@ -87,6 +87,9 @@ * @typedef {Brk.CoindaysCoinyearsDormancyTransferPattern} FullActivityPattern * * + * BPS + percent + ratio pattern + * @typedef {Brk.BpsPercentRatioPattern3} PercentRatioPattern + * * BPS + ratio pattern (for NUPL and similar) * @typedef {Brk.BpsRatioPattern} NuplPattern *