Files
brk/website/scripts/options/distribution/index.js
2026-03-14 12:36:37 +01:00

537 lines
16 KiB
JavaScript

/**
* Cohort module - exports all cohort-related functionality
*
* Folder builders compose sections from building blocks:
* - holdings.js: Supply, UTXO Count, Address Count
* - valuation.js: Realized Cap, Market Cap, MVRV
* - prices.js: Realized Price, ratios
* - cost-basis.js: Cost basis percentiles
* - profitability.js: Unrealized/Realized P&L, Invested Capital
* - activity.js: SOPR, Volume, Lifespan
*/
import { formatCohortTitle } from "../shared.js";
// Section builders
import {
createHoldingsSection,
createHoldingsSectionAll,
createHoldingsSectionAddress,
createHoldingsSectionAddressAmount,
createHoldingsSectionWithRelative,
createHoldingsSectionWithOwnSupply,
createGroupedHoldingsSection,
createGroupedHoldingsSectionAddress,
createGroupedHoldingsSectionAddressAmount,
createGroupedHoldingsSectionWithRelative,
createGroupedHoldingsSectionWithOwnSupply,
} from "./holdings.js";
import {
createValuationSection,
createValuationSectionFull,
createGroupedValuationSection,
createGroupedValuationSectionWithOwnMarketCap,
} from "./valuation.js";
import {
createPricesSectionFull,
createPricesSectionBasic,
createGroupedPricesSection,
} from "./prices.js";
import {
createCostBasisSectionWithPercentiles,
createGroupedCostBasisSectionWithPercentiles,
} from "./cost-basis.js";
import {
createProfitabilitySection,
createProfitabilitySectionAll,
createProfitabilitySectionFull,
createProfitabilitySectionWithNupl,
createProfitabilitySectionWithInvestedCapitalPct,
createProfitabilitySectionBasicWithInvestedCapitalPct,
createProfitabilitySectionLongTerm,
createGroupedProfitabilitySection,
createGroupedProfitabilitySectionWithNupl,
createGroupedProfitabilitySectionWithInvestedCapitalPct,
createGroupedProfitabilitySectionBasicWithInvestedCapitalPct,
createGroupedProfitabilitySectionLongTerm,
} from "./profitability.js";
import {
createActivitySection,
createActivitySectionWithAdjusted,
createActivitySectionWithActivity,
createActivitySectionMinimal,
createGroupedActivitySection,
createGroupedActivitySectionWithAdjusted,
createGroupedActivitySectionWithActivity,
createGroupedActivitySectionMinimal,
} from "./activity.js";
// Re-export data builder
export { buildCohortData } from "./data.js";
// ============================================================================
// Single Cohort Folder Builders
// ============================================================================
/**
* All folder: for the special "All" cohort
* @param {CohortAll} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderAll(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionAll({ cohort, title }),
createValuationSectionFull({ cohort, title }),
createPricesSectionFull({ cohort, title }),
createCostBasisSectionWithPercentiles({ cohort, title }),
createProfitabilitySectionAll({ cohort, title }),
createActivitySectionWithAdjusted({ cohort, title }),
],
};
}
/**
* Full folder: adjustedSopr + percentiles + RelToMarketCap
* @param {CohortFull} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderFull(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionWithRelative({ cohort, title }),
createValuationSectionFull({ cohort, title }),
createPricesSectionFull({ cohort, title }),
createCostBasisSectionWithPercentiles({ cohort, title }),
createProfitabilitySectionFull({ cohort, title }),
createActivitySectionWithAdjusted({ cohort, title }),
],
};
}
/**
* Adjusted folder: adjustedSopr only, no percentiles
* @param {CohortWithAdjusted} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderWithAdjusted(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionWithOwnSupply({ cohort, title }),
createValuationSection({ cohort, title }),
createPricesSectionBasic({ cohort, title }),
createProfitabilitySectionWithNupl({ cohort, title }),
createActivitySectionWithActivity({ cohort, title }),
],
};
}
/**
* Folder for cohorts with nupl + percentiles
* @param {CohortWithNuplPercentiles} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderWithNupl(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionWithRelative({ cohort, title }),
createValuationSectionFull({ cohort, title }),
createPricesSectionFull({ cohort, title }),
createCostBasisSectionWithPercentiles({ cohort, title }),
createProfitabilitySectionWithNupl({ cohort, title }),
createActivitySection({ cohort, title }),
],
};
}
/**
* LongTerm folder: has own market cap + NUPL + peak regret + P/L ratio
* @param {CohortLongTerm} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderLongTerm(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionWithRelative({ cohort, title }),
createValuationSectionFull({ cohort, title }),
createPricesSectionFull({ cohort, title }),
createCostBasisSectionWithPercentiles({ cohort, title }),
createProfitabilitySectionLongTerm({ cohort, title }),
createActivitySection({ cohort, title }),
],
};
}
/**
* Age range folder: no nupl
* @param {CohortAgeRange} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderAgeRange(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionWithOwnSupply({ cohort, title }),
createValuationSection({ cohort, title }),
createPricesSectionBasic({ cohort, title }),
createProfitabilitySectionWithInvestedCapitalPct({ cohort, title }),
createActivitySectionWithActivity({ cohort, title }),
],
};
}
/**
* Basic folder WITH RelToMarketCap
* @param {CohortBasicWithMarketCap} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderBasicWithMarketCap(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSection({ cohort, title }),
createValuationSection({ cohort, title }),
createPricesSectionBasic({ cohort, title }),
createProfitabilitySectionWithNupl({ 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
* @param {CohortAddress} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderAddress(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionAddress({ cohort, title }),
createValuationSection({ cohort, title }),
createPricesSectionBasic({ cohort, title }),
createProfitabilitySectionBasicWithInvestedCapitalPct({ cohort, title }),
createActivitySectionMinimal({ cohort, title }),
],
};
}
/**
* Folder for cohorts WITHOUT relative section
* @param {CohortWithoutRelative} cohort
* @returns {PartialOptionsGroup}
*/
export function createCohortFolderWithoutRelative(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSection({ cohort, title }),
createValuationSection({ cohort, title }),
createPricesSectionBasic({ cohort, title }),
createProfitabilitySection({ cohort, title }),
createActivitySectionMinimal({ cohort, title }),
],
};
}
/**
* Address amount cohort folder: has NUPL + addrCount
* @param {AddressCohortObject} cohort
* @returns {PartialOptionsGroup}
*/
export function createAddressCohortFolder(cohort) {
const title = formatCohortTitle(cohort.name);
return {
name: cohort.name || "all",
tree: [
createHoldingsSectionAddressAmount({ cohort, title }),
createValuationSection({ cohort, title }),
createPricesSectionBasic({ cohort, title }),
createProfitabilitySectionWithNupl({ cohort, title }),
createActivitySectionMinimal({ cohort, title }),
],
};
}
// ============================================================================
// Grouped Cohort Folder Builders
// ============================================================================
/**
* @param {CohortGroupFull} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderFull({
name,
title: groupTitle,
list,
all,
}) {
const title = formatCohortTitle(groupTitle);
return {
name: name || "all",
tree: [
createGroupedHoldingsSectionWithRelative({ list, all, title }),
createGroupedValuationSectionWithOwnMarketCap({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedCostBasisSectionWithPercentiles({ list, all, title }),
createGroupedProfitabilitySectionWithNupl({ list, all, title }),
createGroupedActivitySectionWithAdjusted({ list, all, title }),
],
};
}
/**
* @param {CohortGroupWithAdjusted} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderWithAdjusted({
name,
title: groupTitle,
list,
all,
}) {
const title = formatCohortTitle(groupTitle);
return {
name: name || "all",
tree: [
createGroupedHoldingsSectionWithOwnSupply({ list, all, title }),
createGroupedValuationSection({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedProfitabilitySectionWithInvestedCapitalPct({ list, all, title }),
createGroupedActivitySectionWithActivity({ list, all, title }),
],
};
}
/**
* @param {CohortGroupWithNuplPercentiles} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderWithNupl({
name,
title: groupTitle,
list,
all,
}) {
const title = formatCohortTitle(groupTitle);
return {
name: name || "all",
tree: [
createGroupedHoldingsSectionWithRelative({ list, all, title }),
createGroupedValuationSection({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedCostBasisSectionWithPercentiles({ list, all, title }),
createGroupedProfitabilitySectionWithNupl({ list, all, title }),
createGroupedActivitySection({ list, all, title }),
],
};
}
/**
* @param {CohortGroupLongTerm} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderLongTerm({
name,
title: groupTitle,
list,
all,
}) {
const title = formatCohortTitle(groupTitle);
return {
name: name || "all",
tree: [
createGroupedHoldingsSectionWithRelative({ list, all, title }),
createGroupedValuationSectionWithOwnMarketCap({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedCostBasisSectionWithPercentiles({ list, all, title }),
createGroupedProfitabilitySectionLongTerm({ list, all, title }),
createGroupedActivitySection({ list, all, title }),
],
};
}
/**
* @param {CohortGroupAgeRange} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderAgeRange({
name,
title: groupTitle,
list,
all,
}) {
const title = formatCohortTitle(groupTitle);
return {
name: name || "all",
tree: [
createGroupedHoldingsSectionWithOwnSupply({ list, all, title }),
createGroupedValuationSection({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedProfitabilitySectionWithInvestedCapitalPct({
list,
all,
title,
}),
createGroupedActivitySectionWithActivity({ list, all, title }),
],
};
}
/**
* @param {CohortGroupBasicWithMarketCap} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderBasicWithMarketCap({
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 }),
createGroupedProfitabilitySection({ list, all, title }),
createGroupedActivitySectionMinimal({ list, all, title }),
],
};
}
/**
* @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 {CohortGroupAddress} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderAddress({
name,
title: groupTitle,
list,
all,
}) {
const title = formatCohortTitle(groupTitle);
return {
name: name || "all",
tree: [
createGroupedHoldingsSectionAddress({ list, all, title }),
createGroupedValuationSection({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedProfitabilitySectionBasicWithInvestedCapitalPct({
list,
all,
title,
}),
createGroupedActivitySectionMinimal({ list, all, title }),
],
};
}
/**
* @param {CohortGroupWithoutRelative} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedCohortFolderWithoutRelative({
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 }),
createGroupedProfitabilitySection({ list, all, title }),
createGroupedActivitySectionMinimal({ list, all, title }),
],
};
}
/**
* @param {AddressCohortGroupObject} args
* @returns {PartialOptionsGroup}
*/
export function createGroupedAddressCohortFolder({
name,
title: groupTitle,
list,
all,
}) {
const title = formatCohortTitle(groupTitle);
return {
name: name || "all",
tree: [
createGroupedHoldingsSectionAddressAmount({ list, all, title }),
createGroupedValuationSection({ list, all, title }),
createGroupedPricesSection({ list, all, title }),
createGroupedProfitabilitySection({ list, all, title }),
createGroupedActivitySectionMinimal({ list, all, title }),
],
};
}