mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -5,7 +5,7 @@ use vecdb::{Rw, StorageMode};
|
||||
use crate::internal::{LazyPerBlock, PerBlock, Resolutions, PercentPerBlock};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub base: Resolutions<StoredF64>,
|
||||
pub value: Resolutions<StoredF64>,
|
||||
pub as_hash: LazyPerBlock<StoredF64>,
|
||||
pub adjustment: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub epoch: PerBlock<Epoch, M>,
|
||||
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "day3_index", version)?,
|
||||
first_height: EagerVec::forced_import(db, "day3_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "hour1_index", version)?,
|
||||
first_height: EagerVec::forced_import(db, "hour1_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "hour12_index", version)?,
|
||||
first_height: EagerVec::forced_import(db, "hour12_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "hour4_index", version)?,
|
||||
first_height: EagerVec::forced_import(db, "hour4_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "minute10_index", version)?,
|
||||
first_height: EagerVec::forced_import(db, "minute10_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "minute30_index", version)?,
|
||||
first_height: EagerVec::forced_import(db, "minute30_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl Vecs {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "month1_index", version)?,
|
||||
date: EagerVec::forced_import(db, "date", version)?,
|
||||
first_height: EagerVec::forced_import(db, "month1_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl Vecs {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "month3_index", version)?,
|
||||
date: EagerVec::forced_import(db, "date", version)?,
|
||||
first_height: EagerVec::forced_import(db, "month3_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl Vecs {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "month6_index", version)?,
|
||||
date: EagerVec::forced_import(db, "date", version)?,
|
||||
first_height: EagerVec::forced_import(db, "month6_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl Vecs {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "week1_index", version)?,
|
||||
date: EagerVec::forced_import(db, "date", version)?,
|
||||
first_height: EagerVec::forced_import(db, "week1_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl Vecs {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "year1_index", version)?,
|
||||
date: EagerVec::forced_import(db, "date", version)?,
|
||||
first_height: EagerVec::forced_import(db, "year1_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ impl Vecs {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "year10_index", version)?,
|
||||
date: EagerVec::forced_import(db, "date", version)?,
|
||||
first_height: EagerVec::forced_import(db, "year10_first_height", version)?,
|
||||
first_height: EagerVec::forced_import(db, "first_height", version)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::parallel_import;
|
||||
#[derive(Traversable)]
|
||||
pub struct BlocksVecs<M: StorageMode = Rw> {
|
||||
pub blockhash: M::Stored<BytesVec<Height, BlockHash>>,
|
||||
#[traversable(wrap = "difficulty", rename = "raw")]
|
||||
#[traversable(wrap = "difficulty", rename = "value")]
|
||||
pub difficulty: M::Stored<PcoVec<Height, StoredF64>>,
|
||||
/// Doesn't guarantee continuity due to possible reorgs and more generally the nature of mining
|
||||
#[traversable(wrap = "time")]
|
||||
|
||||
@@ -23,7 +23,7 @@ pub fn iter_difficulty_epochs(
|
||||
|
||||
let epoch_to_height = &computer.indexes.epoch.first_height;
|
||||
let epoch_to_timestamp = &computer.blocks.time.timestamp.epoch;
|
||||
let epoch_to_difficulty = &computer.blocks.difficulty.base.epoch;
|
||||
let epoch_to_difficulty = &computer.blocks.difficulty.value.epoch;
|
||||
|
||||
let mut results = Vec::with_capacity(end_epoch.to_usize() - start_epoch.to_usize() + 1);
|
||||
let mut prev_difficulty: Option<f64> = None;
|
||||
|
||||
@@ -5,20 +5,27 @@ 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,
|
||||
histogram,
|
||||
line,
|
||||
price,
|
||||
percentRatio,
|
||||
percentRatioBaseline,
|
||||
} from "./series.js";
|
||||
import { periodIdToName } from "./utils.js";
|
||||
|
||||
/**
|
||||
* @typedef {Object} Period
|
||||
* @property {string} id
|
||||
* @property {Color} color
|
||||
* @property {AnyMetricPattern} returns
|
||||
* @property {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} returns
|
||||
* @property {AnyPricePattern} lookback
|
||||
* @property {boolean} [defaultActive]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Period & { cagr: AnyMetricPattern }} PeriodWithCagr
|
||||
* @typedef {Period & { cagr: { percent: AnyMetricPattern, ratio: AnyMetricPattern } }} PeriodWithCagr
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -442,14 +449,11 @@ export function createMarketSection() {
|
||||
name: "Drawdown",
|
||||
title: "ATH Drawdown",
|
||||
top: [price({ metric: ath.high, name: "ATH" })],
|
||||
bottom: [
|
||||
line({
|
||||
metric: ath.drawdown.percent,
|
||||
name: "Drawdown",
|
||||
color: colors.loss,
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
],
|
||||
bottom: percentRatio({
|
||||
pattern: ath.drawdown,
|
||||
name: "Drawdown",
|
||||
color: colors.loss,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Time Since",
|
||||
@@ -535,11 +539,10 @@ export function createMarketSection() {
|
||||
name: "Choppiness",
|
||||
title: "Choppiness Index",
|
||||
bottom: [
|
||||
line({
|
||||
metric: range.choppinessIndex2w.percent,
|
||||
...percentRatio({
|
||||
pattern: range.choppinessIndex2w,
|
||||
name: "2w",
|
||||
color: colors.indicator.main,
|
||||
unit: Unit.index,
|
||||
}),
|
||||
...priceLines({ unit: Unit.index, numbers: [61.8, 38.2] }),
|
||||
],
|
||||
@@ -1182,14 +1185,11 @@ export function createMarketSection() {
|
||||
{
|
||||
name: "Gini",
|
||||
title: "Gini Coefficient",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.gini.percent,
|
||||
name: "Gini",
|
||||
color: colors.loss,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
],
|
||||
bottom: percentRatio({
|
||||
pattern: indicators.gini,
|
||||
name: "Gini",
|
||||
color: colors.loss,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "RHODL Ratio",
|
||||
|
||||
@@ -12,12 +12,15 @@ import {
|
||||
fromSupplyPattern,
|
||||
chartsFromFullPerBlock,
|
||||
chartsFromCount,
|
||||
fromStatsPattern,
|
||||
chartsFromSumPerBlock,
|
||||
rollingWindowsTree,
|
||||
distributionWindowsTree,
|
||||
mapWindows,
|
||||
ROLLING_WINDOWS,
|
||||
chartsFromBlockAnd6b,
|
||||
percentRatio,
|
||||
percentRatioDots,
|
||||
rollingPercentRatioTree,
|
||||
} from "./series.js";
|
||||
import { satsBtcUsd, satsBtcUsdFrom } from "./shared.js";
|
||||
|
||||
@@ -236,10 +239,9 @@ export function createNetworkSection() {
|
||||
}),
|
||||
],
|
||||
},
|
||||
rollingWindowsTree({
|
||||
windows: mapWindows(addresses.delta[key].rate, (r) => r.ratio),
|
||||
rollingPercentRatioTree({
|
||||
windows: addresses.delta[key].rate,
|
||||
title: `${titlePrefix}Address Growth Rate`,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
],
|
||||
},
|
||||
@@ -351,12 +353,11 @@ export function createNetworkSection() {
|
||||
tree: ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `${groupName} Address Growth Rate (${w.name})`,
|
||||
bottom: types.map((t) =>
|
||||
line({
|
||||
metric: addresses.delta[t.key].rate[w.key].ratio,
|
||||
bottom: types.flatMap((t) =>
|
||||
percentRatio({
|
||||
pattern: addresses.delta[t.key].rate[w.key],
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
),
|
||||
})),
|
||||
@@ -465,19 +466,58 @@ export function createNetworkSection() {
|
||||
{
|
||||
name: "Inflation",
|
||||
title: "Inflation Rate",
|
||||
bottom: [
|
||||
dots({
|
||||
metric: supply.inflationRate.percent,
|
||||
name: "Rate",
|
||||
unit: Unit.percentage,
|
||||
bottom: percentRatioDots({
|
||||
pattern: supply.inflationRate,
|
||||
name: "Rate",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Market Cap",
|
||||
tree: [
|
||||
{
|
||||
name: "Base",
|
||||
title: "Market Cap",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.marketCap.usd,
|
||||
name: "Market Cap",
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
],
|
||||
},
|
||||
rollingWindowsTree({
|
||||
windows: mapWindows(
|
||||
supply.marketCap.delta.change,
|
||||
(c) => c.usd,
|
||||
),
|
||||
title: "Market Cap Change",
|
||||
unit: Unit.usd,
|
||||
series: baseline,
|
||||
}),
|
||||
rollingPercentRatioTree({
|
||||
windows: supply.marketCap.delta.rate,
|
||||
title: "Market Cap Growth Rate",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Hodled or Lost",
|
||||
title: "Hodled or Lost Supply",
|
||||
bottom: satsBtcUsd({
|
||||
pattern: supply.hodledOrLost,
|
||||
name: "Supply",
|
||||
}),
|
||||
},
|
||||
rollingWindowsTree({
|
||||
windows: supply.marketMinusRealizedCapGrowthRate,
|
||||
title: "Market - Realized Cap Growth Rate",
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
{
|
||||
name: "Unspendable",
|
||||
tree: [
|
||||
{
|
||||
name: "Sum",
|
||||
name: "Base",
|
||||
title: "Unspendable Supply",
|
||||
bottom: satsBtcUsdFrom({
|
||||
source: supply.burned.unspendable,
|
||||
@@ -485,6 +525,31 @@ export function createNetworkSection() {
|
||||
name: "sum",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: "Unspendable Supply Rolling",
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
satsBtcUsd({
|
||||
pattern: supply.burned.unspendable.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `Unspendable Supply ${w.name}`,
|
||||
bottom: satsBtcUsd({
|
||||
pattern: supply.burned.unspendable.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: "Unspendable Supply (Total)",
|
||||
@@ -500,14 +565,45 @@ export function createNetworkSection() {
|
||||
name: "OP_RETURN",
|
||||
tree: [
|
||||
{
|
||||
name: "Sum",
|
||||
name: "Base",
|
||||
title: "OP_RETURN Burned",
|
||||
bottom: satsBtcUsd({ pattern: scripts.value.opreturn.base, name: "sum" }),
|
||||
bottom: satsBtcUsd({
|
||||
pattern: supply.burned.opreturn.base,
|
||||
name: "sum",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: "OP_RETURN Burned Rolling",
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
satsBtcUsd({
|
||||
pattern: supply.burned.opreturn.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `OP_RETURN Burned ${w.name}`,
|
||||
bottom: satsBtcUsd({
|
||||
pattern: supply.burned.opreturn.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: "OP_RETURN Burned (Total)",
|
||||
bottom: satsBtcUsd({ pattern: scripts.value.opreturn.cumulative, name: "all-time" }),
|
||||
bottom: satsBtcUsd({
|
||||
pattern: supply.burned.opreturn.cumulative,
|
||||
name: "all-time",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -527,12 +623,25 @@ export function createNetworkSection() {
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Fee Rate",
|
||||
title: "Transaction Fee Rate",
|
||||
bottom: fromStatsPattern({
|
||||
pattern: transactions.fees.feeRate.block,
|
||||
unit: Unit.feeRate,
|
||||
}),
|
||||
name: "Fees",
|
||||
tree: [
|
||||
{
|
||||
name: "Fee Rate",
|
||||
tree: chartsFromBlockAnd6b({
|
||||
pattern: transactions.fees.feeRate,
|
||||
title: "Transaction Fee Rate",
|
||||
unit: Unit.feeRate,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Fee",
|
||||
tree: chartsFromBlockAnd6b({
|
||||
pattern: transactions.fees.fee,
|
||||
title: "Transaction Fee",
|
||||
unit: Unit.sats,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Volume",
|
||||
@@ -553,27 +662,92 @@ export function createNetworkSection() {
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Annualized",
|
||||
title: "Annualized Transaction Volume",
|
||||
name: "Sent Rolling",
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: "Sent Volume Rolling",
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
satsBtcUsd({
|
||||
pattern: transactions.volume.sentSum.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `Sent Volume ${w.name}`,
|
||||
bottom: satsBtcUsd({
|
||||
pattern: transactions.volume.sentSum.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sent Cumulative",
|
||||
title: "Sent Volume (Total)",
|
||||
bottom: satsBtcUsd({
|
||||
pattern: transactions.volume.sentSum.sum._1y,
|
||||
name: "Annualized",
|
||||
pattern: transactions.volume.sentSum.cumulative,
|
||||
name: "all-time",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Received Rolling",
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: "Received Volume Rolling",
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
satsBtcUsd({
|
||||
pattern: transactions.volume.receivedSum.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `Received Volume ${w.name}`,
|
||||
bottom: satsBtcUsd({
|
||||
pattern: transactions.volume.receivedSum.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Received Cumulative",
|
||||
title: "Received Volume (Total)",
|
||||
bottom: satsBtcUsd({
|
||||
pattern: transactions.volume.receivedSum.cumulative,
|
||||
name: "all-time",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Size",
|
||||
title: "Transaction Size",
|
||||
bottom: [
|
||||
...fromStatsPattern({
|
||||
pattern: transactions.size.weight.block,
|
||||
unit: Unit.wu,
|
||||
}),
|
||||
...fromStatsPattern({
|
||||
pattern: transactions.size.vsize.block,
|
||||
unit: Unit.vb,
|
||||
}),
|
||||
tree: [
|
||||
{
|
||||
name: "Weight",
|
||||
tree: chartsFromBlockAnd6b({
|
||||
pattern: transactions.size.weight,
|
||||
title: "Transaction Weight",
|
||||
unit: Unit.wu,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "vSize",
|
||||
tree: chartsFromBlockAnd6b({
|
||||
pattern: transactions.size.vsize,
|
||||
title: "Transaction vSize",
|
||||
unit: Unit.vb,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -592,6 +766,39 @@ export function createNetworkSection() {
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: "Transaction Versions Rolling",
|
||||
bottom: entries(transactions.versions).flatMap(
|
||||
([v, data], i, arr) =>
|
||||
ROLLING_WINDOWS.map((w) =>
|
||||
line({
|
||||
metric: data.sum[w.key],
|
||||
name: `${v} ${w.name}`,
|
||||
color: colors.at(i, arr.length),
|
||||
unit: Unit.count,
|
||||
}),
|
||||
),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `Transaction Versions (${w.name})`,
|
||||
bottom: entries(transactions.versions).map(
|
||||
([v, data], i, arr) =>
|
||||
line({
|
||||
metric: data.sum[w.key],
|
||||
name: v,
|
||||
color: colors.at(i, arr.length),
|
||||
unit: Unit.count,
|
||||
}),
|
||||
),
|
||||
})),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: "Transaction Versions (Total)",
|
||||
@@ -815,12 +1022,33 @@ export function createNetworkSection() {
|
||||
{
|
||||
name: "Fullness",
|
||||
title: "Block Fullness",
|
||||
bottom: [
|
||||
dots({
|
||||
metric: blocks.fullness.percent,
|
||||
name: "base",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
bottom: percentRatioDots({
|
||||
pattern: blocks.fullness,
|
||||
name: "base",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Difficulty",
|
||||
tree: [
|
||||
{
|
||||
name: "Base",
|
||||
title: "Mining Difficulty",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.difficulty.base,
|
||||
name: "Difficulty",
|
||||
unit: Unit.count,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Adjustment",
|
||||
title: "Difficulty Adjustment",
|
||||
bottom: percentRatioDots({
|
||||
pattern: blocks.difficulty.adjustment,
|
||||
name: "Adjustment",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -996,12 +1224,11 @@ export function createNetworkSection() {
|
||||
tree: ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `Address Growth Rate by Type (${w.name})`,
|
||||
bottom: addressTypes.map((t) =>
|
||||
line({
|
||||
metric: addresses.delta[t.key].rate[w.key].ratio,
|
||||
bottom: addressTypes.flatMap((t) =>
|
||||
percentRatio({
|
||||
pattern: addresses.delta[t.key].rate[w.key],
|
||||
name: t.name,
|
||||
color: t.color,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: t.defaultActive,
|
||||
}),
|
||||
),
|
||||
@@ -1218,12 +1445,24 @@ export function createNetworkSection() {
|
||||
color: colors.segwit,
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.segwit.ratio,
|
||||
name: "SegWit",
|
||||
color: colors.segwit,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.taproot.percent,
|
||||
name: "Taproot",
|
||||
color: taprootAddresses[1].color,
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.taproot.ratio,
|
||||
name: "Taproot",
|
||||
color: taprootAddresses[1].color,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -1235,6 +1474,11 @@ export function createNetworkSection() {
|
||||
name: "Adoption",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.segwit.ratio,
|
||||
name: "Adoption",
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -1246,6 +1490,11 @@ export function createNetworkSection() {
|
||||
name: "Adoption",
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
line({
|
||||
metric: scripts.adoption.taproot.ratio,
|
||||
name: "Adoption",
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -599,6 +599,86 @@ export function fromSupplyPattern({ pattern, title, color }) {
|
||||
];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Percent + Ratio helpers
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Create percent + ratio series from a BpsPercentRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} args.pattern
|
||||
* @param {string} args.name
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function percentRatio({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
line({ metric: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
line({ metric: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create percent + ratio dots series from a BpsPercentRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} args.pattern
|
||||
* @param {string} args.name
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function percentRatioDots({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
dots({ metric: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
dots({ metric: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create percent + ratio baseline series from a BpsPercentRatioPattern
|
||||
* @param {Object} args
|
||||
* @param {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} args.pattern
|
||||
* @param {string} args.name
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function percentRatioBaseline({ pattern, name, color, defaultActive }) {
|
||||
return [
|
||||
baseline({ metric: pattern.percent, name, color, defaultActive, unit: Unit.percentage }),
|
||||
baseline({ metric: pattern.ratio, name, color, defaultActive, unit: Unit.ratio }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Rolling folder tree where each window is a BpsPercentRatioPattern (percent + ratio)
|
||||
* @param {Object} args
|
||||
* @param {{ _24h: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1w: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1m: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, _1y: { percent: AnyMetricPattern, ratio: AnyMetricPattern } }} args.windows
|
||||
* @param {string} args.title
|
||||
* @param {(args: {pattern: { percent: AnyMetricPattern, ratio: AnyMetricPattern }, name: string, color: Color}) => AnyFetchedSeriesBlueprint[]} [args.series]
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function rollingPercentRatioTree({ windows, title, series = percentRatio }) {
|
||||
return {
|
||||
name: "Rolling",
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: `${title} Rolling`,
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
series({ pattern: windows[w.key], name: w.name, color: w.color }),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `${title} ${w.name}`,
|
||||
bottom: series({ pattern: windows[w.key], name: w.name, color: w.color }),
|
||||
})),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Chart-generating helpers (return PartialOptionsTree for folder structures)
|
||||
// ============================================================================
|
||||
@@ -798,6 +878,29 @@ export function chartsFromSum({
|
||||
export const chartsFromSumPerBlock = (args) =>
|
||||
chartsFromSum({ ...args, distributionSuffix: "per Block" });
|
||||
|
||||
/**
|
||||
* Create Per Block + Per 6 Blocks stats charts from a _6bBlockTxPattern
|
||||
* @param {Object} args
|
||||
* @param {{ block: DistributionStats, _6b: DistributionStats }} args.pattern
|
||||
* @param {string} args.title
|
||||
* @param {Unit} args.unit
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
export function chartsFromBlockAnd6b({ pattern, title, unit }) {
|
||||
return [
|
||||
{
|
||||
name: "Per Block",
|
||||
title: `${title} per Block`,
|
||||
bottom: fromStatsPattern({ pattern: pattern.block, unit }),
|
||||
},
|
||||
{
|
||||
name: "Per 6 Blocks",
|
||||
title: `${title} per 6 Blocks`,
|
||||
bottom: fromStatsPattern({ pattern: pattern._6b, unit }),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Split pattern with rolling sum windows + cumulative into charts
|
||||
* @param {Object} args
|
||||
@@ -809,6 +912,11 @@ export const chartsFromSumPerBlock = (args) =>
|
||||
*/
|
||||
export function chartsFromCount({ pattern, title, unit, color }) {
|
||||
return [
|
||||
{
|
||||
name: "Base",
|
||||
title,
|
||||
bottom: [{ metric: pattern.base, title: "base", color, unit }],
|
||||
},
|
||||
rollingWindowsTree({ windows: pattern.sum, title, unit }),
|
||||
{
|
||||
name: "Cumulative",
|
||||
|
||||
Reference in New Issue
Block a user