import { brk } from "../../utils/client.js"; import { colors } from "../../utils/colors.js"; import { Unit } from "../../utils/units.js"; import { ageRanges } from "../age-ranges.js"; import { line, price } from "../series.js"; import { satsBtcUsd, simplePriceRatioTree } from "../shared.js"; /** * @typedef {Object} CoinflowAgeRange * @property {string} name * @property {Color} color * @property {{ * mobility: AnySeriesPattern, * spendingRate: AnySeriesPattern, * spendingExposure: AnySeriesPattern, * supply: { mobile: AnyValuePattern, immobile: AnyValuePattern }, * }} tree */ /** * @param {readonly CoinflowAgeRange[]} ranges * @param {"mobility" | "spendingRate" | "spendingExposure"} key * @param {string} name * @returns {PartialChartOption} */ function ageRangeRatioChart(ranges, key, name) { return { name, title: `${name} by UTXO Age`, bottom: ranges.map((range) => line({ series: range.tree[key], name: range.name, color: range.color, unit: Unit.ratio, }), ), }; } /** * @param {readonly CoinflowAgeRange[]} ranges * @param {"mobile" | "immobile"} key * @param {string} name * @returns {PartialChartOption} */ function ageRangeSupplyChart(ranges, key, name) { return { name, title: `${name} Supply by UTXO Age`, bottom: ranges.flatMap((range) => satsBtcUsd({ pattern: range.tree.supply[key], name: range.name, color: range.color, }), ), }; } /** * Create Coinflow section. * @returns {PartialOptionsGroup} */ export function createCoinflowSection() { const { coinflow } = brk.series.frameworks; const ranges = ageRanges.map(({ key, ...range }) => ({ ...range, tree: coinflow.ageRange[key], })); const terms = [ { name: "STH", color: colors.term.short, tree: coinflow.sth }, { name: "LTH", color: colors.term.long, tree: coinflow.lth }, ]; const cohorts = [ { name: "All", color: colors.loss, tree: coinflow }, ...terms, ]; const frameworkCohorts = [ { name: "All", color: colors.coinflow, tree: coinflow }, ...terms, ]; const horizons = /** @type {const} */ ([ { key: "_8y", name: "8Y" }, { key: "_4y", name: "4Y" }, { key: "_2y", name: "2Y" }, { key: "_1y", name: "1Y" }, { key: "_6m", name: "6M" }, { key: "_3m", name: "3M" }, { key: "_1m", name: "1M" }, ]).map((horizon, index, all) => ({ ...horizon, color: colors.at(index, all.length), })); return { name: "Coinflow", tree: [ { name: "Price", tree: [ { name: "Compare", title: "Coinflow Price by Holder Term", top: frameworkCohorts.map(({ name, color, tree }) => price({ series: tree.price, name, color, }), ), bottom: frameworkCohorts.map(({ name, color, tree }) => line({ series: tree.price.ratio, name: `Spot / ${name}`, color, unit: Unit.ratio, }), ), }, ...frameworkCohorts.map(({ name, color, tree }) => { const title = name === "All" ? "Coinflow Price" : `${name} Coinflow Price`; const [chart] = simplePriceRatioTree({ pattern: tree.price, title, legend: name, color, }); return { ...chart, name }; }), ], }, { name: "Capitalization", tree: [ { name: "Compare", title: "Coinflow Cap by Holder Term", bottom: frameworkCohorts.map(({ name, color, tree }) => line({ series: tree.cap.usd, name, color, unit: Unit.usd, }), ), }, ...frameworkCohorts.map(({ name, color, tree }) => ({ name, title: name === "All" ? "Coinflow Cap" : `${name} Coinflow Cap`, bottom: [ line({ series: tree.cap.usd, name, color, unit: Unit.usd, }), ], })), ], }, { name: "Supply", tree: [ { name: "Overview", title: "Mobile vs Immobile Supply", bottom: [ ...satsBtcUsd({ pattern: coinflow.supply.mobile, name: "Mobile", color: colors.mobile, }), ...satsBtcUsd({ pattern: coinflow.supply.immobile, name: "Immobile", color: colors.immobile, }), ], }, { name: "By Holder Term", tree: [ { name: "Mobile", title: "Mobile Supply by Holder Term", bottom: terms.flatMap(({ name, color, tree }) => satsBtcUsd({ pattern: tree.supply.mobile, name, color, }), ), }, { name: "Immobile", title: "Immobile Supply by Holder Term", bottom: terms.flatMap(({ name, color, tree }) => satsBtcUsd({ pattern: tree.supply.immobile, name, color, }), ), }, ], }, { name: "By UTXO Age", tree: [ ageRangeSupplyChart(ranges, "mobile", "Mobile"), ageRangeSupplyChart(ranges, "immobile", "Immobile"), ], }, { name: "In Loss", tree: [ { name: "By Holder Term", title: "Mobile Supply in Loss by Holder Term", bottom: cohorts.map(({ name, color, tree }) => line({ series: tree.supply.mobile.inLoss.share, name, color, unit: Unit.ratio, }), ), }, { name: "By Horizon", tree: cohorts.map(({ name, tree }) => ({ name, title: name === "All" ? "Mobile Supply in Loss by Horizon" : `${name} Mobile Supply in Loss by Horizon`, bottom: horizons.map((horizon) => line({ series: tree.horizon[horizon.key].supply.inLoss.share, name: horizon.name, color: horizon.color, unit: Unit.ratio, }), ), })), }, ], }, ], }, { name: "Activity", tree: [ { name: "By UTXO Age", tree: [ ageRangeRatioChart(ranges, "mobility", "Mobility"), ageRangeRatioChart( ranges, "spendingRate", "Spending Rate", ), ageRangeRatioChart( ranges, "spendingExposure", "Spending Exposure", ), ], }, ], }, ], }; }