global: snapshot

This commit is contained in:
nym21
2026-02-12 22:52:57 +01:00
parent 3bc20a0a46
commit b779edc0d6
60 changed files with 8720 additions and 1504 deletions

View File

@@ -396,7 +396,7 @@ export function createCointimeSection() {
line({
metric: reserveRisk.vocdd365dMedian,
name: "365d Median",
color: colors.ma._1y,
color: colors.time._1y,
unit: Unit.usd,
}),
],

View File

@@ -367,21 +367,21 @@ export function createActivitySection({
line({
metric: tree.activity.sent14dEma.sats,
name: "14d EMA",
color: colors.ma._14d,
color: colors.indicator.main,
unit: Unit.sats,
defaultActive: false,
}),
line({
metric: tree.activity.sent14dEma.bitcoin,
name: "14d EMA",
color: colors.ma._14d,
color: colors.indicator.main,
unit: Unit.btc,
defaultActive: false,
}),
line({
metric: tree.activity.sent14dEma.dollars,
name: "14d EMA",
color: colors.ma._14d,
color: colors.indicator.main,
unit: Unit.usd,
defaultActive: false,
}),
@@ -814,13 +814,13 @@ function createSingleSellSideRiskSeries(tree) {
line({
metric: tree.realized.sellSideRiskRatio30dEma,
name: "30d EMA",
color: colors.ma._1m,
color: colors.time._1m,
unit: Unit.ratio,
}),
line({
metric: tree.realized.sellSideRiskRatio7dEma,
name: "7d EMA",
color: colors.ma._1w,
color: colors.time._1w,
unit: Unit.ratio,
}),
dots({

View File

@@ -11,118 +11,30 @@
*/
import { colors } from "../../utils/colors.js";
import { entries } from "../../utils/array.js";
import { Unit } from "../../utils/units.js";
import { priceLines } from "../constants.js";
import { line, price } from "../series.js";
import { mapCohortsWithAll } from "../shared.js";
const ACTIVE_PCTS = new Set(["pct75", "pct50", "pct25"]);
/**
* @param {PercentilesPattern} p
* @param {(name: string) => string} [n]
* @returns {FetchedPriceSeriesBlueprint[]}
*/
function createCorePercentileSeries(p, n = (x) => x) {
return [
price({
metric: p.pct95,
name: n("p95"),
color: colors.pct._95,
defaultActive: false,
}),
price({
metric: p.pct90,
name: n("p90"),
color: colors.pct._90,
defaultActive: false,
}),
price({
metric: p.pct85,
name: n("p85"),
color: colors.pct._85,
defaultActive: false,
}),
price({
metric: p.pct80,
name: n("p80"),
color: colors.pct._80,
defaultActive: false,
}),
price({ metric: p.pct75, name: n("p75"), color: colors.pct._75 }),
price({
metric: p.pct70,
name: n("p70"),
color: colors.pct._70,
defaultActive: false,
}),
price({
metric: p.pct65,
name: n("p65"),
color: colors.pct._65,
defaultActive: false,
}),
price({
metric: p.pct60,
name: n("p60"),
color: colors.pct._60,
defaultActive: false,
}),
price({
metric: p.pct55,
name: n("p55"),
color: colors.pct._55,
defaultActive: false,
}),
price({ metric: p.pct50, name: n("p50"), color: colors.pct._50 }),
price({
metric: p.pct45,
name: n("p45"),
color: colors.pct._45,
defaultActive: false,
}),
price({
metric: p.pct40,
name: n("p40"),
color: colors.pct._40,
defaultActive: false,
}),
price({
metric: p.pct35,
name: n("p35"),
color: colors.pct._35,
defaultActive: false,
}),
price({
metric: p.pct30,
name: n("p30"),
color: colors.pct._30,
defaultActive: false,
}),
price({ metric: p.pct25, name: n("p25"), color: colors.pct._25 }),
price({
metric: p.pct20,
name: n("p20"),
color: colors.pct._20,
defaultActive: false,
}),
price({
metric: p.pct15,
name: n("p15"),
color: colors.pct._15,
defaultActive: false,
}),
price({
metric: p.pct10,
name: n("p10"),
color: colors.pct._10,
defaultActive: false,
}),
price({
metric: p.pct05,
name: n("p05"),
color: colors.pct._05,
defaultActive: false,
}),
];
return entries(p)
.reverse()
.map(([key, metric], i, arr) =>
price({
metric,
name: n(key.replace("pct", "p")),
color: colors.at(i, arr.length),
...(ACTIVE_PCTS.has(key) ? {} : { defaultActive: false }),
}),
);
}
/**
@@ -136,13 +48,13 @@ function createSingleSummarySeriesBasic(cohort) {
price({
metric: tree.costBasis.max,
name: "Max",
color: colors.pct._100,
color: colors.stat.max,
defaultActive: false,
}),
price({
metric: tree.costBasis.min,
name: "Min",
color: colors.pct._0,
color: colors.stat.min,
defaultActive: false,
}),
];
@@ -160,26 +72,26 @@ function createSingleSummarySeriesWithPercentiles(cohort) {
price({
metric: tree.costBasis.max,
name: "Max (p100)",
color: colors.pct._100,
color: colors.stat.max,
defaultActive: false,
}),
price({
metric: p.pct75,
name: "Q3 (p75)",
color: colors.pct._75,
color: colors.stat.pct75,
defaultActive: false,
}),
price({ metric: p.pct50, name: "Median (p50)", color: colors.pct._50 }),
price({ metric: p.pct50, name: "Median (p50)", color: colors.stat.median }),
price({
metric: p.pct25,
name: "Q1 (p25)",
color: colors.pct._25,
color: colors.stat.pct25,
defaultActive: false,
}),
price({
metric: tree.costBasis.min,
name: "Min (p0)",
color: colors.pct._0,
color: colors.stat.min,
defaultActive: false,
}),
];
@@ -208,14 +120,14 @@ function createSingleByCoinSeries(cohort) {
price({
metric: cb.max,
name: "p100",
color: colors.pct._100,
color: colors.stat.max,
defaultActive: false,
}),
...createCorePercentileSeries(cb.percentiles),
price({
metric: cb.min,
name: "p0",
color: colors.pct._0,
color: colors.stat.min,
defaultActive: false,
}),
];

View File

@@ -67,68 +67,72 @@ export function buildCohortData() {
};
// Max age cohorts (up to X time)
const upToDate = entries(utxoCohorts.maxAge).map(([key, tree]) => {
const upToDate = entries(utxoCohorts.maxAge).map(([key, tree], i, arr) => {
const names = MAX_AGE_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.age[key],
color: colors.at(i, arr.length),
tree,
};
});
// Min age cohorts (from X time)
const fromDate = entries(utxoCohorts.minAge).map(([key, tree]) => {
const fromDate = entries(utxoCohorts.minAge).map(([key, tree], i, arr) => {
const names = MIN_AGE_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.age[key],
color: colors.at(i, arr.length),
tree,
};
});
// Age range cohorts
const dateRange = entries(utxoCohorts.ageRange).map(([key, tree]) => {
const names = AGE_RANGE_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.ageRange[key],
tree,
};
});
const dateRange = entries(utxoCohorts.ageRange).map(
([key, tree], i, arr) => {
const names = AGE_RANGE_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.at(i, arr.length),
tree,
};
},
);
// Epoch cohorts
const epoch = entries(utxoCohorts.epoch).map(([key, tree]) => {
const epoch = entries(utxoCohorts.epoch).map(([key, tree], i, arr) => {
const names = EPOCH_NAMES[key];
return {
name: names.short,
title: names.long,
color: colors.epoch[key],
color: colors.at(i, arr.length),
tree,
};
});
// UTXOs above amount
const utxosAboveAmount = entries(utxoCohorts.geAmount).map(([key, tree]) => {
const names = GE_AMOUNT_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.amount[key],
tree,
};
});
const utxosAboveAmount = entries(utxoCohorts.geAmount).map(
([key, tree], i, arr) => {
const names = GE_AMOUNT_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.at(i, arr.length),
tree,
};
},
);
// Addresses above amount
const addressesAboveAmount = entries(addressCohorts.geAmount).map(
([key, cohort]) => {
([key, cohort], i, arr) => {
const names = GE_AMOUNT_NAMES[key];
return {
name: names.short,
title: `Addresses ${names.long}`,
color: colors.amount[key],
color: colors.at(i, arr.length),
tree: cohort,
addrCount: {
count: cohort.addrCount,
@@ -139,24 +143,26 @@ export function buildCohortData() {
);
// UTXOs under amount
const utxosUnderAmount = entries(utxoCohorts.ltAmount).map(([key, tree]) => {
const names = LT_AMOUNT_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.amount[key],
tree,
};
});
const utxosUnderAmount = entries(utxoCohorts.ltAmount).map(
([key, tree], i, arr) => {
const names = LT_AMOUNT_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.at(i, arr.length),
tree,
};
},
);
// Addresses under amount
const addressesUnderAmount = entries(addressCohorts.ltAmount).map(
([key, cohort]) => {
([key, cohort], i, arr) => {
const names = LT_AMOUNT_NAMES[key];
return {
name: names.short,
title: `Addresses ${names.long}`,
color: colors.amount[key],
color: colors.at(i, arr.length),
tree: cohort,
addrCount: {
count: cohort.addrCount,
@@ -168,12 +174,12 @@ export function buildCohortData() {
// UTXOs amount ranges
const utxosAmountRanges = entries(utxoCohorts.amountRange).map(
([key, tree]) => {
([key, tree], i, arr) => {
const names = AMOUNT_RANGE_NAMES[key];
return {
name: names.short,
title: `UTXOs ${names.long}`,
color: colors.amountRange[key],
color: colors.at(i, arr.length),
tree,
};
},
@@ -181,12 +187,12 @@ export function buildCohortData() {
// Addresses amount ranges
const addressesAmountRanges = entries(addressCohorts.amountRange).map(
([key, cohort]) => {
([key, cohort], i, arr) => {
const names = AMOUNT_RANGE_NAMES[key];
return {
name: names.short,
title: `Addresses ${names.long}`,
color: colors.amountRange[key],
color: colors.at(i, arr.length),
tree: cohort,
addrCount: {
count: cohort.addrCount,
@@ -197,12 +203,12 @@ export function buildCohortData() {
);
// Spendable type cohorts - split by addressability
const typeAddressable = ADDRESSABLE_TYPES.map((key) => {
const typeAddressable = ADDRESSABLE_TYPES.map((key, i, arr) => {
const names = SPENDABLE_TYPE_NAMES[key];
return {
name: names.short,
title: names.short,
color: colors.scriptType[key],
color: colors.at(i, arr.length),
tree: utxoCohorts.type[key],
addrCount: addrCount[key],
};
@@ -210,26 +216,28 @@ export function buildCohortData() {
const typeOther = entries(utxoCohorts.type)
.filter(([key]) => !isAddressable(key))
.map(([key, tree]) => {
.map(([key, tree], i, arr) => {
const names = SPENDABLE_TYPE_NAMES[key];
return {
name: names.short,
title: names.short,
color: colors.scriptType[key],
color: colors.at(i, arr.length),
tree,
};
});
// Year cohorts
const year = entries(utxoCohorts.year).map(([key, tree]) => {
const names = YEAR_NAMES[key];
return {
name: names.short,
title: names.long,
color: colors.year[key],
tree,
};
});
const year = entries(utxoCohorts.year)
.reverse()
.map(([key, tree], i, arr) => {
const names = YEAR_NAMES[key];
return {
name: names.short,
title: names.long,
color: colors.at(i, arr.length),
tree,
};
});
return {
cohortAll,

View File

@@ -91,7 +91,7 @@ export function createValuationSectionFull({ cohort, title }) {
* @returns {PartialOptionsGroup}
*/
export function createValuationSection({ cohort, title }) {
const { tree, color } = cohort;
const { tree } = cohort;
return {
name: "Valuation",
tree: [

View File

@@ -66,17 +66,20 @@ const periodName = (key) => periodIdToName(key.slice(1), true);
* @typedef {BaseEntryItem & { cagr: AnyMetricPattern }} LongEntryItem
*/
const ALL_YEARS = /** @type {const} */ ([...YEARS_2020S, ...YEARS_2010S]);
/**
* Build DCA class entry from year
* @param {MarketDca} dca
* @param {DcaYear} year
* @param {number} i
* @returns {BaseEntryItem}
*/
function buildYearEntry(dca, year) {
function buildYearEntry(dca, year, i) {
const key = /** @type {DcaYearKey} */ (`_${year}`);
return {
name: `${year}`,
color: colors.year[key],
color: colors.at(i, ALL_YEARS.length),
costBasis: dca.classAveragePrice[key],
returns: dca.classReturns[key],
minReturn: dca.classMinReturn[key],
@@ -536,10 +539,12 @@ function createPeriodSection({ dca, lookback, returns }) {
const isLumpSum = !!lookback;
const suffix = isLumpSum ? "Lump Sum" : "DCA";
/** @param {AllPeriodKey} key @returns {BaseEntryItem} */
const buildBaseEntry = (key) => ({
const allPeriods = /** @type {const} */ ([...SHORT_PERIODS, ...LONG_PERIODS]);
/** @param {AllPeriodKey} key @param {number} i @returns {BaseEntryItem} */
const buildBaseEntry = (key, i) => ({
name: periodName(key),
color: colors.dca[key],
color: colors.at(i, allPeriods.length),
costBasis: isLumpSum ? lookback[key] : dca.periodAveragePrice[key],
returns: isLumpSum ? dca.periodLumpSumReturns[key] : dca.periodReturns[key],
minReturn: isLumpSum
@@ -557,10 +562,10 @@ function createPeriodSection({ dca, lookback, returns }) {
stack: isLumpSum ? dca.periodLumpSumStack[key] : dca.periodStack[key],
});
/** @param {LongPeriodKey} key @returns {LongEntryItem} */
const buildLongEntry = (key) =>
/** @param {LongPeriodKey} key @param {number} i @returns {LongEntryItem} */
const buildLongEntry = (key, i) =>
withCagr(
buildBaseEntry(key),
buildBaseEntry(key, i),
isLumpSum ? returns.cagr[key] : dca.periodCagr[key],
);
@@ -578,8 +583,10 @@ function createPeriodSection({ dca, lookback, returns }) {
titlePrefix: `${entry.name} ${suffix}`,
});
const shortEntries = SHORT_PERIODS.map(buildBaseEntry);
const longEntries = LONG_PERIODS.map(buildLongEntry);
const shortEntries = SHORT_PERIODS.map((key, i) => buildBaseEntry(key, i));
const longEntries = LONG_PERIODS.map((key, i) =>
buildLongEntry(key, SHORT_PERIODS.length + i),
);
return {
name: `${suffix} by Period`,
@@ -651,8 +658,12 @@ export function createDcaByStartYearSection({ dca }) {
],
});
const entries2020s = YEARS_2020S.map((year) => buildYearEntry(dca, year));
const entries2010s = YEARS_2010S.map((year) => buildYearEntry(dca, year));
const entries2020s = YEARS_2020S.map((year, i) =>
buildYearEntry(dca, year, i),
);
const entries2010s = YEARS_2010S.map((year, i) =>
buildYearEntry(dca, year, YEARS_2020S.length + i),
);
return {
name: "DCA by Start Year",

View File

@@ -5,7 +5,7 @@ import { brk } from "../client.js";
import { includes } from "../utils/array.js";
import { Unit } from "../utils/units.js";
import { priceLine, priceLines } from "./constants.js";
import { baseline, histogram, line, price } from "./series.js";
import { baseline, candlestick, histogram, line, price } from "./series.js";
import { createPriceRatioCharts } from "./shared.js";
import { periodIdToName } from "./utils.js";
@@ -184,7 +184,7 @@ function historicalSubSection(name, periods) {
* @returns {PartialOptionsGroup}
*/
export function createMarketSection() {
const { market, supply, price: priceMetrics } = brk.metrics;
const { market, supply, distribution, price: priceMetrics } = brk.metrics;
const {
movingAverage: ma,
ath,
@@ -195,53 +195,28 @@ export function createMarketSection() {
lookback,
} = market;
/** @type {Period[]} */
const shortPeriods = [
{
id: "1d",
color: colors.returns._1d,
returns: returns.priceReturns._1d,
lookback: lookback._1d,
},
{
id: "1w",
color: colors.returns._1w,
returns: returns.priceReturns._1w,
lookback: lookback._1w,
},
{
id: "1m",
color: colors.returns._1m,
returns: returns.priceReturns._1m,
lookback: lookback._1m,
},
const shortPeriodsBase = [
{ id: "1d", returns: returns.priceReturns._1d, lookback: lookback._1d },
{ id: "1w", returns: returns.priceReturns._1w, lookback: lookback._1w },
{ id: "1m", returns: returns.priceReturns._1m, lookback: lookback._1m },
{
id: "3m",
color: colors.returns._3m,
returns: returns.priceReturns._3m,
lookback: lookback._3m,
defaultActive: false,
},
{
id: "6m",
color: colors.returns._6m,
returns: returns.priceReturns._6m,
lookback: lookback._6m,
defaultActive: false,
},
{
id: "1y",
color: colors.returns._1y,
returns: returns.priceReturns._1y,
lookback: lookback._1y,
},
{ id: "1y", returns: returns.priceReturns._1y, lookback: lookback._1y },
];
/** @type {PeriodWithCagr[]} */
const longPeriods = [
const longPeriodsBase = [
{
id: "2y",
color: colors.returns._2y,
returns: returns.priceReturns._2y,
cagr: returns.cagr._2y,
lookback: lookback._2y,
@@ -249,7 +224,6 @@ export function createMarketSection() {
},
{
id: "3y",
color: colors.returns._3y,
returns: returns.priceReturns._3y,
cagr: returns.cagr._3y,
lookback: lookback._3y,
@@ -257,14 +231,12 @@ export function createMarketSection() {
},
{
id: "4y",
color: colors.returns._4y,
returns: returns.priceReturns._4y,
cagr: returns.cagr._4y,
lookback: lookback._4y,
},
{
id: "5y",
color: colors.returns._5y,
returns: returns.priceReturns._5y,
cagr: returns.cagr._5y,
lookback: lookback._5y,
@@ -272,7 +244,6 @@ export function createMarketSection() {
},
{
id: "6y",
color: colors.returns._6y,
returns: returns.priceReturns._6y,
cagr: returns.cagr._6y,
lookback: lookback._6y,
@@ -280,7 +251,6 @@ export function createMarketSection() {
},
{
id: "8y",
color: colors.returns._8y,
returns: returns.priceReturns._8y,
cagr: returns.cagr._8y,
lookback: lookback._8y,
@@ -288,7 +258,6 @@ export function createMarketSection() {
},
{
id: "10y",
color: colors.returns._10y,
returns: returns.priceReturns._10y,
cagr: returns.cagr._10y,
lookback: lookback._10y,
@@ -296,96 +265,117 @@ export function createMarketSection() {
},
];
const totalReturnPeriods =
shortPeriodsBase.length + longPeriodsBase.length;
/** @type {Period[]} */
const shortPeriods = shortPeriodsBase.map((p, i) => ({
...p,
color: colors.at(i, totalReturnPeriods),
}));
/** @type {PeriodWithCagr[]} */
const longPeriods = longPeriodsBase.map((p, i) => ({
...p,
color: colors.at(shortPeriodsBase.length + i, totalReturnPeriods),
}));
/** @type {MaPeriod[]} */
const sma = [
{ id: "1w", color: colors.ma._1w, ratio: ma.price1wSma },
{ id: "8d", color: colors.ma._8d, ratio: ma.price8dSma },
{ id: "13d", color: colors.ma._13d, ratio: ma.price13dSma },
{ id: "21d", color: colors.ma._21d, ratio: ma.price21dSma },
{ id: "1m", color: colors.ma._1m, ratio: ma.price1mSma },
{ id: "34d", color: colors.ma._34d, ratio: ma.price34dSma },
{ id: "55d", color: colors.ma._55d, ratio: ma.price55dSma },
{ id: "89d", color: colors.ma._89d, ratio: ma.price89dSma },
{ id: "111d", color: colors.ma._111d, ratio: ma.price111dSma },
{ id: "144d", color: colors.ma._144d, ratio: ma.price144dSma },
{ id: "200d", color: colors.ma._200d, ratio: ma.price200dSma },
{ id: "350d", color: colors.ma._350d, ratio: ma.price350dSma },
{ id: "1y", color: colors.ma._1y, ratio: ma.price1ySma },
{ id: "2y", color: colors.ma._2y, ratio: ma.price2ySma },
{ id: "200w", color: colors.ma._200w, ratio: ma.price200wSma },
{ id: "4y", color: colors.ma._4y, ratio: ma.price4ySma },
];
{ id: "1w", ratio: ma.price1wSma },
{ id: "8d", ratio: ma.price8dSma },
{ id: "13d", ratio: ma.price13dSma },
{ id: "21d", ratio: ma.price21dSma },
{ id: "1m", ratio: ma.price1mSma },
{ id: "34d", ratio: ma.price34dSma },
{ id: "55d", ratio: ma.price55dSma },
{ id: "89d", ratio: ma.price89dSma },
{ id: "111d", ratio: ma.price111dSma },
{ id: "144d", ratio: ma.price144dSma },
{ id: "200d", ratio: ma.price200dSma },
{ id: "350d", ratio: ma.price350dSma },
{ id: "1y", ratio: ma.price1ySma },
{ id: "2y", ratio: ma.price2ySma },
{ id: "200w", ratio: ma.price200wSma },
{ id: "4y", ratio: ma.price4ySma },
].map((p, i, arr) => ({ ...p, color: colors.at(i, arr.length) }));
/** @type {MaPeriod[]} */
const ema = [
{ id: "1w", color: colors.ma._1w, ratio: ma.price1wEma },
{ id: "8d", color: colors.ma._8d, ratio: ma.price8dEma },
{ id: "12d", color: colors.ma._12d, ratio: ma.price12dEma },
{ id: "13d", color: colors.ma._13d, ratio: ma.price13dEma },
{ id: "21d", color: colors.ma._21d, ratio: ma.price21dEma },
{ id: "26d", color: colors.ma._26d, ratio: ma.price26dEma },
{ id: "1m", color: colors.ma._1m, ratio: ma.price1mEma },
{ id: "34d", color: colors.ma._34d, ratio: ma.price34dEma },
{ id: "55d", color: colors.ma._55d, ratio: ma.price55dEma },
{ id: "89d", color: colors.ma._89d, ratio: ma.price89dEma },
{ id: "144d", color: colors.ma._144d, ratio: ma.price144dEma },
{ id: "200d", color: colors.ma._200d, ratio: ma.price200dEma },
{ id: "1y", color: colors.ma._1y, ratio: ma.price1yEma },
{ id: "2y", color: colors.ma._2y, ratio: ma.price2yEma },
{ id: "200w", color: colors.ma._200w, ratio: ma.price200wEma },
{ id: "4y", color: colors.ma._4y, ratio: ma.price4yEma },
];
{ id: "1w", ratio: ma.price1wEma },
{ id: "8d", ratio: ma.price8dEma },
{ id: "12d", ratio: ma.price12dEma },
{ id: "13d", ratio: ma.price13dEma },
{ id: "21d", ratio: ma.price21dEma },
{ id: "26d", ratio: ma.price26dEma },
{ id: "1m", ratio: ma.price1mEma },
{ id: "34d", ratio: ma.price34dEma },
{ id: "55d", ratio: ma.price55dEma },
{ id: "89d", ratio: ma.price89dEma },
{ id: "144d", ratio: ma.price144dEma },
{ id: "200d", ratio: ma.price200dEma },
{ id: "1y", ratio: ma.price1yEma },
{ id: "2y", ratio: ma.price2yEma },
{ id: "200w", ratio: ma.price200wEma },
{ id: "4y", ratio: ma.price4yEma },
].map((p, i, arr) => ({ ...p, color: colors.at(i, arr.length) }));
// SMA vs EMA comparison periods (common periods only)
const smaVsEma = [
{
id: "1w",
name: "1 Week",
color: colors.ma._1w,
sma: ma.price1wSma,
ema: ma.price1wEma,
},
{
id: "1m",
name: "1 Month",
color: colors.ma._1m,
sma: ma.price1mSma,
ema: ma.price1mEma,
},
{
id: "200d",
name: "200 Day",
color: colors.ma._200d,
sma: ma.price200dSma,
ema: ma.price200dEma,
},
{
id: "1y",
name: "1 Year",
color: colors.ma._1y,
sma: ma.price1ySma,
ema: ma.price1yEma,
},
{
id: "200w",
name: "200 Week",
color: colors.ma._200w,
sma: ma.price200wSma,
ema: ma.price200wEma,
},
{
id: "4y",
name: "4 Year",
color: colors.ma._4y,
sma: ma.price4ySma,
ema: ma.price4yEma,
},
];
].map((p, i, arr) => ({ ...p, color: colors.at(i, arr.length) }));
return {
name: "Market",
tree: [
{ name: "Price", title: "Bitcoin Price" },
{
name: "Oracle",
title: "On-chain Price",
top: [
// @ts-ignore
candlestick({
metric: priceMetrics.oracle.ohlcDollars,
name: "Oracle",
unit: Unit.usd,
}),
],
},
{
name: "Sats/$",
@@ -401,13 +391,53 @@ export function createMarketSection() {
{
name: "Capitalization",
title: "Market Capitalization",
bottom: [
line({
metric: supply.marketCap,
name: "Capitalization",
unit: Unit.usd,
}),
tree: [
{
name: "Market Cap",
title: "Market Capitalization",
bottom: [
line({
metric: supply.marketCap,
name: "Market Cap",
unit: Unit.usd,
}),
],
},
{
name: "Realized Cap",
title: "Realized Capitalization",
bottom: [
line({
metric: distribution.utxoCohorts.all.realized.realizedCap,
name: "Realized Cap",
color: colors.realized,
unit: Unit.usd,
}),
],
},
{
name: "Growth Rate",
title: "Capitalization Growth Rate",
bottom: [
line({
metric: supply.marketCapGrowthRate,
name: "Market Cap",
color: colors.bitcoin,
unit: Unit.percentage,
}),
line({
metric: supply.realizedCapGrowthRate,
name: "Realized Cap",
color: colors.usd,
unit: Unit.percentage,
}),
baseline({
metric: supply.capGrowthRateDiff,
name: "Difference",
unit: Unit.percentage,
}),
],
},
],
},
@@ -632,7 +662,7 @@ export function createMarketSection() {
price({
metric: ma.price200dSma.price,
name: "200d SMA",
color: colors.ma._200d,
color: colors.indicator.main,
}),
price({
metric: ma.price200dSmaX24,

View File

@@ -244,7 +244,7 @@ export function createMiningSection() {
line({
metric: blocks.mining.hashRate2mSma,
name: "2m SMA",
color: colors.ma._2m,
color: colors.indicator.main,
unit: Unit.hashRate,
defaultActive: false,
}),
@@ -677,7 +677,7 @@ export function createMiningSection() {
line({
metric: p.pool._1mDominance,
name: p.name,
color: colors.at(i),
color: colors.at(i, majorPools.length),
unit: Unit.percentage,
}),
),
@@ -689,7 +689,7 @@ export function createMiningSection() {
line({
metric: p.pool._1mBlocksMined,
name: p.name,
color: colors.at(i),
color: colors.at(i, majorPools.length),
unit: Unit.count,
}),
),
@@ -702,7 +702,7 @@ export function createMiningSection() {
source: p.pool.coinbase,
key: "sum",
name: p.name,
color: colors.at(i),
color: colors.at(i, majorPools.length),
}),
),
},
@@ -719,7 +719,7 @@ export function createMiningSection() {
line({
metric: p.pool._1mDominance,
name: p.name,
color: colors.at(i),
color: colors.at(i, antpoolFriends.length),
unit: Unit.percentage,
}),
),
@@ -731,7 +731,7 @@ export function createMiningSection() {
line({
metric: p.pool._1mBlocksMined,
name: p.name,
color: colors.at(i),
color: colors.at(i, antpoolFriends.length),
unit: Unit.count,
}),
),
@@ -744,7 +744,7 @@ export function createMiningSection() {
source: p.pool.coinbase,
key: "sum",
name: p.name,
color: colors.at(i),
color: colors.at(i, antpoolFriends.length),
}),
),
},

View File

@@ -3,6 +3,7 @@
import { colors } from "../utils/colors.js";
import { brk } from "../client.js";
import { Unit } from "../utils/units.js";
import { entries } from "../utils/array.js";
import { priceLine } from "./constants.js";
import {
line,
@@ -375,25 +376,13 @@ export function createNetworkSection() {
});
// Script type groups for Output Counts
const legacyScripts = /** @type {const} */ ([
{ key: "p2pkh", name: "P2PKH", color: st.p2pkh },
{ key: "p2pk33", name: "P2PK33", color: st.p2pk33 },
{ key: "p2pk65", name: "P2PK65", color: st.p2pk65 },
]);
const scriptHashScripts = /** @type {const} */ ([
{ key: "p2sh", name: "P2SH", color: st.p2sh },
{ key: "p2ms", name: "P2MS", color: st.p2ms },
]);
const segwitScripts = /** @type {const} */ ([
{ key: "segwit", name: "All SegWit", color: colors.segwit },
{ key: "p2wsh", name: "P2WSH", color: st.p2wsh },
{ key: "p2wpkh", name: "P2WPKH", color: st.p2wpkh },
]);
const otherScripts = /** @type {const} */ ([
{ key: "opreturn", name: "OP_RETURN", color: st.opreturn },
{ key: "emptyoutput", name: "Empty", color: st.empty },
{ key: "unknownoutput", name: "Unknown", color: st.unknown },
]);
const legacyScripts = legacyAddresses.slice(1); // p2pkh, p2pk33, p2pk65
const scriptHashScripts = [legacyAddresses[0], nonAddressableTypes[0]]; // p2sh, p2ms
const segwitScripts = [
/** @type {const} */ ({ key: "segwit", name: "All SegWit", color: colors.segwit }),
...segwitAddresses,
];
const otherScripts = nonAddressableTypes.slice(1); // opreturn, empty, unknown
/**
* Create Compare charts for a script group
@@ -558,50 +547,28 @@ export function createNetworkSection() {
{
name: "Sum",
title: "Transaction Versions",
bottom: [
line({
metric: transactions.versions.v1.sum,
name: "v1",
color: colors.txVersion.v1,
unit: Unit.count,
}),
line({
metric: transactions.versions.v2.sum,
name: "v2",
color: colors.txVersion.v2,
unit: Unit.count,
}),
line({
metric: transactions.versions.v3.sum,
name: "v3",
color: colors.txVersion.v3,
unit: Unit.count,
}),
],
bottom: entries(transactions.versions).map(
([v, data], i, arr) =>
line({
metric: data.sum,
name: v,
color: colors.at(i, arr.length),
unit: Unit.count,
}),
),
},
{
name: "Cumulative",
title: "Transaction Versions (Total)",
bottom: [
line({
metric: transactions.versions.v1.cumulative,
name: "v1",
color: colors.txVersion.v1,
unit: Unit.count,
}),
line({
metric: transactions.versions.v2.cumulative,
name: "v2",
color: colors.txVersion.v2,
unit: Unit.count,
}),
line({
metric: transactions.versions.v3.cumulative,
name: "v3",
color: colors.txVersion.v3,
unit: Unit.count,
}),
],
bottom: entries(transactions.versions).map(
([v, data], i, arr) =>
line({
metric: data.cumulative,
name: v,
color: colors.at(i, arr.length),
unit: Unit.count,
}),
),
},
],
},
@@ -1248,7 +1215,7 @@ export function createNetworkSection() {
line({
metric: scripts.count.taprootAdoption.cumulative,
name: "Taproot",
color: colors.scriptType.p2tr,
color: taprootAddresses[1].color,
unit: Unit.percentage,
}),
],

View File

@@ -321,14 +321,14 @@ export function sdBandsRatio(sd) {
* @param {AnyRatioPattern} ratio
*/
export function ratioSmas(ratio) {
return /** @type {const} */ ([
{ name: "1w SMA", metric: ratio.ratio1wSma, color: colors.ma._1w },
{ name: "1m SMA", metric: ratio.ratio1mSma, color: colors.ma._1m },
{ name: "1y SMA", metric: ratio.ratio1ySd.sma, color: colors.ma._1y },
{ name: "2y SMA", metric: ratio.ratio2ySd.sma, color: colors.ma._2y },
{ name: "4y SMA", metric: ratio.ratio4ySd.sma, color: colors.ma._4y },
return [
{ name: "1w SMA", metric: ratio.ratio1wSma },
{ name: "1m SMA", metric: ratio.ratio1mSma },
{ name: "1y SMA", metric: ratio.ratio1ySd.sma },
{ name: "2y SMA", metric: ratio.ratio2ySd.sma },
{ name: "4y SMA", metric: ratio.ratio4ySd.sma },
{ name: "All SMA", metric: ratio.ratioSd.sma, color: colors.time.all },
]);
].map((s, i, arr) => ({ color: colors.at(i, arr.length), ...s }));
}
/**
@@ -400,6 +400,13 @@ export function createZScoresFolder({
}) {
const sdPats = sdPatterns(ratio);
const zscorePeriods = [
{ name: "1y", sd: ratio.ratio1ySd },
{ name: "2y", sd: ratio.ratio2ySd },
{ name: "4y", sd: ratio.ratio4ySd },
{ name: "all", sd: ratio.ratioSd, color: colors.time.all },
].map((s, i, arr) => ({ color: colors.at(i, arr.length), ...s }));
return {
name: "Z-Scores",
tree: [
@@ -408,56 +415,24 @@ export function createZScoresFolder({
title: formatTitle("Z-Scores"),
top: [
price({ metric: pricePattern, name: legend, color }),
price({
metric: ratio.ratio1ySd._0sdUsd,
name: "1y 0σ",
color: colors.ma._1y,
defaultActive: false,
}),
price({
metric: ratio.ratio2ySd._0sdUsd,
name: "2y 0σ",
color: colors.ma._2y,
defaultActive: false,
}),
price({
metric: ratio.ratio4ySd._0sdUsd,
name: "4y 0σ",
color: colors.ma._4y,
defaultActive: false,
}),
price({
metric: ratio.ratioSd._0sdUsd,
name: "all 0σ",
color: colors.time.all,
defaultActive: false,
}),
...zscorePeriods.map((p) =>
price({
metric: p.sd._0sdUsd,
name: `${p.name} 0σ`,
color: p.color,
defaultActive: false,
}),
),
],
bottom: [
line({
metric: ratio.ratioSd.zscore,
name: "All",
color: colors.time.all,
unit: Unit.sd,
}),
line({
metric: ratio.ratio4ySd.zscore,
name: "4y",
color: colors.ma._4y,
unit: Unit.sd,
}),
line({
metric: ratio.ratio2ySd.zscore,
name: "2y",
color: colors.ma._2y,
unit: Unit.sd,
}),
line({
metric: ratio.ratio1ySd.zscore,
name: "1y",
color: colors.ma._1y,
unit: Unit.sd,
}),
...zscorePeriods.reverse().map((p) =>
line({
metric: p.sd.zscore,
name: p.name,
color: p.color,
unit: Unit.sd,
}),
),
...priceLines({
unit: Unit.sd,
numbers: [0, 1, -1, 2, -2, 3, -3],