Files
brk/website/scripts/options/frameworks/coinflow.js
T
2026-07-29 10:50:14 +02:00

187 lines
4.6 KiB
JavaScript

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 } 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;
const ranges = ageRanges.map(({ key, ...range }) => ({
...range,
tree: coinflow.ageRange[key],
}));
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: "Supply",
tree: [
{
name: "Breakdown",
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: "Mobile in Loss",
title: "Mobile Supply in Loss",
bottom: [
line({
series: coinflow.supply.mobile.inLoss.share,
name: "Lifetime",
color: colors.loss,
unit: Unit.ratio,
}),
],
},
{
name: "In Loss by Horizon",
title: "Mobile Supply in Loss by Horizon",
bottom: horizons.map((horizon) =>
line({
series:
coinflow.horizon[horizon.key].supply.inLoss.share,
name: horizon.name,
color: horizon.color,
unit: Unit.ratio,
}),
),
},
],
},
{
name: "Cap",
title: "Coinflow Cap",
bottom: [
line({
series: coinflow.cap.usd,
name: "Coinflow",
color: colors.coinflow,
unit: Unit.usd,
}),
],
},
{
name: "Price",
title: "Coinflow Price",
top: [
price({
series: coinflow.price,
name: "Coinflow",
color: colors.coinflow,
}),
],
bottom: [
line({
series: coinflow.price.ratio,
name: "Spot / Coinflow",
color: colors.coinflow,
unit: Unit.ratio,
}),
],
},
{
name: "Age Range",
tree: [
ageRangeRatioChart(ranges, "mobility", "Mobility"),
ageRangeRatioChart(ranges, "spendingRate", "Spending Rate"),
ageRangeRatioChart(
ranges,
"spendingExposure",
"Spending Exposure",
),
{
name: "Supply",
tree: [
ageRangeSupplyChart(ranges, "mobile", "Mobile"),
ageRangeSupplyChart(ranges, "immobile", "Immobile"),
],
},
],
},
],
};
}