global: snapshot

This commit is contained in:
nym21
2026-01-11 17:19:00 +01:00
parent 6f45ec13f3
commit ea70c381de
419 changed files with 38059 additions and 7653 deletions
+1
View File
@@ -0,0 +1 @@
*/**/*.md
+50 -50
View File
@@ -1558,12 +1558,13 @@
</script>
<!-- IMPORTMAP -->
<link rel="modulepreload" href="/scripts/chart/index.02f627a6.js">
<link rel="modulepreload" href="/scripts/chart/index.891e1546.js">
<link rel="modulepreload" href="/scripts/chart/oklch.21450255.js">
<link rel="modulepreload" href="/scripts/entry.10db80a8.js">
<link rel="modulepreload" href="/scripts/entry.fe229b42.js">
<link rel="modulepreload" href="/scripts/lazy.1ae52534.js">
<link rel="modulepreload" href="/scripts/main.22a5bd79.js">
<link rel="modulepreload" href="/scripts/modules/brk-client/index.922b14c3.js">
<link rel="modulepreload" href="/scripts/modules/brk-client/index.d7a5bd12.js">
<link rel="modulepreload" href="/scripts/modules/brk-client/test.119c2b6e.js">
<link rel="modulepreload" href="/scripts/modules/lean-qr/2.6.1/index.09195c13.mjs">
<link rel="modulepreload" href="/scripts/modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.803b7fb0.mjs">
<link rel="modulepreload" href="/scripts/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.1e264451.mjs">
@@ -1575,33 +1576,32 @@
<link rel="modulepreload" href="/scripts/modules/solidjs-signals/0.6.3/dist/prod.2f80e335.js">
<link rel="modulepreload" href="/scripts/modules/solidjs-signals/0.8.5/dist/prod.8ae56250.js">
<link rel="modulepreload" href="/scripts/options/_partial_old.62bf3faa.js">
<link rel="modulepreload" href="/scripts/options/chain.4fe9edeb.js">
<link rel="modulepreload" href="/scripts/options/cohorts/address.446eab82.js">
<link rel="modulepreload" href="/scripts/options/cohorts/data.92c2a350.js">
<link rel="modulepreload" href="/scripts/options/cohorts/index.47f11280.js">
<link rel="modulepreload" href="/scripts/options/cohorts/shared.028a47f5.js">
<link rel="modulepreload" href="/scripts/options/cohorts/types.1e23c94d.js">
<link rel="modulepreload" href="/scripts/options/cohorts/utxo.90aa2b4f.js">
<link rel="modulepreload" href="/scripts/options/cointime.d859b72a.js">
<link rel="modulepreload" href="/scripts/options/chain.3d99e062.js">
<link rel="modulepreload" href="/scripts/options/cohorts/address.2e8a42cb.js">
<link rel="modulepreload" href="/scripts/options/cohorts/data.f7f24b88.js">
<link rel="modulepreload" href="/scripts/options/cohorts/index.b0e57c9d.js">
<link rel="modulepreload" href="/scripts/options/cohorts/shared.0602caa3.js">
<link rel="modulepreload" href="/scripts/options/cohorts/utxo.f0e69857.js">
<link rel="modulepreload" href="/scripts/options/cointime.a69ba0e7.js">
<link rel="modulepreload" href="/scripts/options/colors/cohorts.262d4551.js">
<link rel="modulepreload" href="/scripts/options/colors/index.a54dc83f.js">
<link rel="modulepreload" href="/scripts/options/colors/misc.bee7dbee.js">
<link rel="modulepreload" href="/scripts/options/constants.190d9d82.js">
<link rel="modulepreload" href="/scripts/options/context.bd3985fb.js">
<link rel="modulepreload" href="/scripts/options/constants.f5b525fe.js">
<link rel="modulepreload" href="/scripts/options/context.85881310.js">
<link rel="modulepreload" href="/scripts/options/full.cbb89ca5.js">
<link rel="modulepreload" href="/scripts/options/market/averages.52ae3c62.js">
<link rel="modulepreload" href="/scripts/options/market/index.e6011fff.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/bands.eb583383.js">
<link rel="modulepreload" href="/scripts/options/market/averages.d95aa3e1.js">
<link rel="modulepreload" href="/scripts/options/market/index.6896a1b5.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/bands.81b19b83.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/index.70e9b3e4.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/momentum.8f20362c.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/onchain.d06affed.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/volatility.a12b9495.js">
<link rel="modulepreload" href="/scripts/options/market/investing.c00cb6ed.js">
<link rel="modulepreload" href="/scripts/options/market/performance.f381010b.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/momentum.48e71442.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/onchain.f75ddfd9.js">
<link rel="modulepreload" href="/scripts/options/market/indicators/volatility.08ec92d7.js">
<link rel="modulepreload" href="/scripts/options/market/investing.57ded805.js">
<link rel="modulepreload" href="/scripts/options/market/performance.36c7ad40.js">
<link rel="modulepreload" href="/scripts/options/market/utils.e3e058d8.js">
<link rel="modulepreload" href="/scripts/options/partial.1bfb5914.js">
<link rel="modulepreload" href="/scripts/options/series.3702ffc7.js">
<link rel="modulepreload" href="/scripts/options/types.19186083.js">
<link rel="modulepreload" href="/scripts/options/partial.ab8fdf12.js">
<link rel="modulepreload" href="/scripts/options/series.5a2a34ed.js">
<link rel="modulepreload" href="/scripts/options/types.64db5149.js">
<link rel="modulepreload" href="/scripts/options/unused.24a71427.js">
<link rel="modulepreload" href="/scripts/panes/chart/index.3d231714.js">
<link rel="modulepreload" href="/scripts/panes/chart/screenshot.adc8da89.js">
@@ -1622,18 +1622,19 @@
<link rel="modulepreload" href="/scripts/utils/serde.f9c7ed2b.js">
<link rel="modulepreload" href="/scripts/utils/storage.cbd2ff9c.js">
<link rel="modulepreload" href="/scripts/utils/timing.ae6a47b8.js">
<link rel="modulepreload" href="/scripts/utils/units.97b1a45f.js">
<link rel="modulepreload" href="/scripts/utils/units.30278ea7.js">
<link rel="modulepreload" href="/scripts/utils/url.20469bf9.js">
<link rel="modulepreload" href="/scripts/utils/ws.fe3fb4b1.js">
<script type="importmap">
{
"imports": {
"/scripts/chart/index.js": "/scripts/chart/index.02f627a6.js",
"/scripts/chart/index.js": "/scripts/chart/index.891e1546.js",
"/scripts/chart/oklch.js": "/scripts/chart/oklch.21450255.js",
"/scripts/entry.js": "/scripts/entry.10db80a8.js",
"/scripts/entry.js": "/scripts/entry.fe229b42.js",
"/scripts/lazy.js": "/scripts/lazy.1ae52534.js",
"/scripts/main.js": "/scripts/main.22a5bd79.js",
"/scripts/modules/brk-client/index.js": "/scripts/modules/brk-client/index.922b14c3.js",
"/scripts/modules/brk-client/index.js": "/scripts/modules/brk-client/index.d7a5bd12.js",
"/scripts/modules/brk-client/test.js": "/scripts/modules/brk-client/test.119c2b6e.js",
"/scripts/modules/lean-qr/2.6.1/index.mjs": "/scripts/modules/lean-qr/2.6.1/index.09195c13.mjs",
"/scripts/modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs": "/scripts/modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.803b7fb0.mjs",
"/scripts/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.mjs": "/scripts/modules/lightweight-charts/5.0.9/dist/lightweight-charts.standalone.production.1e264451.mjs",
@@ -1645,33 +1646,32 @@
"/scripts/modules/solidjs-signals/0.6.3/dist/prod.js": "/scripts/modules/solidjs-signals/0.6.3/dist/prod.2f80e335.js",
"/scripts/modules/solidjs-signals/0.8.5/dist/prod.js": "/scripts/modules/solidjs-signals/0.8.5/dist/prod.8ae56250.js",
"/scripts/options/_partial_old.js": "/scripts/options/_partial_old.62bf3faa.js",
"/scripts/options/chain.js": "/scripts/options/chain.4fe9edeb.js",
"/scripts/options/cohorts/address.js": "/scripts/options/cohorts/address.446eab82.js",
"/scripts/options/cohorts/data.js": "/scripts/options/cohorts/data.92c2a350.js",
"/scripts/options/cohorts/index.js": "/scripts/options/cohorts/index.47f11280.js",
"/scripts/options/cohorts/shared.js": "/scripts/options/cohorts/shared.028a47f5.js",
"/scripts/options/cohorts/types.js": "/scripts/options/cohorts/types.1e23c94d.js",
"/scripts/options/cohorts/utxo.js": "/scripts/options/cohorts/utxo.90aa2b4f.js",
"/scripts/options/cointime.js": "/scripts/options/cointime.d859b72a.js",
"/scripts/options/chain.js": "/scripts/options/chain.3d99e062.js",
"/scripts/options/cohorts/address.js": "/scripts/options/cohorts/address.2e8a42cb.js",
"/scripts/options/cohorts/data.js": "/scripts/options/cohorts/data.f7f24b88.js",
"/scripts/options/cohorts/index.js": "/scripts/options/cohorts/index.b0e57c9d.js",
"/scripts/options/cohorts/shared.js": "/scripts/options/cohorts/shared.0602caa3.js",
"/scripts/options/cohorts/utxo.js": "/scripts/options/cohorts/utxo.f0e69857.js",
"/scripts/options/cointime.js": "/scripts/options/cointime.a69ba0e7.js",
"/scripts/options/colors/cohorts.js": "/scripts/options/colors/cohorts.262d4551.js",
"/scripts/options/colors/index.js": "/scripts/options/colors/index.a54dc83f.js",
"/scripts/options/colors/misc.js": "/scripts/options/colors/misc.bee7dbee.js",
"/scripts/options/constants.js": "/scripts/options/constants.190d9d82.js",
"/scripts/options/context.js": "/scripts/options/context.bd3985fb.js",
"/scripts/options/constants.js": "/scripts/options/constants.f5b525fe.js",
"/scripts/options/context.js": "/scripts/options/context.85881310.js",
"/scripts/options/full.js": "/scripts/options/full.cbb89ca5.js",
"/scripts/options/market/averages.js": "/scripts/options/market/averages.52ae3c62.js",
"/scripts/options/market/index.js": "/scripts/options/market/index.e6011fff.js",
"/scripts/options/market/indicators/bands.js": "/scripts/options/market/indicators/bands.eb583383.js",
"/scripts/options/market/averages.js": "/scripts/options/market/averages.d95aa3e1.js",
"/scripts/options/market/index.js": "/scripts/options/market/index.6896a1b5.js",
"/scripts/options/market/indicators/bands.js": "/scripts/options/market/indicators/bands.81b19b83.js",
"/scripts/options/market/indicators/index.js": "/scripts/options/market/indicators/index.70e9b3e4.js",
"/scripts/options/market/indicators/momentum.js": "/scripts/options/market/indicators/momentum.8f20362c.js",
"/scripts/options/market/indicators/onchain.js": "/scripts/options/market/indicators/onchain.d06affed.js",
"/scripts/options/market/indicators/volatility.js": "/scripts/options/market/indicators/volatility.a12b9495.js",
"/scripts/options/market/investing.js": "/scripts/options/market/investing.c00cb6ed.js",
"/scripts/options/market/performance.js": "/scripts/options/market/performance.f381010b.js",
"/scripts/options/market/indicators/momentum.js": "/scripts/options/market/indicators/momentum.48e71442.js",
"/scripts/options/market/indicators/onchain.js": "/scripts/options/market/indicators/onchain.f75ddfd9.js",
"/scripts/options/market/indicators/volatility.js": "/scripts/options/market/indicators/volatility.08ec92d7.js",
"/scripts/options/market/investing.js": "/scripts/options/market/investing.57ded805.js",
"/scripts/options/market/performance.js": "/scripts/options/market/performance.36c7ad40.js",
"/scripts/options/market/utils.js": "/scripts/options/market/utils.e3e058d8.js",
"/scripts/options/partial.js": "/scripts/options/partial.1bfb5914.js",
"/scripts/options/series.js": "/scripts/options/series.3702ffc7.js",
"/scripts/options/types.js": "/scripts/options/types.19186083.js",
"/scripts/options/partial.js": "/scripts/options/partial.ab8fdf12.js",
"/scripts/options/series.js": "/scripts/options/series.5a2a34ed.js",
"/scripts/options/types.js": "/scripts/options/types.64db5149.js",
"/scripts/options/unused.js": "/scripts/options/unused.24a71427.js",
"/scripts/panes/chart/index.js": "/scripts/panes/chart/index.3d231714.js",
"/scripts/panes/chart/screenshot.js": "/scripts/panes/chart/screenshot.adc8da89.js",
@@ -1692,7 +1692,7 @@
"/scripts/utils/serde.js": "/scripts/utils/serde.f9c7ed2b.js",
"/scripts/utils/storage.js": "/scripts/utils/storage.cbd2ff9c.js",
"/scripts/utils/timing.js": "/scripts/utils/timing.ae6a47b8.js",
"/scripts/utils/units.js": "/scripts/utils/units.97b1a45f.js",
"/scripts/utils/units.js": "/scripts/utils/units.30278ea7.js",
"/scripts/utils/url.js": "/scripts/utils/url.20469bf9.js",
"/scripts/utils/ws.js": "/scripts/utils/ws.fe3fb4b1.js"
}
+15 -8
View File
@@ -5,7 +5,7 @@
*
* @import { Signal, Signals, Accessor } from "./signals.js";
*
* @import { BrkClient, CatalogTree_Distribution_UtxoCohorts as UtxoCohortTree, CatalogTree_Distribution_AddressCohorts as AddressCohortTree, CatalogTree_Distribution_UtxoCohorts_All as AllUtxoPattern, _10yTo12yPattern as MinAgePattern, _0satsPattern2 as UtxoAmountPattern, _0satsPattern as AddressAmountPattern, Ratio1ySdPattern, Dollars, Price111dSmaPattern as EmaRatioPattern, Index, BlockCountPattern, SizePattern, FullnessPattern, FeeRatePattern, CoinbasePattern, ActivePriceRatioPattern, _0satsPattern, UnclaimedRewardsPattern as ValuePattern, Metric, MetricPattern, AnyMetricPattern, MetricEndpoint, MetricData, AnyMetricEndpoint, AnyMetricData, AddrCountPattern, CatalogTree_Blocks_Interval as IntervalPattern } from "./modules/brk-client/index.js"
* @import { BrkClient, CatalogTree_Distribution_UtxoCohorts as UtxoCohortTree, CatalogTree_Distribution_AddressCohorts as AddressCohortTree, CatalogTree_Distribution_UtxoCohorts_All as AllUtxoPattern, CatalogTree_Distribution_UtxoCohorts_Term_Short as ShortTermPattern, CatalogTree_Distribution_UtxoCohorts_Term_Long as LongTermPattern, _10yPattern as MaxAgePattern, _10yTo12yPattern as AgeRangePattern, _0satsPattern2 as UtxoAmountPattern, _0satsPattern as AddressAmountPattern, _100btcPattern as BasicUtxoPattern, _0satsPattern2 as EpochPattern, Ratio1ySdPattern, Dollars, Price111dSmaPattern as EmaRatioPattern, Index, BlockCountPattern, SizePattern, FullnessPattern, FeeRatePattern, CoinbasePattern, ActivePriceRatioPattern, _0satsPattern, UnclaimedRewardsPattern as ValuePattern, Metric, MetricPattern, AnyMetricPattern, MetricEndpoint, MetricData, AnyMetricEndpoint, AnyMetricData, AddrCountPattern, CatalogTree_Blocks_Interval as IntervalPattern, _24hCoinbaseSumPattern as SupplyPattern, RelativePattern, RelativePattern2, RelativePattern5, CatalogTree_Distribution_UtxoCohorts_All_Relative as AllRelativePattern } from "./modules/brk-client/index.js"
*
* @import { Resources, MetricResource } from './resources.js'
*
@@ -15,7 +15,9 @@
*
* @import { WebSockets } from "./utils/ws.js"
*
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, UtxoCohortGroupObject, AddressCohortGroupObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, AgeCohortObject, AmountCohortObject, AgeCohortGroupObject, AmountCohortGroupObject } from "./options/partial.js"
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedBaselineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, PatternAll, PatternFull, PatternWithAdjusted, PatternWithPercentiles, PatternBasic, CohortAll, CohortFull, CohortWithAdjusted, CohortWithPercentiles, CohortBasic, CohortGroupFull, CohortGroupWithAdjusted, CohortGroupWithPercentiles, CohortGroupBasic, UtxoCohortGroupObject, AddressCohortGroupObject } from "./options/partial.js"
*
* @import { line as LineSeriesFn, baseline as BaselineSeriesFn, histogram as HistogramSeriesFn } from "./options/series.js"
*
* @import { UnitObject as Unit } from "./utils/units.js"
*
@@ -34,17 +36,22 @@
* @typedef {keyof PoolIdToPoolName} PoolId
*
* Pattern unions by cohort type
* @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} UtxoCohortPattern
* @typedef {AllUtxoPattern | AgeRangePattern | UtxoAmountPattern} UtxoCohortPattern
* @typedef {AddressAmountPattern} AddressCohortPattern
* @typedef {UtxoCohortPattern | AddressCohortPattern} CohortPattern
*
* Relative pattern capability types
* @typedef {RelativePattern | RelativePattern5} RelativeWithMarketCap
* @typedef {RelativePattern2 | RelativePattern5} RelativeWithOwnMarketCap
* @typedef {RelativePattern2 | RelativePattern5 | AllRelativePattern} RelativeWithOwnPnl
*
* Capability-based pattern groupings (patterns that have specific properties)
* @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} PatternWithRealizedPrice
* @typedef {AllUtxoPattern | AgeRangePattern | UtxoAmountPattern} PatternWithRealizedPrice
* @typedef {AllUtxoPattern} PatternWithFullRealized
* @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} PatternWithNupl
* @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} PatternWithCostBasis
* @typedef {AllUtxoPattern | MinAgePattern | UtxoAmountPattern} PatternWithActivity
* @typedef {AllUtxoPattern | MinAgePattern} PatternWithCostBasisPercentiles
* @typedef {AllUtxoPattern | AgeRangePattern | UtxoAmountPattern} PatternWithNupl
* @typedef {AllUtxoPattern | AgeRangePattern | UtxoAmountPattern} PatternWithCostBasis
* @typedef {AllUtxoPattern | AgeRangePattern | UtxoAmountPattern} PatternWithActivity
* @typedef {AllUtxoPattern | AgeRangePattern} PatternWithCostBasisPercentiles
*
* Cohort objects with specific pattern capabilities
* @typedef {{ name: string, title: string, color: Color, tree: PatternWithRealizedPrice }} CohortWithRealizedPrice
+153 -75
View File
@@ -11,7 +11,7 @@ export function createChainSection(ctx) {
const {
colors,
brk,
s,
line,
createPriceLine,
fromSizePattern,
fromFullnessPattern,
@@ -20,6 +20,7 @@ export function createChainSection(ctx) {
fromValuePattern,
fromBlockCountWithUnit,
fromIntervalPattern,
fromSupplyPattern,
} = ctx;
const {
blocks,
@@ -46,22 +47,33 @@ export function createChainSection(ctx) {
name: "Dominance",
title: `Mining Dominance of ${poolName}`,
bottom: [
s({
line({
metric: pool._24hDominance,
name: "24h",
color: colors.orange,
unit: Unit.percentage,
defaultActive: false,
}),
line({
metric: pool._1wDominance,
name: "1w",
color: colors.red,
unit: Unit.percentage,
defaultActive: false,
}),
s({ metric: pool._1mDominance, name: "1m", unit: Unit.percentage }),
s({
line({
metric: pool._1mDominance,
name: "1m",
unit: Unit.percentage,
}),
line({
metric: pool._1yDominance,
name: "1y",
color: colors.lime,
unit: Unit.percentage,
defaultActive: false,
}),
s({
line({
metric: pool.dominance,
name: "all time",
color: colors.teal,
@@ -74,32 +86,32 @@ export function createChainSection(ctx) {
name: "Blocks mined",
title: `Blocks mined by ${poolName}`,
bottom: [
s({
line({
metric: pool.blocksMined.sum,
name: "Sum",
unit: Unit.count,
}),
s({
line({
metric: pool.blocksMined.cumulative,
name: "Cumulative",
color: colors.blue,
unit: Unit.count,
}),
s({
line({
metric: pool._1wBlocksMined,
name: "1w Sum",
color: colors.red,
unit: Unit.count,
defaultActive: false,
}),
s({
line({
metric: pool._1mBlocksMined,
name: "1m Sum",
color: colors.pink,
unit: Unit.count,
defaultActive: false,
}),
s({
line({
metric: pool._1yBlocksMined,
name: "1y Sum",
color: colors.purple,
@@ -112,8 +124,18 @@ export function createChainSection(ctx) {
name: "Rewards",
title: `Rewards collected by ${poolName}`,
bottom: [
...fromValuePattern(pool.coinbase, "coinbase", colors.orange, colors.red),
...fromValuePattern(pool.subsidy, "subsidy", colors.lime, colors.emerald),
...fromValuePattern(
pool.coinbase,
"coinbase",
colors.orange,
colors.red,
),
...fromValuePattern(
pool.subsidy,
"subsidy",
colors.lime,
colors.emerald,
),
...fromValuePattern(pool.fee, "fee", colors.cyan, colors.indigo),
],
},
@@ -121,7 +143,7 @@ export function createChainSection(ctx) {
name: "Days since block",
title: `Days since ${poolName} mined a block`,
bottom: [
s({
line({
metric: pool.daysSinceBlock,
name: "Since block",
unit: Unit.days,
@@ -143,29 +165,33 @@ export function createChainSection(ctx) {
name: "Count",
title: "Block Count",
bottom: [
...fromBlockCountWithUnit(blocks.count.blockCount, "Block", Unit.count),
s({
...fromBlockCountWithUnit(
blocks.count.blockCount,
"Block",
Unit.count,
),
line({
metric: blocks.count.blockCountTarget,
name: "Target",
color: colors.gray,
unit: Unit.count,
options: { lineStyle: 4 },
}),
s({
line({
metric: blocks.count._1wBlockCount,
name: "1w sum",
color: colors.red,
unit: Unit.count,
defaultActive: false,
}),
s({
line({
metric: blocks.count._1mBlockCount,
name: "1m sum",
color: colors.pink,
unit: Unit.count,
defaultActive: false,
}),
s({
line({
metric: blocks.count._1yBlockCount,
name: "1y sum",
color: colors.purple,
@@ -211,36 +237,36 @@ export function createChainSection(ctx) {
name: "Volume",
title: "Transaction Volume",
bottom: [
s({
line({
metric: transactions.volume.sentSum.sats,
name: "Sent",
unit: Unit.sats,
}),
s({
line({
metric: transactions.volume.sentSum.bitcoin,
name: "Sent",
unit: Unit.btc,
}),
s({
line({
metric: transactions.volume.sentSum.dollars,
name: "Sent",
unit: Unit.usd,
}),
s({
line({
metric: transactions.volume.annualizedVolume.sats,
name: "annualized",
color: colors.red,
unit: Unit.sats,
defaultActive: false,
}),
s({
line({
metric: transactions.volume.annualizedVolume.bitcoin,
name: "annualized",
color: colors.red,
unit: Unit.btc,
defaultActive: false,
}),
s({
line({
metric: transactions.volume.annualizedVolume.dollars,
name: "annualized",
color: colors.lime,
@@ -253,7 +279,11 @@ export function createChainSection(ctx) {
name: "Size",
title: "Transaction Size",
bottom: [
...fromFeeRatePattern(transactions.size.weight, "weight", Unit.wu),
...fromFeeRatePattern(
transactions.size.weight,
"weight",
Unit.wu,
),
...fromFeeRatePattern(transactions.size.vsize, "vsize", Unit.vb),
],
},
@@ -261,21 +291,39 @@ export function createChainSection(ctx) {
name: "Versions",
title: "Transaction Versions",
bottom: [
...fromBlockCountWithUnit(transactions.versions.v1, "v1", Unit.count, colors.orange, colors.red),
...fromBlockCountWithUnit(transactions.versions.v2, "v2", Unit.count, colors.cyan, colors.blue),
...fromBlockCountWithUnit(transactions.versions.v3, "v3", Unit.count, colors.lime, colors.green),
...fromBlockCountWithUnit(
transactions.versions.v1,
"v1",
Unit.count,
colors.orange,
colors.red,
),
...fromBlockCountWithUnit(
transactions.versions.v2,
"v2",
Unit.count,
colors.cyan,
colors.blue,
),
...fromBlockCountWithUnit(
transactions.versions.v3,
"v3",
Unit.count,
colors.lime,
colors.green,
),
],
},
{
name: "Velocity",
title: "Transactions Velocity",
bottom: [
s({
line({
metric: supply.velocity.btc,
name: "bitcoin",
unit: Unit.ratio,
}),
s({
line({
metric: supply.velocity.usd,
name: "dollars",
color: colors.emerald,
@@ -287,7 +335,7 @@ export function createChainSection(ctx) {
name: "Speed",
title: "Transactions Per Second",
bottom: [
s({
line({
metric: transactions.volume.txPerSec,
name: "Transactions",
unit: Unit.perSec,
@@ -310,7 +358,7 @@ export function createChainSection(ctx) {
name: "Speed",
title: "Inputs Per Second",
bottom: [
s({
line({
metric: transactions.volume.inputsPerSec,
name: "Inputs",
unit: Unit.perSec,
@@ -339,7 +387,7 @@ export function createChainSection(ctx) {
name: "Speed",
title: "Outputs Per Second",
bottom: [
s({
line({
metric: transactions.volume.outputsPerSec,
name: "Outputs",
unit: Unit.perSec,
@@ -355,7 +403,13 @@ export function createChainSection(ctx) {
{
name: "Count",
title: "UTXO Count",
bottom: fromFullnessPattern(outputs.count.utxoCount, "Count", Unit.count),
bottom: [
line({
metric: outputs.count.utxoCount,
name: "Count",
unit: Unit.count,
}),
],
},
],
},
@@ -373,7 +427,7 @@ export function createChainSection(ctx) {
title: "Block Subsidy",
bottom: [
...fromCoinbasePattern(blocks.rewards.subsidy, "Subsidy"),
s({
line({
metric: blocks.rewards.subsidyDominance,
name: "Dominance",
color: colors.purple,
@@ -391,43 +445,43 @@ export function createChainSection(ctx) {
name: "Total",
title: "Transaction Fees",
bottom: [
s({
line({
metric: transactions.fees.fee.sats.sum,
name: "Sum",
unit: Unit.sats,
}),
s({
line({
metric: transactions.fees.fee.sats.cumulative,
name: "Cumulative",
color: colors.blue,
unit: Unit.sats,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.fee.bitcoin.sum,
name: "Sum",
unit: Unit.btc,
}),
s({
line({
metric: transactions.fees.fee.bitcoin.cumulative,
name: "Cumulative",
color: colors.blue,
unit: Unit.btc,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.fee.dollars.sum,
name: "Sum",
unit: Unit.usd,
}),
s({
line({
metric: transactions.fees.fee.dollars.cumulative,
name: "Cumulative",
color: colors.blue,
unit: Unit.usd,
defaultActive: false,
}),
s({
line({
metric: blocks.rewards.feeDominance,
name: "Dominance",
color: colors.purple,
@@ -440,55 +494,55 @@ export function createChainSection(ctx) {
name: "Rate",
title: "Fee Rate",
bottom: [
s({
line({
metric: transactions.fees.feeRate.median,
name: "Median",
color: colors.purple,
unit: Unit.feeRate,
}),
s({
line({
metric: transactions.fees.feeRate.average,
name: "Average",
color: colors.blue,
unit: Unit.feeRate,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.feeRate.min,
name: "Min",
color: colors.red,
unit: Unit.feeRate,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.feeRate.max,
name: "Max",
color: colors.green,
unit: Unit.feeRate,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.feeRate.pct10,
name: "pct10",
color: colors.rose,
unit: Unit.feeRate,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.feeRate.pct25,
name: "pct25",
color: colors.pink,
unit: Unit.feeRate,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.feeRate.pct75,
name: "pct75",
color: colors.violet,
unit: Unit.feeRate,
defaultActive: false,
}),
s({
line({
metric: transactions.fees.feeRate.pct90,
name: "pct90",
color: colors.fuchsia,
@@ -508,33 +562,33 @@ export function createChainSection(ctx) {
name: "Hashrate",
title: "Network Hashrate",
bottom: [
s({
line({
metric: blocks.mining.hashRate,
name: "Hashrate",
unit: Unit.hashRate,
}),
s({
line({
metric: blocks.mining.hashRate1wSma,
name: "1w SMA",
color: colors.red,
unit: Unit.hashRate,
defaultActive: false,
}),
s({
line({
metric: blocks.mining.hashRate1mSma,
name: "1m SMA",
color: colors.orange,
unit: Unit.hashRate,
defaultActive: false,
}),
s({
line({
metric: blocks.mining.hashRate2mSma,
name: "2m SMA",
color: colors.yellow,
unit: Unit.hashRate,
defaultActive: false,
}),
s({
line({
metric: blocks.mining.hashRate1ySma,
name: "1y SMA",
color: colors.lime,
@@ -547,19 +601,19 @@ export function createChainSection(ctx) {
name: "Difficulty",
title: "Network Difficulty",
bottom: [
s({
line({
metric: blocks.difficulty.raw,
name: "Difficulty",
unit: Unit.difficulty,
}),
s({
line({
metric: blocks.difficulty.adjustment,
name: "Adjustment",
color: colors.orange,
unit: Unit.percentage,
defaultActive: false,
}),
s({
line({
metric: blocks.difficulty.asHash,
name: "As hash",
color: colors.default,
@@ -567,14 +621,14 @@ export function createChainSection(ctx) {
defaultActive: false,
options: { lineStyle: 1 },
}),
s({
line({
metric: blocks.difficulty.blocksBeforeNextAdjustment,
name: "Blocks until adj.",
color: colors.indigo,
unit: Unit.blocks,
defaultActive: false,
}),
s({
line({
metric: blocks.difficulty.daysBeforeNextAdjustment,
name: "Days until adj.",
color: colors.purple,
@@ -587,32 +641,32 @@ export function createChainSection(ctx) {
name: "Hash Price",
title: "Hash Price",
bottom: [
s({
line({
metric: blocks.mining.hashPriceThs,
name: "TH/s",
color: colors.emerald,
unit: Unit.usdPerThsPerDay,
}),
s({
line({
metric: blocks.mining.hashPricePhs,
name: "PH/s",
color: colors.emerald,
unit: Unit.usdPerPhsPerDay,
}),
s({
line({
metric: blocks.mining.hashPriceRebound,
name: "Rebound",
color: colors.yellow,
unit: Unit.percentage,
}),
s({
line({
metric: blocks.mining.hashPriceThsMin,
name: "TH/s Min",
color: colors.red,
unit: Unit.usdPerThsPerDay,
options: { lineStyle: 1 },
}),
s({
line({
metric: blocks.mining.hashPricePhsMin,
name: "PH/s Min",
color: colors.red,
@@ -625,32 +679,32 @@ export function createChainSection(ctx) {
name: "Hash Value",
title: "Hash Value",
bottom: [
s({
line({
metric: blocks.mining.hashValueThs,
name: "TH/s",
color: colors.orange,
unit: Unit.satsPerThsPerDay,
}),
s({
line({
metric: blocks.mining.hashValuePhs,
name: "PH/s",
color: colors.orange,
unit: Unit.satsPerPhsPerDay,
}),
s({
line({
metric: blocks.mining.hashValueRebound,
name: "Rebound",
color: colors.yellow,
unit: Unit.percentage,
}),
s({
line({
metric: blocks.mining.hashValueThsMin,
name: "TH/s Min",
color: colors.red,
unit: Unit.satsPerThsPerDay,
options: { lineStyle: 1 },
}),
s({
line({
metric: blocks.mining.hashValuePhsMin,
name: "PH/s Min",
color: colors.red,
@@ -663,18 +717,18 @@ export function createChainSection(ctx) {
name: "Halving",
title: "Halving Info",
bottom: [
s({
line({
metric: blocks.halving.blocksBeforeNextHalving,
name: "Blocks until halving",
unit: Unit.blocks,
}),
s({
line({
metric: blocks.halving.daysBeforeNextHalving,
name: "Days until halving",
color: colors.orange,
unit: Unit.days,
}),
s({
line({
metric: blocks.halving.epoch,
name: "Halving epoch",
color: colors.purple,
@@ -687,7 +741,7 @@ export function createChainSection(ctx) {
name: "Puell Multiple",
title: "Puell Multiple",
bottom: [
s({
line({
metric: market.indicators.puellMultiple,
name: "Puell Multiple",
unit: Unit.ratio,
@@ -708,6 +762,11 @@ export function createChainSection(ctx) {
{
name: "Unspendable",
tree: [
{
name: "Supply",
title: "Unspendable Supply",
bottom: fromValuePattern(supply.burned.unspendable, "Supply"),
},
{
name: "OP_RETURN",
tree: [
@@ -720,23 +779,42 @@ export function createChainSection(ctx) {
Unit.count,
),
},
{
name: "Supply",
title: "OP_RETURN Supply",
bottom: fromValuePattern(supply.burned.opreturn, "Supply"),
},
],
},
],
},
// Supply
{
name: "Supply",
title: "Circulating Supply",
bottom: fromSupplyPattern(supply.circulating, "Supply"),
},
// Inflation
{
name: "Inflation",
title: "Inflation Rate",
bottom: [
s({
line({
metric: supply.inflation,
name: "Rate",
unit: Unit.percentage,
}),
],
},
// Unclaimed Rewards
{
name: "Unclaimed Rewards",
title: "Unclaimed Block Rewards",
bottom: fromValuePattern(blocks.rewards.unclaimedRewards, "Unclaimed"),
},
],
};
}
@@ -135,7 +135,7 @@ export function createAddressCohortFolder(ctx, args) {
* @returns {PartialOptionsTree}
*/
function createRealizedPriceOptions(ctx, args, title) {
const { s } = ctx;
const { line } = ctx;
const { tree, color } = args;
return [
@@ -143,7 +143,7 @@ function createRealizedPriceOptions(ctx, args, title) {
name: "price",
title: `Realized Price ${title}`,
top: [
s({
line({
metric: tree.realized.realizedPrice,
name: "Realized",
color,
@@ -163,11 +163,11 @@ function createRealizedPriceOptions(ctx, args, title) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
function createRealizedCapWithExtras(ctx, list, args, useGroupName) {
const { s, createPriceLine } = ctx;
const { line, baseline, createPriceLine } = ctx;
const isSingle = !("list" in args);
return list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.realized.realizedCap,
name: useGroupName ? name : "Capitalization",
color,
@@ -175,10 +175,9 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName) {
}),
...(isSingle
? [
/** @type {AnyFetchedSeriesBlueprint} */ ({
type: "Baseline",
baseline({
metric: tree.realized.realizedCap30dDelta,
title: "30d Change",
name: "30d Change",
unit: Unit.usd,
defaultActive: false,
}),
@@ -197,7 +196,7 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName) {
* @returns {PartialOptionsTree}
*/
function createRealizedPnlSection(ctx, args, title) {
const { colors, s } = ctx;
const { colors, line } = ctx;
const { realized } = args.tree;
return [
@@ -205,13 +204,13 @@ function createRealizedPnlSection(ctx, args, title) {
name: "pnl",
title: `Realized Profit And Loss ${title}`,
bottom: [
s({
line({
metric: realized.realizedProfit.sum,
name: "Profit",
color: colors.green,
unit: Unit.usd,
}),
s({
line({
metric: realized.realizedLoss.sum,
name: "Loss",
color: colors.red,
@@ -219,20 +218,20 @@ function createRealizedPnlSection(ctx, args, title) {
defaultActive: false,
}),
// RealizedPattern (address cohorts) doesn't have realizedProfitToLossRatio
s({
line({
metric: realized.totalRealizedPnl,
name: "Total",
color: colors.default,
defaultActive: false,
unit: Unit.usd,
}),
s({
line({
metric: realized.negRealizedLoss.sum,
name: "Negative Loss",
color: colors.red,
unit: Unit.usd,
}),
s({
line({
metric: realized.negRealizedLoss.cumulative,
name: "Negative Loss",
color: colors.red,
@@ -252,7 +251,7 @@ function createRealizedPnlSection(ctx, args, title) {
* @returns {PartialOptionsTree}
*/
function createUnrealizedSection(ctx, list, useGroupName, title) {
const { colors, s } = ctx;
const { colors, line, baseline } = ctx;
return [
{
@@ -262,12 +261,10 @@ function createUnrealizedSection(ctx, list, useGroupName, title) {
name: "nupl",
title: `Net Unrealized Profit/Loss ${title}`,
bottom: list.flatMap(({ color, name, tree }) => [
/** @type {AnyFetchedSeriesBlueprint} */ ({
type: "Baseline",
baseline({
metric: tree.unrealized.netUnrealizedPnl,
title: useGroupName ? name : "NUPL",
color: useGroupName ? color : undefined,
colors: useGroupName ? undefined : [colors.red, colors.green],
name: useGroupName ? name : "NUPL",
color: useGroupName ? color : [colors.red, colors.green],
unit: Unit.ratio,
options: { baseValue: { price: 0 } },
}),
@@ -277,7 +274,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) {
name: "profit",
title: `Unrealized Profit ${title}`,
bottom: list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.unrealized.unrealizedProfit,
name: useGroupName ? name : "Profit",
color,
@@ -289,7 +286,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) {
name: "loss",
title: `Unrealized Loss ${title}`,
bottom: list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.unrealized.unrealizedLoss,
name: useGroupName ? name : "Loss",
color,
@@ -311,7 +308,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) {
* @returns {PartialOptionsTree}
*/
function createCostBasisSection(ctx, list, useGroupName, title) {
const { s } = ctx;
const { line } = ctx;
return [
{
@@ -321,7 +318,7 @@ function createCostBasisSection(ctx, list, useGroupName, title) {
name: "min",
title: `Min Cost Basis ${title}`,
top: list.map(({ color, name, tree }) =>
s({
line({
metric: tree.costBasis.min,
name: useGroupName ? name : "Min",
color,
@@ -333,7 +330,7 @@ function createCostBasisSection(ctx, list, useGroupName, title) {
name: "max",
title: `Max Cost Basis ${title}`,
top: list.map(({ color, name, tree }) =>
s({
line({
metric: tree.costBasis.max,
name: useGroupName ? name : "Max",
color,
@@ -355,7 +352,7 @@ function createCostBasisSection(ctx, list, useGroupName, title) {
* @returns {PartialOptionsTree}
*/
function createActivitySection(ctx, list, useGroupName, title) {
const { s } = ctx;
const { line } = ctx;
return [
{
@@ -365,13 +362,13 @@ function createActivitySection(ctx, list, useGroupName, title) {
name: "coinblocks destroyed",
title: `Coinblocks Destroyed ${title}`,
bottom: list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.activity.coinblocksDestroyed.sum,
name: useGroupName ? name : "Coinblocks",
color,
unit: Unit.coinblocks,
}),
s({
line({
metric: tree.activity.coinblocksDestroyed.cumulative,
name: useGroupName ? name : "Coinblocks",
color,
@@ -383,13 +380,13 @@ function createActivitySection(ctx, list, useGroupName, title) {
name: "coindays destroyed",
title: `Coindays Destroyed ${title}`,
bottom: list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.activity.coindaysDestroyed.sum,
name: useGroupName ? name : "Coindays",
color,
unit: Unit.coindays,
}),
s({
line({
metric: tree.activity.coindaysDestroyed.cumulative,
name: useGroupName ? name : "Coindays",
color,
@@ -42,8 +42,8 @@ export function buildCohortData(colors, brk) {
SPENDABLE_TYPE_NAMES,
} = brk;
// Base cohort representing "all"
/** @type {UtxoCohortObject} */
// Base cohort representing "all" - CohortAll (adjustedSopr + percentiles but no RelToMarketCap)
/** @type {CohortAll} */
const cohortAll = {
name: "",
title: "",
@@ -51,28 +51,27 @@ export function buildCohortData(colors, brk) {
tree: utxoCohorts.all,
};
/** @type {UtxoCohortObject} */
const cohortAllForComparison = {
name: "all",
title: "",
color: colors.default,
tree: utxoCohorts.all,
// Term cohorts - split because short is CohortFull, long is CohortWithPercentiles
const shortNames = TERM_NAMES.short;
/** @type {CohortFull} */
const termShort = {
name: shortNames.short,
title: shortNames.long,
color: colors[termColors.short],
tree: utxoCohorts.term.short,
};
// Term cohorts (short/long term holders)
/** @type {readonly UtxoCohortObject[]} */
const terms = entries(utxoCohorts.term).map(([key, tree]) => {
const names = TERM_NAMES[key];
return {
name: names.short,
title: names.long,
color: colors[termColors[key]],
tree,
};
});
const longNames = TERM_NAMES.long;
/** @type {CohortWithPercentiles} */
const termLong = {
name: longNames.short,
title: longNames.long,
color: colors[termColors.long],
tree: utxoCohorts.term.long,
};
// Max age cohorts (up to X time)
/** @type {readonly UtxoCohortObject[]} */
// Max age cohorts (up to X time) - CohortWithAdjusted (adjustedSopr only)
/** @type {readonly CohortWithAdjusted[]} */
const upToDate = entries(utxoCohorts.maxAge).map(([key, tree]) => {
const names = MAX_AGE_NAMES[key];
return {
@@ -83,8 +82,8 @@ export function buildCohortData(colors, brk) {
};
});
// Min age cohorts (from X time)
/** @type {readonly UtxoCohortObject[]} */
// Min age cohorts (from X time) - CohortBasic (neither adjustedSopr nor percentiles)
/** @type {readonly CohortBasic[]} */
const fromDate = entries(utxoCohorts.minAge).map(([key, tree]) => {
const names = MIN_AGE_NAMES[key];
return {
@@ -95,8 +94,8 @@ export function buildCohortData(colors, brk) {
};
});
// Age range cohorts
/** @type {readonly UtxoCohortObject[]} */
// Age range cohorts - CohortWithPercentiles (percentiles only)
/** @type {readonly CohortWithPercentiles[]} */
const dateRange = entries(utxoCohorts.ageRange).map(([key, tree]) => {
const names = AGE_RANGE_NAMES[key];
return {
@@ -107,8 +106,8 @@ export function buildCohortData(colors, brk) {
};
});
// Epoch cohorts
/** @type {readonly UtxoCohortObject[]} */
// Epoch cohorts - CohortBasic (neither adjustedSopr nor percentiles)
/** @type {readonly CohortBasic[]} */
const epoch = entries(utxoCohorts.epoch).map(([key, tree]) => {
const names = EPOCH_NAMES[key];
return {
@@ -119,8 +118,8 @@ export function buildCohortData(colors, brk) {
};
});
// UTXOs above amount
/** @type {readonly UtxoCohortObject[]} */
// UTXOs above amount - CohortBasic (neither adjustedSopr nor percentiles)
/** @type {readonly CohortBasic[]} */
const utxosAboveAmount = entries(utxoCohorts.geAmount).map(([key, tree]) => {
const names = GE_AMOUNT_NAMES[key];
return {
@@ -145,8 +144,8 @@ export function buildCohortData(colors, brk) {
},
);
// UTXOs under amount
/** @type {readonly UtxoCohortObject[]} */
// UTXOs under amount - CohortBasic (neither adjustedSopr nor percentiles)
/** @type {readonly CohortBasic[]} */
const utxosUnderAmount = entries(utxoCohorts.ltAmount).map(([key, tree]) => {
const names = LT_AMOUNT_NAMES[key];
return {
@@ -171,8 +170,8 @@ export function buildCohortData(colors, brk) {
},
);
// UTXOs amount ranges
/** @type {readonly UtxoCohortObject[]} */
// UTXOs amount ranges - CohortBasic (neither adjustedSopr nor percentiles)
/** @type {readonly CohortBasic[]} */
const utxosAmountRanges = entries(utxoCohorts.amountRange).map(
([key, tree]) => {
const names = AMOUNT_RANGE_NAMES[key];
@@ -199,8 +198,8 @@ export function buildCohortData(colors, brk) {
},
);
// Spendable type cohorts
/** @type {readonly UtxoCohortObject[]} */
// Spendable type cohorts - CohortBasic (neither adjustedSopr nor percentiles)
/** @type {readonly CohortBasic[]} */
const type = entries(utxoCohorts.type).map(([key, tree]) => {
const names = SPENDABLE_TYPE_NAMES[key];
return {
@@ -213,8 +212,8 @@ export function buildCohortData(colors, brk) {
return {
cohortAll,
cohortAllForComparison,
terms,
termShort,
termLong,
upToDate,
fromDate,
dateRange,
@@ -6,7 +6,13 @@
export { buildCohortData } from "./data.js";
// Cohort folder builders (type-safe!)
export { createUtxoCohortFolder, createAgeCohortFolder, createAmountCohortFolder } from "./utxo.js";
export {
createCohortFolderAll,
createCohortFolderFull,
createCohortFolderWithAdjusted,
createCohortFolderWithPercentiles,
createCohortFolderBasic,
} from "./utxo.js";
export { createAddressCohortFolder } from "./address.js";
// Shared helpers
@@ -9,23 +9,23 @@ import { Unit } from "../../utils/units.js";
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createSingleSupplySeries(ctx, cohort) {
const { colors, s, createPriceLine } = ctx;
const { colors, line, createPriceLine } = ctx;
const { tree } = cohort;
return [
s({
line({
metric: tree.supply.total.sats,
name: "Supply",
color: colors.default,
unit: Unit.sats,
}),
s({
line({
metric: tree.supply.total.bitcoin,
name: "Supply",
color: colors.default,
unit: Unit.btc,
}),
s({
line({
metric: tree.supply.total.dollars,
name: "Supply",
color: colors.default,
@@ -33,7 +33,7 @@ export function createSingleSupplySeries(ctx, cohort) {
}),
...("supplyRelToCirculatingSupply" in tree.relative
? [
s({
line({
metric: tree.relative.supplyRelToCirculatingSupply,
name: "Supply",
color: colors.default,
@@ -41,57 +41,57 @@ export function createSingleSupplySeries(ctx, cohort) {
}),
]
: []),
s({
line({
metric: tree.unrealized.supplyInProfit.sats,
name: "In Profit",
color: colors.green,
unit: Unit.sats,
}),
s({
line({
metric: tree.unrealized.supplyInProfit.bitcoin,
name: "In Profit",
color: colors.green,
unit: Unit.btc,
}),
s({
line({
metric: tree.unrealized.supplyInProfit.dollars,
name: "In Profit",
color: colors.green,
unit: Unit.usd,
}),
s({
line({
metric: tree.unrealized.supplyInLoss.sats,
name: "In Loss",
color: colors.red,
unit: Unit.sats,
}),
s({
line({
metric: tree.unrealized.supplyInLoss.bitcoin,
name: "In Loss",
color: colors.red,
unit: Unit.btc,
}),
s({
line({
metric: tree.unrealized.supplyInLoss.dollars,
name: "In Loss",
color: colors.red,
unit: Unit.usd,
}),
s({
line({
metric: tree.supply.halved.sats,
name: "half",
color: colors.gray,
unit: Unit.sats,
options: { lineStyle: 4 },
}),
s({
line({
metric: tree.supply.halved.bitcoin,
name: "half",
color: colors.gray,
unit: Unit.btc,
options: { lineStyle: 4 },
}),
s({
line({
metric: tree.supply.halved.dollars,
name: "half",
color: colors.gray,
@@ -100,13 +100,13 @@ export function createSingleSupplySeries(ctx, cohort) {
}),
...("supplyInProfitRelToCirculatingSupply" in tree.relative
? [
s({
line({
metric: tree.relative.supplyInProfitRelToCirculatingSupply,
name: "In Profit",
color: colors.green,
unit: Unit.pctSupply,
}),
s({
line({
metric: tree.relative.supplyInLossRelToCirculatingSupply,
name: "In Loss",
color: colors.red,
@@ -114,13 +114,13 @@ export function createSingleSupplySeries(ctx, cohort) {
}),
]
: []),
s({
line({
metric: tree.relative.supplyInProfitRelToOwnSupply,
name: "In Profit",
color: colors.green,
unit: Unit.pctOwn,
}),
s({
line({
metric: tree.relative.supplyInLossRelToOwnSupply,
name: "In Loss",
color: colors.red,
@@ -143,21 +143,21 @@ export function createSingleSupplySeries(ctx, cohort) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createGroupedSupplyTotalSeries(ctx, list) {
const { s, brk } = ctx;
const { line, brk } = ctx;
const constant100 = brk.tree.constants.constant100;
return list.flatMap(({ color, name, tree }) => [
s({ metric: tree.supply.total.sats, name, color, unit: Unit.sats }),
s({ metric: tree.supply.total.bitcoin, name, color, unit: Unit.btc }),
s({ metric: tree.supply.total.dollars, name, color, unit: Unit.usd }),
line({ metric: tree.supply.total.sats, name, color, unit: Unit.sats }),
line({ metric: tree.supply.total.bitcoin, name, color, unit: Unit.btc }),
line({ metric: tree.supply.total.dollars, name, color, unit: Unit.usd }),
"supplyRelToCirculatingSupply" in tree.relative
? s({
? line({
metric: tree.relative.supplyRelToCirculatingSupply,
name,
color,
unit: Unit.pctSupply,
})
: s({ metric: constant100, name, color, unit: Unit.pctSupply }),
: line({ metric: constant100, name, color, unit: Unit.pctSupply }),
]);
}
@@ -168,22 +168,22 @@ export function createGroupedSupplyTotalSeries(ctx, list) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createGroupedSupplyInProfitSeries(ctx, list) {
const { s } = ctx;
const { line } = ctx;
return list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.unrealized.supplyInProfit.sats,
name,
color,
unit: Unit.sats,
}),
s({
line({
metric: tree.unrealized.supplyInProfit.bitcoin,
name,
color,
unit: Unit.btc,
}),
s({
line({
metric: tree.unrealized.supplyInProfit.dollars,
name,
color,
@@ -191,7 +191,7 @@ export function createGroupedSupplyInProfitSeries(ctx, list) {
}),
...("supplyInProfitRelToCirculatingSupply" in tree.relative
? [
s({
line({
metric: tree.relative.supplyInProfitRelToCirculatingSupply,
name,
color,
@@ -209,22 +209,22 @@ export function createGroupedSupplyInProfitSeries(ctx, list) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createGroupedSupplyInLossSeries(ctx, list) {
const { s } = ctx;
const { line } = ctx;
return list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.unrealized.supplyInLoss.sats,
name,
color,
unit: Unit.sats,
}),
s({
line({
metric: tree.unrealized.supplyInLoss.bitcoin,
name,
color,
unit: Unit.btc,
}),
s({
line({
metric: tree.unrealized.supplyInLoss.dollars,
name,
color,
@@ -232,7 +232,7 @@ export function createGroupedSupplyInLossSeries(ctx, list) {
}),
...("supplyInLossRelToCirculatingSupply" in tree.relative
? [
s({
line({
metric: tree.relative.supplyInLossRelToCirculatingSupply,
name,
color,
@@ -251,10 +251,10 @@ export function createGroupedSupplyInLossSeries(ctx, list) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createUtxoCountSeries(ctx, list, useGroupName) {
const { s } = ctx;
const { line } = ctx;
return list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.outputs.utxoCount,
name: useGroupName ? name : "Count",
color,
@@ -271,10 +271,10 @@ export function createUtxoCountSeries(ctx, list, useGroupName) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createAddressCountSeries(ctx, list, useGroupName) {
const { s, colors } = ctx;
const { line, colors } = ctx;
return list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.addrCount,
name: useGroupName ? name : "Count",
color: useGroupName ? color : colors.orange,
@@ -290,10 +290,10 @@ export function createAddressCountSeries(ctx, list, useGroupName) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createRealizedPriceSeries(ctx, list) {
const { s } = ctx;
const { line } = ctx;
return list.map(({ color, name, tree }) =>
s({ metric: tree.realized.realizedPrice, name, color, unit: Unit.usd }),
line({ metric: tree.realized.realizedPrice, name, color, unit: Unit.usd }),
);
}
@@ -304,11 +304,11 @@ export function createRealizedPriceSeries(ctx, list) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createRealizedPriceRatioSeries(ctx, list) {
const { s, createPriceLine } = ctx;
const { line, createPriceLine } = ctx;
return [
...list.map(({ color, name, tree }) =>
s({
line({
metric: tree.realized.realizedPriceExtra.ratio,
name,
color,
@@ -327,10 +327,10 @@ export function createRealizedPriceRatioSeries(ctx, list) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createRealizedCapSeries(ctx, list, useGroupName) {
const { s } = ctx;
const { line } = ctx;
return list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.realized.realizedCap,
name: useGroupName ? name : "Capitalization",
color,
@@ -347,16 +347,16 @@ export function createRealizedCapSeries(ctx, list, useGroupName) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createCostBasisMinMaxSeries(ctx, list, useGroupName) {
const { s } = ctx;
const { line } = ctx;
return list.flatMap(({ color, name, tree }) => [
s({
line({
metric: tree.costBasis.min,
name: useGroupName ? `${name} min` : "Min",
color,
unit: Unit.usd,
}),
s({
line({
metric: tree.costBasis.max,
name: useGroupName ? `${name} max` : "Max",
color,
@@ -373,39 +373,39 @@ export function createCostBasisMinMaxSeries(ctx, list, useGroupName) {
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function createCostBasisPercentilesSeries(ctx, list, useGroupName) {
const { s } = ctx;
const { line } = ctx;
return list.flatMap(({ color, name, tree }) => {
const percentiles = tree.costBasis.percentiles;
return [
s({
line({
metric: percentiles.costBasisPct10,
name: useGroupName ? `${name} p10` : "p10",
color,
unit: Unit.usd,
defaultActive: false,
}),
s({
line({
metric: percentiles.costBasisPct25,
name: useGroupName ? `${name} p25` : "p25",
color,
unit: Unit.usd,
defaultActive: false,
}),
s({
line({
metric: percentiles.costBasisPct50,
name: useGroupName ? `${name} p50` : "p50",
color,
unit: Unit.usd,
}),
s({
line({
metric: percentiles.costBasisPct75,
name: useGroupName ? `${name} p75` : "p75",
color,
unit: Unit.usd,
defaultActive: false,
}),
s({
line({
metric: percentiles.costBasisPct90,
name: useGroupName ? `${name} p90` : "p90",
color,
@@ -1,6 +0,0 @@
/**
* Cohort-related type definitions
* Types are defined in ../types.js, this file exists for documentation
*/
export {};
File diff suppressed because it is too large Load Diff
+48 -43
View File
@@ -17,7 +17,7 @@ function createCointimePriceWithRatioOptions(
ctx,
{ title, legend, price, ratio, color },
) {
const { s, colors, createPriceLine } = ctx;
const { line, colors, createPriceLine } = ctx;
// Percentile USD mappings
const percentileUsdMap = [
@@ -68,15 +68,15 @@ function createCointimePriceWithRatioOptions(
{
name: "price",
title,
top: [s({ metric: price, name: legend, color, unit: Unit.usd })],
top: [line({ metric: price, name: legend, color, unit: Unit.usd })],
},
{
name: "Ratio",
title: `${title} Ratio`,
top: [
s({ metric: price, name: legend, color, unit: Unit.usd }),
line({ metric: price, name: legend, color, unit: Unit.usd }),
...percentileUsdMap.map(({ name: pctName, prop, color: pctColor }) =>
s({
line({
metric: prop,
name: pctName,
color: pctColor,
@@ -87,45 +87,45 @@ function createCointimePriceWithRatioOptions(
),
],
bottom: [
s({ metric: ratio.ratio, name: "Ratio", color, unit: Unit.ratio }),
s({
line({ metric: ratio.ratio, name: "Ratio", color, unit: Unit.ratio }),
line({
metric: ratio.ratio1wSma,
name: "1w SMA",
color: colors.lime,
unit: Unit.ratio,
}),
s({
line({
metric: ratio.ratio1mSma,
name: "1m SMA",
color: colors.teal,
unit: Unit.ratio,
}),
s({
line({
metric: ratio.ratio1ySd.sma,
name: "1y SMA",
color: colors.sky,
unit: Unit.ratio,
}),
s({
line({
metric: ratio.ratio2ySd.sma,
name: "2y SMA",
color: colors.indigo,
unit: Unit.ratio,
}),
s({
line({
metric: ratio.ratio4ySd.sma,
name: "4y SMA",
color: colors.purple,
unit: Unit.ratio,
}),
s({
line({
metric: ratio.ratioSd.sma,
name: "All SMA",
color: colors.rose,
unit: Unit.ratio,
}),
...percentileMap.map(({ name: pctName, prop, color: pctColor }) =>
s({
line({
metric: prop,
name: pctName,
color: pctColor,
@@ -143,10 +143,15 @@ function createCointimePriceWithRatioOptions(
name: nameAddon,
title: `${title} ${titleAddon} Z-Score`,
top: getSdBands(sd).map(({ name: bandName, prop, color: bandColor }) =>
s({ metric: prop, name: bandName, color: bandColor, unit: Unit.usd }),
line({
metric: prop,
name: bandName,
color: bandColor,
unit: Unit.usd,
}),
),
bottom: [
s({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
line({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
createPriceLine({ unit: Unit.sd, number: 3 }),
createPriceLine({ unit: Unit.sd, number: 2 }),
createPriceLine({ unit: Unit.sd, number: 1 }),
@@ -166,7 +171,7 @@ function createCointimePriceWithRatioOptions(
* @returns {PartialOptionsGroup}
*/
export function createCointimeSection(ctx) {
const { colors, brk, s } = ctx;
const { colors, brk, line } = ctx;
const { cointime, distribution, supply } = brk.tree;
const { pricing, cap, activity, supply: cointimeSupply, adjusted } = cointime;
const { all } = distribution.utxoCohorts;
@@ -248,7 +253,7 @@ export function createCointimeSection(ctx) {
name: "Compare",
title: "Compare Cointime Prices",
top: cointimePrices.map(({ price, name, color }) =>
s({ metric: price, name, color, unit: Unit.usd }),
line({ metric: price, name, color, unit: Unit.usd }),
),
},
...cointimePrices.map(({ price, ratio, name, color, title }) => ({
@@ -272,20 +277,20 @@ export function createCointimeSection(ctx) {
name: "Compare",
title: "Compare Cointime Capitalizations",
bottom: [
s({
line({
metric: supply.marketCap,
name: "Market",
color: colors.default,
unit: Unit.usd,
}),
s({
line({
metric: all.realized.realizedCap,
name: "Realized",
color: colors.orange,
unit: Unit.usd,
}),
...cointimeCapitalizations.map(({ metric, name, color }) =>
s({ metric, name, color, unit: Unit.usd }),
line({ metric, name, color, unit: Unit.usd }),
),
],
},
@@ -293,14 +298,14 @@ export function createCointimeSection(ctx) {
name,
title,
bottom: [
s({ metric, name, color, unit: Unit.usd }),
s({
line({ metric, name, color, unit: Unit.usd }),
line({
metric: supply.marketCap,
name: "Market",
color: colors.default,
unit: Unit.usd,
}),
s({
line({
metric: all.realized.realizedCap,
name: "Realized",
color: colors.orange,
@@ -317,19 +322,19 @@ export function createCointimeSection(ctx) {
title: "Cointime Supply",
bottom: [
// All supply (different pattern structure)
s({
line({
metric: all.supply.total.sats,
name: "All",
color: colors.orange,
unit: Unit.sats,
}),
s({
line({
metric: all.supply.total.bitcoin,
name: "All",
color: colors.orange,
unit: Unit.btc,
}),
s({
line({
metric: all.supply.total.dollars,
name: "All",
color: colors.orange,
@@ -340,9 +345,9 @@ export function createCointimeSection(ctx) {
[cointimeSupply.vaultedSupply, "Vaulted", colors.lime],
[cointimeSupply.activeSupply, "Active", colors.rose],
]).flatMap(([supplyItem, name, color]) => [
s({ metric: supplyItem.sats, name, color, unit: Unit.sats }),
s({ metric: supplyItem.bitcoin, name, color, unit: Unit.btc }),
s({ metric: supplyItem.dollars, name, color, unit: Unit.usd }),
line({ metric: supplyItem.sats, name, color, unit: Unit.sats }),
line({ metric: supplyItem.bitcoin, name, color, unit: Unit.btc }),
line({ metric: supplyItem.dollars, name, color, unit: Unit.usd }),
]),
],
},
@@ -352,19 +357,19 @@ export function createCointimeSection(ctx) {
name: "Liveliness & Vaultedness",
title: "Liveliness & Vaultedness",
bottom: [
s({
line({
metric: activity.liveliness,
name: "Liveliness",
color: colors.rose,
unit: Unit.ratio,
}),
s({
line({
metric: activity.vaultedness,
name: "Vaultedness",
color: colors.lime,
unit: Unit.ratio,
}),
s({
line({
metric: activity.activityToVaultednessRatio,
name: "Liveliness / Vaultedness",
color: colors.purple,
@@ -379,13 +384,13 @@ export function createCointimeSection(ctx) {
title: "Coinblocks",
bottom: [
// Destroyed comes from the all cohort's activity
s({
line({
metric: all.activity.coinblocksDestroyed.sum,
name: "Destroyed",
color: colors.red,
unit: Unit.coinblocks,
}),
s({
line({
metric: all.activity.coinblocksDestroyed.cumulative,
name: "Cumulative Destroyed",
color: colors.red,
@@ -393,26 +398,26 @@ export function createCointimeSection(ctx) {
unit: Unit.coinblocks,
}),
// Created and stored from cointime
s({
line({
metric: activity.coinblocksCreated.sum,
name: "Created",
color: colors.orange,
unit: Unit.coinblocks,
}),
s({
line({
metric: activity.coinblocksCreated.cumulative,
name: "Cumulative Created",
color: colors.orange,
defaultActive: false,
unit: Unit.coinblocks,
}),
s({
line({
metric: activity.coinblocksStored.sum,
name: "Stored",
color: colors.green,
unit: Unit.coinblocks,
}),
s({
line({
metric: activity.coinblocksStored.cumulative,
name: "Cumulative Stored",
color: colors.green,
@@ -431,13 +436,13 @@ export function createCointimeSection(ctx) {
name: "Inflation",
title: "Cointime-Adjusted Inflation Rate",
bottom: [
s({
line({
metric: supply.inflation,
name: "Base",
color: colors.orange,
unit: Unit.percentage,
}),
s({
line({
metric: adjusted.cointimeAdjInflationRate,
name: "Adjusted",
color: colors.purple,
@@ -450,25 +455,25 @@ export function createCointimeSection(ctx) {
name: "Velocity",
title: "Cointime-Adjusted Transactions Velocity",
bottom: [
s({
line({
metric: supply.velocity.btc,
name: "BTC",
color: colors.orange,
unit: Unit.ratio,
}),
s({
line({
metric: adjusted.cointimeAdjTxBtcVelocity,
name: "Adj. BTC",
color: colors.red,
unit: Unit.ratio,
}),
s({
line({
metric: supply.velocity.usd,
name: "USD",
color: colors.emerald,
unit: Unit.ratio,
}),
s({
line({
metric: adjusted.cointimeAdjTxUsdVelocity,
name: "Adj. USD",
color: colors.lime,
@@ -1,5 +1,7 @@
/** Constant helpers for creating price lines and reference lines */
import { line } from "./series.js";
/**
* Get constant pattern by number dynamically from tree
* Examples: 0 → constant0, 38.2 → constant382, -1 → constantMinus1
@@ -92,7 +94,7 @@ export function createPriceLines({ constants, colors, numbers, unit }) {
* @param {boolean} [args.defaultActive]
* @returns {FetchedLineSeriesBlueprint}
*/
export function line({
export function constantLine({
colors,
constant,
name,
@@ -101,9 +103,9 @@ export function line({
lineStyle,
defaultActive,
}) {
return {
return line({
metric: constant,
title: name,
name,
unit,
defaultActive,
color: color ?? colors.gray,
@@ -112,5 +114,5 @@ export function line({
lastValueVisible: false,
crosshairMarkerVisible: false,
},
};
});
}
+35 -5
View File
@@ -1,5 +1,7 @@
import {
s,
line,
baseline,
histogram,
fromBlockCount,
fromBitcoin,
fromBlockSize,
@@ -8,10 +10,12 @@ import {
fromFeeRatePattern,
fromCoinbasePattern,
fromValuePattern,
fromBitcoinPatternWithUnit,
fromBlockCountWithUnit,
fromIntervalPattern,
fromSupplyPattern,
} from "./series.js";
import { createPriceLine, createPriceLines, line } from "./constants.js";
import { createPriceLine, createPriceLines, constantLine } from "./constants.js";
/**
* Create a context object with all dependencies for building partial options
@@ -28,7 +32,9 @@ export function createContext({ colors, brk }) {
brk,
// Series helpers
s,
line,
baseline,
histogram,
fromBlockCount: (pattern, title, color) =>
fromBlockCount(colors, pattern, title, color),
fromBitcoin: (pattern, title, color) =>
@@ -45,14 +51,38 @@ export function createContext({ colors, brk }) {
fromCoinbasePattern(colors, pattern, title),
fromValuePattern: (pattern, title, sumColor, cumulativeColor) =>
fromValuePattern(colors, pattern, title, sumColor, cumulativeColor),
fromBitcoinPatternWithUnit: (
pattern,
title,
unit,
sumColor,
cumulativeColor,
) =>
fromBitcoinPatternWithUnit(
colors,
pattern,
title,
unit,
sumColor,
cumulativeColor,
),
fromBlockCountWithUnit: (pattern, title, unit, sumColor, cumulativeColor) =>
fromBlockCountWithUnit(colors, pattern, title, unit, sumColor, cumulativeColor),
fromBlockCountWithUnit(
colors,
pattern,
title,
unit,
sumColor,
cumulativeColor,
),
fromIntervalPattern: (pattern, title, unit, color) =>
fromIntervalPattern(colors, pattern, title, unit, color),
fromSupplyPattern: (pattern, title, color) =>
fromSupplyPattern(colors, pattern, title, color),
createPriceLine: (args) => createPriceLine({ constants, colors, ...args }),
createPriceLines: (args) =>
createPriceLines({ constants, colors, ...args }),
line: (args) => line({ colors, ...args }),
constantLine: (args) => constantLine({ colors, ...args }),
};
}
@@ -44,8 +44,11 @@ export function buildAverages(colors, ma) {
* @param {Color} [args.color]
* @returns {PartialOptionsTree}
*/
export function createPriceWithRatioOptions(ctx, { title, legend, ratio, color }) {
const { s, colors, createPriceLine } = ctx;
export function createPriceWithRatioOptions(
ctx,
{ title, legend, ratio, color },
) {
const { line, colors, createPriceLine } = ctx;
const priceMetric = ratio.price;
const percentileUsdMap = [
@@ -94,27 +97,71 @@ export function createPriceWithRatioOptions(ctx, { title, legend, ratio, color }
{
name: "price",
title,
top: [s({ metric: priceMetric, name: legend, color, unit: Unit.usd })],
top: [line({ metric: priceMetric, name: legend, color, unit: Unit.usd })],
},
{
name: "Ratio",
title: `${title} Ratio`,
top: [
s({ metric: priceMetric, name: legend, color, unit: Unit.usd }),
line({ metric: priceMetric, name: legend, color, unit: Unit.usd }),
...percentileUsdMap.map(({ name: pctName, prop, color: pctColor }) =>
s({ metric: prop, name: pctName, color: pctColor, defaultActive: false, unit: Unit.usd, options: { lineStyle: 1 } }),
line({
metric: prop,
name: pctName,
color: pctColor,
defaultActive: false,
unit: Unit.usd,
options: { lineStyle: 1 },
}),
),
],
bottom: [
s({ metric: ratio.ratio, name: "Ratio", color, unit: Unit.ratio }),
s({ metric: ratio.ratio1wSma, name: "1w SMA", color: colors.lime, unit: Unit.ratio }),
s({ metric: ratio.ratio1mSma, name: "1m SMA", color: colors.teal, unit: Unit.ratio }),
s({ metric: ratio.ratio1ySd.sma, name: "1y SMA", color: colors.sky, unit: Unit.ratio }),
s({ metric: ratio.ratio2ySd.sma, name: "2y SMA", color: colors.indigo, unit: Unit.ratio }),
s({ metric: ratio.ratio4ySd.sma, name: "4y SMA", color: colors.purple, unit: Unit.ratio }),
s({ metric: ratio.ratioSd.sma, name: "All SMA", color: colors.rose, unit: Unit.ratio }),
line({ metric: ratio.ratio, name: "Ratio", color, unit: Unit.ratio }),
line({
metric: ratio.ratio1wSma,
name: "1w SMA",
color: colors.lime,
unit: Unit.ratio,
}),
line({
metric: ratio.ratio1mSma,
name: "1m SMA",
color: colors.teal,
unit: Unit.ratio,
}),
line({
metric: ratio.ratio1ySd.sma,
name: "1y SMA",
color: colors.sky,
unit: Unit.ratio,
}),
line({
metric: ratio.ratio2ySd.sma,
name: "2y SMA",
color: colors.indigo,
unit: Unit.ratio,
}),
line({
metric: ratio.ratio4ySd.sma,
name: "4y SMA",
color: colors.purple,
unit: Unit.ratio,
}),
line({
metric: ratio.ratioSd.sma,
name: "All SMA",
color: colors.rose,
unit: Unit.ratio,
}),
...percentileMap.map(({ name: pctName, prop, color: pctColor }) =>
s({ metric: prop, name: pctName, color: pctColor, defaultActive: false, unit: Unit.ratio, options: { lineStyle: 1 } }),
line({
metric: prop,
name: pctName,
color: pctColor,
defaultActive: false,
unit: Unit.ratio,
options: { lineStyle: 1 },
}),
),
createPriceLine({ unit: Unit.ratio, number: 1 }),
],
@@ -125,10 +172,15 @@ export function createPriceWithRatioOptions(ctx, { title, legend, ratio, color }
name: nameAddon,
title: `${title} ${titleAddon} Z-Score`,
top: getSdBands(sd).map(({ name: bandName, prop, color: bandColor }) =>
s({ metric: prop, name: bandName, color: bandColor, unit: Unit.usd }),
line({
metric: prop,
name: bandName,
color: bandColor,
unit: Unit.usd,
}),
),
bottom: [
s({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
line({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
createPriceLine({ unit: Unit.sd, number: 3 }),
createPriceLine({ unit: Unit.sd, number: 2 }),
createPriceLine({ unit: Unit.sd, number: 1 }),
@@ -148,7 +200,7 @@ export function createPriceWithRatioOptions(ctx, { title, legend, ratio, color }
* @param {ReturnType<typeof buildAverages>} averages
*/
export function createAveragesSection(ctx, averages) {
const { s } = ctx;
const { line } = ctx;
return {
name: "Averages",
@@ -162,7 +214,12 @@ export function createAveragesSection(ctx, averages) {
name: "Compare",
title: `Market Price ${nameAddon} Moving Averages`,
top: averages.map(({ id, color, sma, ema }) =>
s({ metric: (metricAddon === "sma" ? sma : ema).price, name: id, color, unit: Unit.usd }),
line({
metric: (metricAddon === "sma" ? sma : ema).price,
name: id,
color,
unit: Unit.usd,
}),
),
},
...averages.map(({ name, color, sma, ema }) => ({
@@ -12,7 +12,7 @@ import { createInvestingSection } from "./investing.js";
* @returns {PartialOptionsGroup}
*/
export function createMarketSection(ctx) {
const { colors, brk, s } = ctx;
const { colors, brk, line } = ctx;
const { market, supply } = brk.tree;
const {
movingAverage,
@@ -41,7 +41,7 @@ export function createMarketSection(ctx) {
name: "Capitalization",
title: "Market Capitalization",
bottom: [
s({
line({
metric: supply.marketCap,
name: "Capitalization",
unit: Unit.usd,
@@ -53,27 +53,31 @@ export function createMarketSection(ctx) {
{
name: "All Time High",
title: "All Time High",
top: [s({ metric: ath.priceAth, name: "ATH", unit: Unit.usd })],
top: [line({ metric: ath.priceAth, name: "ATH", unit: Unit.usd })],
bottom: [
s({
line({
metric: ath.priceDrawdown,
name: "Drawdown",
color: colors.red,
unit: Unit.percentage,
}),
s({ metric: ath.daysSincePriceAth, name: "Since", unit: Unit.days }),
s({
line({
metric: ath.daysSincePriceAth,
name: "Since",
unit: Unit.days,
}),
line({
metric: ath.yearsSincePriceAth,
name: "Since",
unit: Unit.years,
}),
s({
line({
metric: ath.maxDaysBetweenPriceAths,
name: "Max",
color: colors.red,
unit: Unit.days,
}),
s({
line({
metric: ath.maxYearsBetweenPriceAths,
name: "Max",
color: colors.red,
@@ -10,7 +10,7 @@ import { Unit } from "../../../utils/units.js";
* @param {Market["movingAverage"]} args.movingAverage
*/
export function createBandsSection(ctx, { range, movingAverage }) {
const { s, colors } = ctx;
const { line, colors } = ctx;
return {
name: "Bands",
@@ -46,8 +46,13 @@ export function createBandsSection(ctx, { range, movingAverage }) {
name: id,
title: `Bitcoin Price ${title} MinMax Bands`,
top: [
s({ metric: min, name: "Min", color: colors.red, unit: Unit.usd }),
s({
line({
metric: min,
name: "Min",
color: colors.red,
unit: Unit.usd,
}),
line({
metric: max,
name: "Max",
color: colors.green,
@@ -60,19 +65,19 @@ export function createBandsSection(ctx, { range, movingAverage }) {
name: "Mayer Multiple",
title: "Mayer Multiple",
top: [
s({
line({
metric: movingAverage.price200dSma.price,
name: "200d SMA",
color: colors.yellow,
unit: Unit.usd,
}),
s({
line({
metric: movingAverage.price200dSmaX24,
name: "200d SMA x2.4",
color: colors.green,
unit: Unit.usd,
}),
s({
line({
metric: movingAverage.price200dSmaX08,
name: "200d SMA x0.8",
color: colors.red,
@@ -8,7 +8,7 @@ import { Unit } from "../../../utils/units.js";
* @param {Market["indicators"]} indicators
*/
export function createMomentumSection(ctx, indicators) {
const { s, colors, createPriceLine } = ctx;
const { line, histogram, colors, createPriceLine } = ctx;
return {
name: "Momentum",
@@ -17,20 +17,20 @@ export function createMomentumSection(ctx, indicators) {
name: "RSI",
title: "Relative Strength Index (14d)",
bottom: [
s({
line({
metric: indicators.rsi14d,
name: "RSI",
color: colors.indigo,
unit: Unit.index,
}),
s({
line({
metric: indicators.rsi14dMin,
name: "Min",
color: colors.red,
defaultActive: false,
unit: Unit.index,
}),
s({
line({
metric: indicators.rsi14dMax,
name: "Max",
color: colors.green,
@@ -38,7 +38,11 @@ export function createMomentumSection(ctx, indicators) {
unit: Unit.index,
}),
createPriceLine({ unit: Unit.index, number: 70 }),
createPriceLine({ unit: Unit.index, number: 50, defaultActive: false }),
createPriceLine({
unit: Unit.index,
number: 50,
defaultActive: false,
}),
createPriceLine({ unit: Unit.index, number: 30 }),
],
},
@@ -46,19 +50,19 @@ export function createMomentumSection(ctx, indicators) {
name: "StochRSI",
title: "Stochastic RSI",
bottom: [
// s({
// line({
// metric: indicators.stochRsi,
// name: "Stoch RSI",
// color: colors.purple,
// unit: Unit.index,
// }),
s({
line({
metric: indicators.stochRsiK,
name: "K",
color: colors.blue,
unit: Unit.index,
}),
s({
line({
metric: indicators.stochRsiD,
name: "D",
color: colors.orange,
@@ -72,8 +76,8 @@ export function createMomentumSection(ctx, indicators) {
// name: "Stochastic",
// title: "Stochastic Oscillator",
// bottom: [
// s({ metric: indicators.stochK, name: "K", color: colors.blue, unit: Unit.index }),
// s({ metric: indicators.stochD, name: "D", color: colors.orange, unit: Unit.index }),
// line({ metric: indicators.stochK, name: "K", color: colors.blue, unit: Unit.index }),
// line({ metric: indicators.stochD, name: "D", color: colors.orange, unit: Unit.index }),
// createPriceLine({ unit: Unit.index, number: 80 }),
// createPriceLine({ unit: Unit.index, number: 20 }),
// ],
@@ -82,22 +86,21 @@ export function createMomentumSection(ctx, indicators) {
name: "MACD",
title: "Moving Average Convergence Divergence",
bottom: [
s({
line({
metric: indicators.macdLine,
name: "MACD",
color: colors.blue,
unit: Unit.usd,
}),
s({
line({
metric: indicators.macdSignal,
name: "Signal",
color: colors.orange,
unit: Unit.usd,
}),
/** @type {FetchedHistogramSeriesBlueprint} */ ({
histogram({
metric: indicators.macdHistogram,
title: "Histogram",
type: "Histogram",
name: "Histogram",
unit: Unit.usd,
}),
createPriceLine({ unit: Unit.usd }),
@@ -10,7 +10,7 @@ import { Unit } from "../../../utils/units.js";
* @param {Market["movingAverage"]} args.movingAverage
*/
export function createOnchainSection(ctx, { indicators, movingAverage }) {
const { s, colors, createPriceLine } = ctx;
const { line, colors, createPriceLine } = ctx;
return {
name: "On-chain",
@@ -19,13 +19,13 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) {
name: "Pi Cycle",
title: "Pi Cycle Top Indicator",
top: [
s({
line({
metric: movingAverage.price111dSma.price,
name: "111d SMA",
color: colors.green,
unit: Unit.usd,
}),
s({
line({
metric: movingAverage.price350dSmaX2,
name: "350d SMA x2",
color: colors.red,
@@ -33,7 +33,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) {
}),
],
bottom: [
s({
line({
metric: indicators.piCycle,
name: "Pi Cycle",
color: colors.purple,
@@ -46,7 +46,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) {
name: "Puell Multiple",
title: "Puell Multiple",
bottom: [
s({
line({
metric: indicators.puellMultiple,
name: "Puell",
color: colors.green,
@@ -58,7 +58,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) {
name: "NVT",
title: "Network Value to Transactions Ratio",
bottom: [
s({
line({
metric: indicators.nvt,
name: "NVT",
color: colors.orange,
@@ -70,7 +70,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) {
name: "Gini",
title: "Gini Coefficient",
bottom: [
s({
line({
metric: indicators.gini,
name: "Gini",
color: colors.red,
@@ -10,7 +10,7 @@ import { Unit } from "../../../utils/units.js";
* @param {Market["range"]} args.range
*/
export function createVolatilitySection(ctx, { volatility, range }) {
const { s, colors, createPriceLine } = ctx;
const { line, colors, createPriceLine } = ctx;
return {
name: "Volatility",
@@ -19,21 +19,48 @@ export function createVolatilitySection(ctx, { volatility, range }) {
name: "Index",
title: "Bitcoin Price Volatility Index",
bottom: [
s({ metric: volatility.price1wVolatility, name: "1w", color: colors.red, unit: Unit.percentage }),
s({ metric: volatility.price1mVolatility, name: "1m", color: colors.orange, unit: Unit.percentage }),
s({ metric: volatility.price1yVolatility, name: "1y", color: colors.lime, unit: Unit.percentage }),
line({
metric: volatility.price1wVolatility,
name: "1w",
color: colors.red,
unit: Unit.percentage,
}),
line({
metric: volatility.price1mVolatility,
name: "1m",
color: colors.orange,
unit: Unit.percentage,
}),
line({
metric: volatility.price1yVolatility,
name: "1y",
color: colors.lime,
unit: Unit.percentage,
}),
],
},
{
name: "True Range",
title: "Bitcoin Price True Range",
bottom: [s({ metric: range.priceTrueRange, name: "Value", color: colors.yellow, unit: Unit.usd })],
bottom: [
line({
metric: range.priceTrueRange,
name: "Value",
color: colors.yellow,
unit: Unit.usd,
}),
],
},
{
name: "Choppiness",
title: "Bitcoin Price Choppiness Index",
bottom: [
s({ metric: range.price2wChoppinessIndex, name: "2w", color: colors.red, unit: Unit.index }),
line({
metric: range.price2wChoppinessIndex,
name: "2w",
color: colors.red,
unit: Unit.index,
}),
createPriceLine({ unit: Unit.index, number: 61.8 }),
createPriceLine({ unit: Unit.index, number: 38.2 }),
],
@@ -42,9 +69,24 @@ export function createVolatilitySection(ctx, { volatility, range }) {
name: "Sharpe Ratio",
title: "Sharpe Ratio",
bottom: [
s({ metric: volatility.sharpe1w, name: "1w", color: colors.red, unit: Unit.ratio }),
s({ metric: volatility.sharpe1m, name: "1m", color: colors.orange, unit: Unit.ratio }),
s({ metric: volatility.sharpe1y, name: "1y", color: colors.lime, unit: Unit.ratio }),
line({
metric: volatility.sharpe1w,
name: "1w",
color: colors.red,
unit: Unit.ratio,
}),
line({
metric: volatility.sharpe1m,
name: "1m",
color: colors.orange,
unit: Unit.ratio,
}),
line({
metric: volatility.sharpe1y,
name: "1y",
color: colors.lime,
unit: Unit.ratio,
}),
createPriceLine({ unit: Unit.ratio }),
],
},
@@ -52,9 +94,24 @@ export function createVolatilitySection(ctx, { volatility, range }) {
name: "Sortino Ratio",
title: "Sortino Ratio",
bottom: [
s({ metric: volatility.sortino1w, name: "1w", color: colors.red, unit: Unit.ratio }),
s({ metric: volatility.sortino1m, name: "1m", color: colors.orange, unit: Unit.ratio }),
s({ metric: volatility.sortino1y, name: "1y", color: colors.lime, unit: Unit.ratio }),
line({
metric: volatility.sortino1w,
name: "1w",
color: colors.red,
unit: Unit.ratio,
}),
line({
metric: volatility.sortino1m,
name: "1m",
color: colors.orange,
unit: Unit.ratio,
}),
line({
metric: volatility.sortino1y,
name: "1y",
color: colors.lime,
unit: Unit.ratio,
}),
createPriceLine({ unit: Unit.ratio }),
],
},
@@ -40,7 +40,7 @@ export function buildDcaClasses(colors, dca) {
* @param {Market["returns"]} args.returns
*/
export function createInvestingSection(ctx, { dca, lookback, returns }) {
const { s, colors, createPriceLine } = ctx;
const { line, baseline, colors, createPriceLine } = ctx;
const dcaClasses = buildDcaClasses(colors, dca);
return {
@@ -77,13 +77,13 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
name: "Cost basis",
title: `${name} DCA vs Lump Sum (Cost Basis)`,
top: [
s({
line({
metric: dcaCostBasis,
name: "DCA",
color: colors.green,
unit: Unit.usd,
}),
s({
line({
metric: priceAgo,
name: "Lump sum",
color: colors.orange,
@@ -95,17 +95,15 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
name: "Returns",
title: `${name} DCA vs Lump Sum (Returns)`,
bottom: [
/** @type {AnyFetchedSeriesBlueprint} */ ({
baseline({
metric: dcaReturns,
title: "DCA",
type: "Baseline",
name: "DCA",
unit: Unit.percentage,
}),
/** @type {AnyFetchedSeriesBlueprint} */ ({
baseline({
metric: priceReturns,
title: "Lump sum",
type: "Baseline",
colors: [colors.lime, colors.red],
name: "Lump sum",
color: [colors.lime, colors.red],
unit: Unit.percentage,
}),
createPriceLine({ unit: Unit.percentage }),
@@ -115,37 +113,37 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
name: "Stack",
title: `${name} DCA vs Lump Sum Stack ($100/day)`,
bottom: [
s({
line({
metric: dcaStack.sats,
name: "DCA",
color: colors.green,
unit: Unit.sats,
}),
s({
line({
metric: dcaStack.bitcoin,
name: "DCA",
color: colors.green,
unit: Unit.btc,
}),
s({
line({
metric: dcaStack.dollars,
name: "DCA",
color: colors.green,
unit: Unit.usd,
}),
s({
line({
metric: lumpSumStack.sats,
name: "Lump sum",
color: colors.orange,
unit: Unit.sats,
}),
s({
line({
metric: lumpSumStack.bitcoin,
name: "Lump sum",
color: colors.orange,
unit: Unit.btc,
}),
s({
line({
metric: lumpSumStack.dollars,
name: "Lump sum",
color: colors.orange,
@@ -171,7 +169,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
title: "DCA Cost Basis by Year",
top: dcaClasses.map(
({ year, color, defaultActive, costBasis }) =>
s({
line({
metric: costBasis,
name: `${year}`,
color,
@@ -183,16 +181,14 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
{
name: "Returns",
title: "DCA Returns by Year",
bottom: dcaClasses.map(
({ year, color, defaultActive, returns }) =>
/** @type {AnyFetchedSeriesBlueprint} */ ({
metric: returns,
title: `${year}`,
type: "Baseline",
color,
defaultActive,
unit: Unit.percentage,
}),
bottom: dcaClasses.map(({ year, color, defaultActive, returns }) =>
baseline({
metric: returns,
name: `${year}`,
color,
defaultActive,
unit: Unit.percentage,
}),
),
},
{
@@ -200,21 +196,21 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
title: "DCA Stack by Year ($100/day)",
bottom: dcaClasses.flatMap(
({ year, color, defaultActive, stack }) => [
s({
line({
metric: stack.sats,
name: `${year}`,
color,
defaultActive,
unit: Unit.sats,
}),
s({
line({
metric: stack.bitcoin,
name: `${year}`,
color,
defaultActive,
unit: Unit.btc,
}),
s({
line({
metric: stack.dollars,
name: `${year}`,
color,
@@ -234,7 +230,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
name: "Cost basis",
title: `DCA Class ${year} Cost Basis`,
top: [
s({
line({
metric: costBasis,
name: "Cost basis",
color,
@@ -246,10 +242,9 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
name: "Returns",
title: `DCA Class ${year} Returns`,
bottom: [
/** @type {AnyFetchedSeriesBlueprint} */ ({
baseline({
metric: returns,
title: "Returns",
type: "Baseline",
name: "Returns",
color,
unit: Unit.percentage,
}),
@@ -259,19 +254,19 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
name: "Stack",
title: `DCA Class ${year} Stack ($100/day)`,
bottom: [
s({
line({
metric: stack.sats,
name: "Stack",
color,
unit: Unit.sats,
}),
s({
line({
metric: stack.bitcoin,
name: "Stack",
color,
unit: Unit.btc,
}),
s({
line({
metric: stack.dollars,
name: "Stack",
color,
@@ -9,7 +9,7 @@ import { periodIdToName } from "./utils.js";
* @param {Market["returns"]} returns
*/
export function createPerformanceSection(ctx, returns) {
const { colors, createPriceLine } = ctx;
const { colors, baseline, createPriceLine } = ctx;
return {
name: "Performance",
@@ -35,19 +35,17 @@ export function createPerformanceSection(ctx, returns) {
name,
title: `${name} Performance`,
bottom: [
/** @type {AnyFetchedSeriesBlueprint} */ ({
baseline({
metric: priceReturns,
title: "Total",
type: "Baseline",
name: "Total",
unit: Unit.percentage,
}),
...(cagr
? [
/** @type {AnyFetchedSeriesBlueprint} */ ({
baseline({
metric: cagr,
title: "CAGR",
type: "Baseline",
colors: [colors.lime, colors.pink],
name: "CAGR",
color: [colors.lime, colors.pink],
unit: Unit.percentage,
}),
]
+54 -49
View File
@@ -4,7 +4,11 @@ import { localhost } from "../utils/env.js";
import { createContext } from "./context.js";
import {
buildCohortData,
createUtxoCohortFolder,
createCohortFolderAll,
createCohortFolderFull,
createCohortFolderWithAdjusted,
createCohortFolderWithPercentiles,
createCohortFolderBasic,
createAddressCohortFolder,
} from "./cohorts/index.js";
import { createMarketSection } from "./market/index.js";
@@ -28,8 +32,8 @@ export function createPartialOptions({ colors, brk }) {
// Build cohort data
const {
cohortAll,
cohortAllForComparison,
terms,
termShort,
termLong,
upToDate,
fromDate,
dateRange,
@@ -43,11 +47,15 @@ export function createPartialOptions({ colors, brk }) {
type,
} = buildCohortData(colors, brk);
// Helper to map UTXO cohorts
const mapUtxoCohorts = (/** @type {any} */ cohort) => createUtxoCohortFolder(ctx, cohort);
// Helper to map Address cohorts
const mapAddressCohorts = (/** @type {any} */ cohort) => createAddressCohortFolder(ctx, cohort);
// Helpers to map cohorts by capability type
/** @param {CohortWithAdjusted} cohort */
const mapWithAdjusted = (cohort) => createCohortFolderWithAdjusted(ctx, cohort);
/** @param {CohortWithPercentiles} cohort */
const mapWithPercentiles = (cohort) => createCohortFolderWithPercentiles(ctx, cohort);
/** @param {CohortBasic} cohort */
const mapBasic = (cohort) => createCohortFolderBasic(ctx, cohort);
/** @param {AddressCohortObject} cohort */
const mapAddressCohorts = (cohort) => createAddressCohortFolder(ctx, cohort);
return [
// Debug explorer (localhost only)
@@ -75,123 +83,120 @@ export function createPartialOptions({ colors, brk }) {
{
name: "Cohorts",
tree: [
// All UTXOs
createUtxoCohortFolder(ctx, cohortAll),
// All UTXOs - CohortAll (adjustedSopr + percentiles but no RelToMarketCap)
createCohortFolderAll(ctx, cohortAll),
// Terms (STH/LTH)
// Terms (STH/LTH) - Short is Full, Long is WithPercentiles
{
name: "terms",
tree: [
createUtxoCohortFolder(ctx, {
name: "Compare",
title: "UTXOs Term",
list: [...terms, cohortAllForComparison],
}),
...terms.map(mapUtxoCohorts),
// Individual cohorts with their specific capabilities
createCohortFolderFull(ctx, termShort),
createCohortFolderWithPercentiles(ctx, termLong),
],
},
// Epochs
// Epochs - CohortBasic (neither adjustedSopr nor percentiles)
{
name: "Epochs",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderBasic(ctx, {
name: "Compare",
title: "Epoch",
list: [...epoch, cohortAllForComparison],
list: epoch,
}),
...epoch.map(mapUtxoCohorts),
...epoch.map(mapBasic),
],
},
// Types
// Types - CohortBasic
{
name: "types",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderBasic(ctx, {
name: "Compare",
title: "Type",
list: [...type, cohortAllForComparison],
list: type,
}),
...type.map(mapUtxoCohorts),
...type.map(mapBasic),
],
},
// UTXOs Up to age
// UTXOs Up to age - CohortWithAdjusted (adjustedSopr only)
{
name: "UTXOs Up to age",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderWithAdjusted(ctx, {
name: "Compare",
title: "UTXOs Up To Age",
list: [...upToDate, cohortAllForComparison],
list: upToDate,
}),
...upToDate.map(mapUtxoCohorts),
...upToDate.map(mapWithAdjusted),
],
},
// UTXOs from age
// UTXOs from age - CohortBasic
{
name: "UTXOs from age",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderBasic(ctx, {
name: "Compare",
title: "UTXOs from age",
list: [...fromDate, cohortAllForComparison],
list: fromDate,
}),
...fromDate.map(mapUtxoCohorts),
...fromDate.map(mapBasic),
],
},
// UTXOs age ranges
// UTXOs age ranges - CohortWithPercentiles (percentiles only)
{
name: "UTXOs age Ranges",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderWithPercentiles(ctx, {
name: "Compare",
title: "UTXOs Age Range",
list: [...dateRange, cohortAllForComparison],
list: dateRange,
}),
...dateRange.map(mapUtxoCohorts),
...dateRange.map(mapWithPercentiles),
],
},
// UTXOs under amounts
// UTXOs under amounts - CohortBasic
{
name: "UTXOs under amounts",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderBasic(ctx, {
name: "Compare",
title: "UTXOs under amount",
list: [...utxosUnderAmount, cohortAllForComparison],
list: utxosUnderAmount,
}),
...utxosUnderAmount.map(mapUtxoCohorts),
...utxosUnderAmount.map(mapBasic),
],
},
// UTXOs above amounts
// UTXOs above amounts - CohortBasic
{
name: "UTXOs Above Amounts",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderBasic(ctx, {
name: "Compare",
title: "UTXOs Above Amount",
list: [...utxosAboveAmount, cohortAllForComparison],
list: utxosAboveAmount,
}),
...utxosAboveAmount.map(mapUtxoCohorts),
...utxosAboveAmount.map(mapBasic),
],
},
// UTXOs between amounts
// UTXOs between amounts - CohortBasic
{
name: "UTXOs between amounts",
tree: [
createUtxoCohortFolder(ctx, {
createCohortFolderBasic(ctx, {
name: "Compare",
title: "UTXOs between amounts",
list: [...utxosAmountRanges, cohortAllForComparison],
list: utxosAmountRanges,
}),
...utxosAmountRanges.map(mapUtxoCohorts),
...utxosAmountRanges.map(mapBasic),
],
},
+205 -16
View File
@@ -3,17 +3,17 @@
import { Unit } from "../utils/units.js";
/**
* Create a single series from a tree accessor
* Create a Line series
* @param {Object} args
* @param {AnyMetricPattern} args.metric - Tree accessor with .by property
* @param {string} args.name - Display name for the series
* @param {AnyMetricPattern} args.metric
* @param {string} args.name
* @param {Unit} args.unit
* @param {Color} [args.color]
* @param {Unit} [args.unit]
* @param {boolean} [args.defaultActive]
* @param {LineSeriesPartialOptions} [args.options]
* @returns {AnyFetchedSeriesBlueprint}
* @returns {FetchedLineSeriesBlueprint}
*/
export function s({ metric, name, color, defaultActive, unit, options }) {
export function line({ metric, name, color, defaultActive, unit, options }) {
return {
metric,
title: name,
@@ -24,6 +24,68 @@ export function s({ metric, name, color, defaultActive, unit, options }) {
};
}
/**
* Create a Baseline series
* @param {Object} args
* @param {AnyMetricPattern} args.metric
* @param {string} args.name
* @param {Unit} args.unit
* @param {Color | [Color, Color]} [args.color]
* @param {boolean} [args.defaultActive]
* @param {BaselineSeriesPartialOptions} [args.options]
* @returns {FetchedBaselineSeriesBlueprint}
*/
export function baseline({
metric,
name,
color,
defaultActive,
unit,
options,
}) {
const isTuple = Array.isArray(color);
return {
type: /** @type {const} */ ("Baseline"),
metric,
title: name,
color: isTuple ? undefined : color,
colors: isTuple ? color : undefined,
unit,
defaultActive,
options,
};
}
/**
* Create a Histogram series
* @param {Object} args
* @param {AnyMetricPattern} args.metric
* @param {string} args.name
* @param {Unit} args.unit
* @param {Color | [Color, Color]} [args.color]
* @param {boolean} [args.defaultActive]
* @param {HistogramSeriesPartialOptions} [args.options]
* @returns {FetchedHistogramSeriesBlueprint}
*/
export function histogram({
metric,
name,
color,
defaultActive,
unit,
options,
}) {
return {
type: /** @type {const} */ ("Histogram"),
metric,
title: name,
color,
unit,
defaultActive,
options,
};
}
/**
* Create series from a BlockCountPattern ({ base, sum, cumulative })
* @param {Colors} colors
@@ -424,7 +486,13 @@ export function fromCoinbasePattern(colors, pattern, title) {
* @param {Color} [cumulativeColor]
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function fromValuePattern(colors, pattern, title, sumColor, cumulativeColor) {
export function fromValuePattern(
colors,
pattern,
title,
sumColor,
cumulativeColor,
) {
return [
{
metric: pattern.sats.sum,
@@ -468,6 +536,41 @@ export function fromValuePattern(colors, pattern, title, sumColor, cumulativeCol
];
}
/**
* Create sum/cumulative series from a BitcoinPattern ({ sum, cumulative }) with explicit unit and colors
* @param {Colors} colors
* @param {{ sum: AnyMetricPattern, cumulative: AnyMetricPattern }} pattern
* @param {string} title
* @param {Unit} unit
* @param {Color} [sumColor]
* @param {Color} [cumulativeColor]
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function fromBitcoinPatternWithUnit(
colors,
pattern,
title,
unit,
sumColor,
cumulativeColor,
) {
return [
{
metric: pattern.sum,
title: `${title} sum`,
color: sumColor,
unit,
},
{
metric: pattern.cumulative,
title: `${title} cumulative`,
color: cumulativeColor ?? colors.blue,
unit,
defaultActive: false,
},
];
}
/**
* Create sum/cumulative series from a BlockCountPattern with explicit unit and colors
* @param {Colors} colors
@@ -478,7 +581,14 @@ export function fromValuePattern(colors, pattern, title, sumColor, cumulativeCol
* @param {Color} [cumulativeColor]
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function fromBlockCountWithUnit(colors, pattern, title, unit, sumColor, cumulativeColor) {
export function fromBlockCountWithUnit(
colors,
pattern,
title,
unit,
sumColor,
cumulativeColor,
) {
return [
{
metric: pattern.sum,
@@ -508,13 +618,92 @@ export function fromBlockCountWithUnit(colors, pattern, title, unit, sumColor, c
export function fromIntervalPattern(colors, pattern, title, unit, color) {
return [
{ metric: pattern.base, title, color, unit },
{ metric: pattern.average, title: `${title} avg`, color: colors.purple, unit, defaultActive: false },
{ metric: pattern.min, title: `${title} min`, color: colors.red, unit, defaultActive: false },
{ metric: pattern.max, title: `${title} max`, color: colors.green, unit, defaultActive: false },
{ metric: pattern.median, title: `${title} median`, color: colors.violet, unit, defaultActive: false },
{ metric: pattern.pct10, title: `${title} pct10`, color: colors.rose, unit, defaultActive: false },
{ metric: pattern.pct25, title: `${title} pct25`, color: colors.pink, unit, defaultActive: false },
{ metric: pattern.pct75, title: `${title} pct75`, color: colors.fuchsia, unit, defaultActive: false },
{ metric: pattern.pct90, title: `${title} pct90`, color: colors.amber, unit, defaultActive: false },
{
metric: pattern.average,
title: `${title} avg`,
color: colors.purple,
unit,
defaultActive: false,
},
{
metric: pattern.min,
title: `${title} min`,
color: colors.red,
unit,
defaultActive: false,
},
{
metric: pattern.max,
title: `${title} max`,
color: colors.green,
unit,
defaultActive: false,
},
{
metric: pattern.median,
title: `${title} median`,
color: colors.violet,
unit,
defaultActive: false,
},
{
metric: pattern.pct10,
title: `${title} pct10`,
color: colors.rose,
unit,
defaultActive: false,
},
{
metric: pattern.pct25,
title: `${title} pct25`,
color: colors.pink,
unit,
defaultActive: false,
},
{
metric: pattern.pct75,
title: `${title} pct75`,
color: colors.fuchsia,
unit,
defaultActive: false,
},
{
metric: pattern.pct90,
title: `${title} pct90`,
color: colors.amber,
unit,
defaultActive: false,
},
];
}
/**
* Create series from a SupplyPattern (sats/bitcoin/dollars, no sum/cumulative)
* @param {Colors} colors
* @param {SupplyPattern} pattern
* @param {string} title
* @param {Color} [color]
* @returns {AnyFetchedSeriesBlueprint[]}
*/
export function fromSupplyPattern(colors, pattern, title, color) {
return [
{
metric: pattern.sats,
title,
color: color ?? colors.default,
unit: Unit.sats,
},
{
metric: pattern.bitcoin,
title,
color: color ?? colors.default,
unit: Unit.btc,
},
{
metric: pattern.dollars,
title,
color: color ?? colors.default,
unit: Unit.usd,
},
];
}
+94 -25
View File
@@ -121,19 +121,98 @@
* @property {Color} color
* @property {UtxoCohortPattern} tree
*
* Age cohorts (term, maxAge, minAge, ageRange, epoch) - have cost basis percentiles
* @typedef {Object} AgeCohortObject
* @property {string} name
* @property {string} title
* @property {Color} color
* @property {PatternWithCostBasisPercentiles} tree
* ============================================================================
* UTXO Cohort Pattern Types (based on brk client patterns)
* ============================================================================
*
* Amount cohorts (geAmount, ltAmount, amountRange, type) - no cost basis percentiles
* @typedef {Object} AmountCohortObject
* Patterns with adjustedSopr + percentiles + RelToMarketCap:
* - ShortTermPattern (term.short)
* @typedef {ShortTermPattern} PatternFull
*
* The "All" pattern is special - has adjustedSopr + percentiles but NO RelToMarketCap
* @typedef {AllUtxoPattern} PatternAll
*
* Patterns with adjustedSopr only (RealizedPattern4, CostBasisPattern):
* - MaxAgePattern (maxAge.*)
* @typedef {MaxAgePattern} PatternWithAdjusted
*
* Patterns with percentiles only (RealizedPattern2, CostBasisPattern2):
* - LongTermPattern (term.long)
* - AgeRangePattern (ageRange.*)
* @typedef {LongTermPattern | AgeRangePattern} PatternWithPercentiles
*
* Patterns with neither (RealizedPattern/2, CostBasisPattern):
* - BasicUtxoPattern (minAge.*, geAmount.*, ltAmount.*)
* - EpochPattern (epoch.*)
* @typedef {BasicUtxoPattern | EpochPattern} PatternBasic
*
* ============================================================================
* Cohort Object Types (by capability)
* ============================================================================
*
* All cohort: adjustedSopr + percentiles but NO RelToMarketCap (special)
* @typedef {Object} CohortAll
* @property {string} name
* @property {string} title
* @property {Color} color
* @property {UtxoAmountPattern} tree
* @property {PatternAll} tree
*
* Full cohort: adjustedSopr + percentiles + RelToMarketCap (term.short)
* @typedef {Object} CohortFull
* @property {string} name
* @property {string} title
* @property {Color} color
* @property {PatternFull} tree
*
* Cohort with adjustedSopr only (maxAge.*)
* @typedef {Object} CohortWithAdjusted
* @property {string} name
* @property {string} title
* @property {Color} color
* @property {PatternWithAdjusted} tree
*
* Cohort with percentiles only (term.long, ageRange.*)
* @typedef {Object} CohortWithPercentiles
* @property {string} name
* @property {string} title
* @property {Color} color
* @property {PatternWithPercentiles} tree
*
* Basic cohort: neither (minAge.*, epoch.*, amount cohorts)
* @typedef {Object} CohortBasic
* @property {string} name
* @property {string} title
* @property {Color} color
* @property {PatternBasic} tree
*
* ============================================================================
* Cohort Group Types (by capability)
* ============================================================================
*
* @typedef {Object} CohortGroupFull
* @property {string} name
* @property {string} title
* @property {readonly CohortFull[]} list
*
* @typedef {Object} CohortGroupWithAdjusted
* @property {string} name
* @property {string} title
* @property {readonly CohortWithAdjusted[]} list
*
* @typedef {Object} CohortGroupWithPercentiles
* @property {string} name
* @property {string} title
* @property {readonly CohortWithPercentiles[]} list
*
* @typedef {Object} CohortGroupBasic
* @property {string} name
* @property {string} title
* @property {readonly CohortBasic[]} list
*
* @typedef {Object} UtxoCohortGroupObject
* @property {string} name
* @property {string} title
* @property {readonly UtxoCohortObject[]} list
*
* @typedef {Object} AddressCohortObject
* @property {string} name
@@ -143,20 +222,6 @@
*
* @typedef {UtxoCohortObject | AddressCohortObject} CohortObject
*
* @typedef {Object} UtxoCohortGroupObject
* @property {string} name
* @property {string} title
* @property {readonly UtxoCohortObject[]} list
*
* @typedef {Object} AgeCohortGroupObject
* @property {string} name
* @property {string} title
* @property {readonly AgeCohortObject[]} list
*
* @typedef {Object} AmountCohortGroupObject
* @property {string} name
* @property {string} title
* @property {readonly AmountCohortObject[]} list
*
* @typedef {Object} AddressCohortGroupObject
* @property {string} name
@@ -168,7 +233,9 @@
* @typedef {Object} PartialContext
* @property {Colors} colors
* @property {BrkClient} brk
* @property {(args: { metric: AnyMetricPattern, name: string, unit: Unit, color?: Color, defaultActive?: boolean, options?: LineSeriesPartialOptions }) => AnyFetchedSeriesBlueprint} s
* @property {LineSeriesFn} line
* @property {BaselineSeriesFn} baseline
* @property {HistogramSeriesFn} histogram
* @property {(pattern: BlockCountPattern<any>, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCount
* @property {(pattern: FullnessPattern<any>, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoin
* @property {(pattern: SizePattern<any>, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockSize
@@ -177,11 +244,13 @@
* @property {(pattern: FeeRatePattern<any>, title: string, unit: Unit) => AnyFetchedSeriesBlueprint[]} fromFeeRatePattern
* @property {(pattern: CoinbasePattern, title: string) => AnyFetchedSeriesBlueprint[]} fromCoinbasePattern
* @property {(pattern: ValuePattern, title: string, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromValuePattern
* @property {(pattern: { sum: AnyMetricPattern, cumulative: AnyMetricPattern }, title: string, unit: Unit, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoinPatternWithUnit
* @property {(pattern: BlockCountPattern<any>, title: string, unit: Unit, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCountWithUnit
* @property {(pattern: IntervalPattern, title: string, unit: Unit, color?: Color) => AnyFetchedSeriesBlueprint[]} fromIntervalPattern
* @property {(pattern: SupplyPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromSupplyPattern
* @property {(args: { number?: number, name?: string, defaultActive?: boolean, lineStyle?: LineStyle, color?: Color, unit: Unit }) => FetchedLineSeriesBlueprint} createPriceLine
* @property {(args: { numbers: number[], unit: Unit }) => FetchedLineSeriesBlueprint[]} createPriceLines
* @property {(args: { constant: AnyMetricPattern, name: string, unit: Unit, color?: Color, lineStyle?: number, defaultActive?: boolean }) => FetchedLineSeriesBlueprint} line
* @property {(args: { constant: AnyMetricPattern, name: string, unit: Unit, color?: Color, lineStyle?: number, defaultActive?: boolean }) => FetchedLineSeriesBlueprint} constantLine
*/
// Re-export for type consumers
+1
View File
@@ -21,6 +21,7 @@ export const Unit = /** @type {const} */ ({
pctMcap: { id: "pct-mcap", name: "% of Market Cap" },
pctRcap: { id: "pct-rcap", name: "% of Realized Cap" },
pctOwnMcap: { id: "pct-own-mcap", name: "% of Own Market Cap" },
pctOwnPnl: { id: "pct-own-pnl", name: "% of Own P&L" },
// Time
days: { id: "days", name: "Days" },