mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-26 02:08:10 -07:00
global: snapshot
This commit is contained in:
@@ -5,7 +5,7 @@ use vecdb::{Rw, StorageMode};
|
|||||||
use crate::internal::{LazyPerBlock, PerBlock, Resolutions, PercentPerBlock};
|
use crate::internal::{LazyPerBlock, PerBlock, Resolutions, PercentPerBlock};
|
||||||
#[derive(Traversable)]
|
#[derive(Traversable)]
|
||||||
pub struct Vecs<M: StorageMode = Rw> {
|
pub struct Vecs<M: StorageMode = Rw> {
|
||||||
pub base: Resolutions<StoredF64>,
|
pub value: Resolutions<StoredF64>,
|
||||||
pub as_hash: LazyPerBlock<StoredF64>,
|
pub as_hash: LazyPerBlock<StoredF64>,
|
||||||
pub adjustment: PercentPerBlock<BasisPointsSigned32, M>,
|
pub adjustment: PercentPerBlock<BasisPointsSigned32, M>,
|
||||||
pub epoch: PerBlock<Epoch, M>,
|
pub epoch: PerBlock<Epoch, M>,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ impl Vecs {
|
|||||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "day3_index", version)?,
|
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> {
|
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "hour1_index", version)?,
|
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> {
|
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "hour12_index", version)?,
|
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> {
|
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "hour4_index", version)?,
|
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> {
|
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "minute10_index", version)?,
|
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> {
|
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "minute30_index", version)?,
|
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 {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "month1_index", version)?,
|
identity: EagerVec::forced_import(db, "month1_index", version)?,
|
||||||
date: EagerVec::forced_import(db, "date", 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 {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "month3_index", version)?,
|
identity: EagerVec::forced_import(db, "month3_index", version)?,
|
||||||
date: EagerVec::forced_import(db, "date", 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 {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "month6_index", version)?,
|
identity: EagerVec::forced_import(db, "month6_index", version)?,
|
||||||
date: EagerVec::forced_import(db, "date", 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 {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "week1_index", version)?,
|
identity: EagerVec::forced_import(db, "week1_index", version)?,
|
||||||
date: EagerVec::forced_import(db, "date", 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 {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "year1_index", version)?,
|
identity: EagerVec::forced_import(db, "year1_index", version)?,
|
||||||
date: EagerVec::forced_import(db, "date", 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 {
|
Ok(Self {
|
||||||
identity: EagerVec::forced_import(db, "year10_index", version)?,
|
identity: EagerVec::forced_import(db, "year10_index", version)?,
|
||||||
date: EagerVec::forced_import(db, "date", 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)]
|
#[derive(Traversable)]
|
||||||
pub struct BlocksVecs<M: StorageMode = Rw> {
|
pub struct BlocksVecs<M: StorageMode = Rw> {
|
||||||
pub blockhash: M::Stored<BytesVec<Height, BlockHash>>,
|
pub blockhash: M::Stored<BytesVec<Height, BlockHash>>,
|
||||||
#[traversable(wrap = "difficulty", rename = "raw")]
|
#[traversable(wrap = "difficulty", rename = "value")]
|
||||||
pub difficulty: M::Stored<PcoVec<Height, StoredF64>>,
|
pub difficulty: M::Stored<PcoVec<Height, StoredF64>>,
|
||||||
/// Doesn't guarantee continuity due to possible reorgs and more generally the nature of mining
|
/// Doesn't guarantee continuity due to possible reorgs and more generally the nature of mining
|
||||||
#[traversable(wrap = "time")]
|
#[traversable(wrap = "time")]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub fn iter_difficulty_epochs(
|
|||||||
|
|
||||||
let epoch_to_height = &computer.indexes.epoch.first_height;
|
let epoch_to_height = &computer.indexes.epoch.first_height;
|
||||||
let epoch_to_timestamp = &computer.blocks.time.timestamp.epoch;
|
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 results = Vec::with_capacity(end_epoch.to_usize() - start_epoch.to_usize() + 1);
|
||||||
let mut prev_difficulty: Option<f64> = None;
|
let mut prev_difficulty: Option<f64> = None;
|
||||||
|
|||||||
@@ -5,20 +5,27 @@ import { brk } from "../client.js";
|
|||||||
import { includes } from "../utils/array.js";
|
import { includes } from "../utils/array.js";
|
||||||
import { Unit } from "../utils/units.js";
|
import { Unit } from "../utils/units.js";
|
||||||
import { priceLine, priceLines } from "./constants.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";
|
import { periodIdToName } from "./utils.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Period
|
* @typedef {Object} Period
|
||||||
* @property {string} id
|
* @property {string} id
|
||||||
* @property {Color} color
|
* @property {Color} color
|
||||||
* @property {AnyMetricPattern} returns
|
* @property {{ percent: AnyMetricPattern, ratio: AnyMetricPattern }} returns
|
||||||
* @property {AnyPricePattern} lookback
|
* @property {AnyPricePattern} lookback
|
||||||
* @property {boolean} [defaultActive]
|
* @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",
|
name: "Drawdown",
|
||||||
title: "ATH Drawdown",
|
title: "ATH Drawdown",
|
||||||
top: [price({ metric: ath.high, name: "ATH" })],
|
top: [price({ metric: ath.high, name: "ATH" })],
|
||||||
bottom: [
|
bottom: percentRatio({
|
||||||
line({
|
pattern: ath.drawdown,
|
||||||
metric: ath.drawdown.percent,
|
name: "Drawdown",
|
||||||
name: "Drawdown",
|
color: colors.loss,
|
||||||
color: colors.loss,
|
}),
|
||||||
unit: Unit.percentage,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Time Since",
|
name: "Time Since",
|
||||||
@@ -535,11 +539,10 @@ export function createMarketSection() {
|
|||||||
name: "Choppiness",
|
name: "Choppiness",
|
||||||
title: "Choppiness Index",
|
title: "Choppiness Index",
|
||||||
bottom: [
|
bottom: [
|
||||||
line({
|
...percentRatio({
|
||||||
metric: range.choppinessIndex2w.percent,
|
pattern: range.choppinessIndex2w,
|
||||||
name: "2w",
|
name: "2w",
|
||||||
color: colors.indicator.main,
|
color: colors.indicator.main,
|
||||||
unit: Unit.index,
|
|
||||||
}),
|
}),
|
||||||
...priceLines({ unit: Unit.index, numbers: [61.8, 38.2] }),
|
...priceLines({ unit: Unit.index, numbers: [61.8, 38.2] }),
|
||||||
],
|
],
|
||||||
@@ -1182,14 +1185,11 @@ export function createMarketSection() {
|
|||||||
{
|
{
|
||||||
name: "Gini",
|
name: "Gini",
|
||||||
title: "Gini Coefficient",
|
title: "Gini Coefficient",
|
||||||
bottom: [
|
bottom: percentRatio({
|
||||||
line({
|
pattern: indicators.gini,
|
||||||
metric: indicators.gini.percent,
|
name: "Gini",
|
||||||
name: "Gini",
|
color: colors.loss,
|
||||||
color: colors.loss,
|
}),
|
||||||
unit: Unit.ratio,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "RHODL Ratio",
|
name: "RHODL Ratio",
|
||||||
|
|||||||
@@ -12,12 +12,15 @@ import {
|
|||||||
fromSupplyPattern,
|
fromSupplyPattern,
|
||||||
chartsFromFullPerBlock,
|
chartsFromFullPerBlock,
|
||||||
chartsFromCount,
|
chartsFromCount,
|
||||||
fromStatsPattern,
|
|
||||||
chartsFromSumPerBlock,
|
chartsFromSumPerBlock,
|
||||||
rollingWindowsTree,
|
rollingWindowsTree,
|
||||||
distributionWindowsTree,
|
distributionWindowsTree,
|
||||||
mapWindows,
|
mapWindows,
|
||||||
ROLLING_WINDOWS,
|
ROLLING_WINDOWS,
|
||||||
|
chartsFromBlockAnd6b,
|
||||||
|
percentRatio,
|
||||||
|
percentRatioDots,
|
||||||
|
rollingPercentRatioTree,
|
||||||
} from "./series.js";
|
} from "./series.js";
|
||||||
import { satsBtcUsd, satsBtcUsdFrom } from "./shared.js";
|
import { satsBtcUsd, satsBtcUsdFrom } from "./shared.js";
|
||||||
|
|
||||||
@@ -236,10 +239,9 @@ export function createNetworkSection() {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
rollingWindowsTree({
|
rollingPercentRatioTree({
|
||||||
windows: mapWindows(addresses.delta[key].rate, (r) => r.ratio),
|
windows: addresses.delta[key].rate,
|
||||||
title: `${titlePrefix}Address Growth Rate`,
|
title: `${titlePrefix}Address Growth Rate`,
|
||||||
unit: Unit.ratio,
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -351,12 +353,11 @@ export function createNetworkSection() {
|
|||||||
tree: ROLLING_WINDOWS.map((w) => ({
|
tree: ROLLING_WINDOWS.map((w) => ({
|
||||||
name: w.name,
|
name: w.name,
|
||||||
title: `${groupName} Address Growth Rate (${w.name})`,
|
title: `${groupName} Address Growth Rate (${w.name})`,
|
||||||
bottom: types.map((t) =>
|
bottom: types.flatMap((t) =>
|
||||||
line({
|
percentRatio({
|
||||||
metric: addresses.delta[t.key].rate[w.key].ratio,
|
pattern: addresses.delta[t.key].rate[w.key],
|
||||||
name: t.name,
|
name: t.name,
|
||||||
color: t.color,
|
color: t.color,
|
||||||
unit: Unit.ratio,
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
})),
|
})),
|
||||||
@@ -465,19 +466,58 @@ export function createNetworkSection() {
|
|||||||
{
|
{
|
||||||
name: "Inflation",
|
name: "Inflation",
|
||||||
title: "Inflation Rate",
|
title: "Inflation Rate",
|
||||||
bottom: [
|
bottom: percentRatioDots({
|
||||||
dots({
|
pattern: supply.inflationRate,
|
||||||
metric: supply.inflationRate.percent,
|
name: "Rate",
|
||||||
name: "Rate",
|
}),
|
||||||
unit: Unit.percentage,
|
},
|
||||||
|
{
|
||||||
|
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",
|
name: "Unspendable",
|
||||||
tree: [
|
tree: [
|
||||||
{
|
{
|
||||||
name: "Sum",
|
name: "Base",
|
||||||
title: "Unspendable Supply",
|
title: "Unspendable Supply",
|
||||||
bottom: satsBtcUsdFrom({
|
bottom: satsBtcUsdFrom({
|
||||||
source: supply.burned.unspendable,
|
source: supply.burned.unspendable,
|
||||||
@@ -485,6 +525,31 @@ export function createNetworkSection() {
|
|||||||
name: "sum",
|
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",
|
name: "Cumulative",
|
||||||
title: "Unspendable Supply (Total)",
|
title: "Unspendable Supply (Total)",
|
||||||
@@ -500,14 +565,45 @@ export function createNetworkSection() {
|
|||||||
name: "OP_RETURN",
|
name: "OP_RETURN",
|
||||||
tree: [
|
tree: [
|
||||||
{
|
{
|
||||||
name: "Sum",
|
name: "Base",
|
||||||
title: "OP_RETURN Burned",
|
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",
|
name: "Cumulative",
|
||||||
title: "OP_RETURN Burned (Total)",
|
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",
|
name: "Fees",
|
||||||
title: "Transaction Fee Rate",
|
tree: [
|
||||||
bottom: fromStatsPattern({
|
{
|
||||||
pattern: transactions.fees.feeRate.block,
|
name: "Fee Rate",
|
||||||
unit: Unit.feeRate,
|
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",
|
name: "Volume",
|
||||||
@@ -553,27 +662,92 @@ export function createNetworkSection() {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Annualized",
|
name: "Sent Rolling",
|
||||||
title: "Annualized Transaction Volume",
|
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({
|
bottom: satsBtcUsd({
|
||||||
pattern: transactions.volume.sentSum.sum._1y,
|
pattern: transactions.volume.sentSum.cumulative,
|
||||||
name: "Annualized",
|
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",
|
name: "Size",
|
||||||
title: "Transaction Size",
|
tree: [
|
||||||
bottom: [
|
{
|
||||||
...fromStatsPattern({
|
name: "Weight",
|
||||||
pattern: transactions.size.weight.block,
|
tree: chartsFromBlockAnd6b({
|
||||||
unit: Unit.wu,
|
pattern: transactions.size.weight,
|
||||||
}),
|
title: "Transaction Weight",
|
||||||
...fromStatsPattern({
|
unit: Unit.wu,
|
||||||
pattern: transactions.size.vsize.block,
|
}),
|
||||||
unit: Unit.vb,
|
},
|
||||||
}),
|
{
|
||||||
|
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",
|
name: "Cumulative",
|
||||||
title: "Transaction Versions (Total)",
|
title: "Transaction Versions (Total)",
|
||||||
@@ -815,12 +1022,33 @@ export function createNetworkSection() {
|
|||||||
{
|
{
|
||||||
name: "Fullness",
|
name: "Fullness",
|
||||||
title: "Block Fullness",
|
title: "Block Fullness",
|
||||||
bottom: [
|
bottom: percentRatioDots({
|
||||||
dots({
|
pattern: blocks.fullness,
|
||||||
metric: blocks.fullness.percent,
|
name: "base",
|
||||||
name: "base",
|
}),
|
||||||
unit: Unit.percentage,
|
},
|
||||||
}),
|
{
|
||||||
|
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) => ({
|
tree: ROLLING_WINDOWS.map((w) => ({
|
||||||
name: w.name,
|
name: w.name,
|
||||||
title: `Address Growth Rate by Type (${w.name})`,
|
title: `Address Growth Rate by Type (${w.name})`,
|
||||||
bottom: addressTypes.map((t) =>
|
bottom: addressTypes.flatMap((t) =>
|
||||||
line({
|
percentRatio({
|
||||||
metric: addresses.delta[t.key].rate[w.key].ratio,
|
pattern: addresses.delta[t.key].rate[w.key],
|
||||||
name: t.name,
|
name: t.name,
|
||||||
color: t.color,
|
color: t.color,
|
||||||
unit: Unit.ratio,
|
|
||||||
defaultActive: t.defaultActive,
|
defaultActive: t.defaultActive,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -1218,12 +1445,24 @@ export function createNetworkSection() {
|
|||||||
color: colors.segwit,
|
color: colors.segwit,
|
||||||
unit: Unit.percentage,
|
unit: Unit.percentage,
|
||||||
}),
|
}),
|
||||||
|
line({
|
||||||
|
metric: scripts.adoption.segwit.ratio,
|
||||||
|
name: "SegWit",
|
||||||
|
color: colors.segwit,
|
||||||
|
unit: Unit.ratio,
|
||||||
|
}),
|
||||||
line({
|
line({
|
||||||
metric: scripts.adoption.taproot.percent,
|
metric: scripts.adoption.taproot.percent,
|
||||||
name: "Taproot",
|
name: "Taproot",
|
||||||
color: taprootAddresses[1].color,
|
color: taprootAddresses[1].color,
|
||||||
unit: Unit.percentage,
|
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",
|
name: "Adoption",
|
||||||
unit: Unit.percentage,
|
unit: Unit.percentage,
|
||||||
}),
|
}),
|
||||||
|
line({
|
||||||
|
metric: scripts.adoption.segwit.ratio,
|
||||||
|
name: "Adoption",
|
||||||
|
unit: Unit.ratio,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1246,6 +1490,11 @@ export function createNetworkSection() {
|
|||||||
name: "Adoption",
|
name: "Adoption",
|
||||||
unit: Unit.percentage,
|
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)
|
// Chart-generating helpers (return PartialOptionsTree for folder structures)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -798,6 +878,29 @@ export function chartsFromSum({
|
|||||||
export const chartsFromSumPerBlock = (args) =>
|
export const chartsFromSumPerBlock = (args) =>
|
||||||
chartsFromSum({ ...args, distributionSuffix: "per Block" });
|
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
|
* Split pattern with rolling sum windows + cumulative into charts
|
||||||
* @param {Object} args
|
* @param {Object} args
|
||||||
@@ -809,6 +912,11 @@ export const chartsFromSumPerBlock = (args) =>
|
|||||||
*/
|
*/
|
||||||
export function chartsFromCount({ pattern, title, unit, color }) {
|
export function chartsFromCount({ pattern, title, unit, color }) {
|
||||||
return [
|
return [
|
||||||
|
{
|
||||||
|
name: "Base",
|
||||||
|
title,
|
||||||
|
bottom: [{ metric: pattern.base, title: "base", color, unit }],
|
||||||
|
},
|
||||||
rollingWindowsTree({ windows: pattern.sum, title, unit }),
|
rollingWindowsTree({ windows: pattern.sum, title, unit }),
|
||||||
{
|
{
|
||||||
name: "Cumulative",
|
name: "Cumulative",
|
||||||
|
|||||||
Reference in New Issue
Block a user