mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot part 3
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ use brk_cohort::{
|
||||
};
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Indexes, Sats, Version};
|
||||
use brk_types::{Cents, CentsSquaredSats, Dollars, Height, Indexes, Sats, Version};
|
||||
use rayon::prelude::*;
|
||||
use vecdb::{
|
||||
AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode, WritableVec,
|
||||
@@ -738,15 +738,9 @@ impl UTXOCohorts<Rw> {
|
||||
.min()
|
||||
.unwrap_or_default()
|
||||
.min(Height::from(self.profitability.min_stateful_len()))
|
||||
.min(Height::from(
|
||||
self.all.metrics.realized.min_stateful_len(),
|
||||
))
|
||||
.min(Height::from(
|
||||
self.sth.metrics.realized.min_stateful_len(),
|
||||
))
|
||||
.min(Height::from(
|
||||
self.lth.metrics.realized.min_stateful_len(),
|
||||
))
|
||||
.min(Height::from(self.all.min_stateful_len()))
|
||||
.min(Height::from(self.sth.min_stateful_len()))
|
||||
.min(Height::from(self.lth.min_stateful_len()))
|
||||
}
|
||||
|
||||
/// Import state for all separate cohorts at or before given height.
|
||||
@@ -790,7 +784,7 @@ impl UTXOCohorts<Rw> {
|
||||
|
||||
/// Aggregate RealizedFull fields from age_range states and push to all/sth/lth.
|
||||
/// Called during the block loop after separate cohorts' push_state but before reset.
|
||||
pub(crate) fn push_overlapping_realized_full(&mut self) {
|
||||
pub(crate) fn push_overlapping(&mut self, height_price: Cents) {
|
||||
let Self {
|
||||
all,
|
||||
sth,
|
||||
@@ -805,14 +799,26 @@ impl UTXOCohorts<Rw> {
|
||||
let mut sth_acc = RealizedFullAccum::default();
|
||||
let mut lth_acc = RealizedFullAccum::default();
|
||||
|
||||
for ar in age_range.iter() {
|
||||
if let Some(state) = ar.state.as_ref() {
|
||||
let r = &state.realized;
|
||||
all_acc.add(r);
|
||||
let mut all_icap = (0u128, 0u128);
|
||||
let mut sth_icap = (0u128, 0u128);
|
||||
let mut lth_icap = (0u128, 0u128);
|
||||
|
||||
for ar in age_range.iter_mut() {
|
||||
if let Some(state) = ar.state.as_mut() {
|
||||
all_acc.add(&state.realized);
|
||||
|
||||
let u = state.compute_unrealized_state(height_price);
|
||||
all_icap.0 += u.investor_cap_in_profit_raw;
|
||||
all_icap.1 += u.investor_cap_in_loss_raw;
|
||||
|
||||
if sth_filter.includes(&ar.metrics.filter) {
|
||||
sth_acc.add(r);
|
||||
sth_acc.add(&state.realized);
|
||||
sth_icap.0 += u.investor_cap_in_profit_raw;
|
||||
sth_icap.1 += u.investor_cap_in_loss_raw;
|
||||
} else {
|
||||
lth_acc.add(r);
|
||||
lth_acc.add(&state.realized);
|
||||
lth_icap.0 += u.investor_cap_in_profit_raw;
|
||||
lth_icap.1 += u.investor_cap_in_loss_raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -820,6 +826,13 @@ impl UTXOCohorts<Rw> {
|
||||
all.metrics.realized.push_accum(&all_acc);
|
||||
sth.metrics.realized.push_accum(&sth_acc);
|
||||
lth.metrics.realized.push_accum(<h_acc);
|
||||
|
||||
all.metrics.unrealized.investor_cap_in_profit_raw.push(CentsSquaredSats::new(all_icap.0));
|
||||
all.metrics.unrealized.investor_cap_in_loss_raw.push(CentsSquaredSats::new(all_icap.1));
|
||||
sth.metrics.unrealized.investor_cap_in_profit_raw.push(CentsSquaredSats::new(sth_icap.0));
|
||||
sth.metrics.unrealized.investor_cap_in_loss_raw.push(CentsSquaredSats::new(sth_icap.1));
|
||||
lth.metrics.unrealized.investor_cap_in_profit_raw.push(CentsSquaredSats::new(lth_icap.0));
|
||||
lth.metrics.unrealized.investor_cap_in_loss_raw.push(CentsSquaredSats::new(lth_icap.1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -551,8 +551,8 @@ fn push_cohort_states(
|
||||
},
|
||||
);
|
||||
|
||||
// Phase 2: aggregate age_range realized states → push to overlapping cohorts' RealizedFull
|
||||
utxo_cohorts.push_overlapping_realized_full();
|
||||
// Phase 2: aggregate age_range states → push to overlapping cohorts
|
||||
utxo_cohorts.push_overlapping(height_price);
|
||||
|
||||
// Phase 3: reset per-block values
|
||||
utxo_cohorts
|
||||
|
||||
@@ -50,11 +50,10 @@ impl CohortMetricsBase for AllCohortMetrics {
|
||||
}
|
||||
|
||||
fn min_stateful_len(&self) -> usize {
|
||||
self.supply
|
||||
.min_len()
|
||||
.min(self.outputs.min_len())
|
||||
.min(self.activity.min_len())
|
||||
.min(self.realized.min_stateful_len())
|
||||
// Only check per-block pushed vecs, not aggregated ones (supply, outputs,
|
||||
// activity, realized core, unrealized core are summed from age_range).
|
||||
self.realized
|
||||
.min_stateful_len()
|
||||
.min(self.unrealized.min_stateful_len())
|
||||
.min(self.cost_basis.min_stateful_len())
|
||||
}
|
||||
@@ -138,6 +137,7 @@ impl AllCohortMetrics {
|
||||
|
||||
self.cost_basis.compute_prices(
|
||||
starting_indexes,
|
||||
&prices.spot.cents.height,
|
||||
&self.unrealized.invested_capital.in_profit.cents.height,
|
||||
&self.unrealized.invested_capital.in_loss.cents.height,
|
||||
&self.supply.in_profit.sats.height,
|
||||
|
||||
@@ -47,11 +47,10 @@ impl CohortMetricsBase for ExtendedCohortMetrics {
|
||||
}
|
||||
|
||||
fn min_stateful_len(&self) -> usize {
|
||||
self.supply
|
||||
.min_len()
|
||||
.min(self.outputs.min_len())
|
||||
.min(self.activity.min_len())
|
||||
.min(self.realized.min_stateful_len())
|
||||
// Only check per-block pushed vecs, not aggregated ones (supply, outputs,
|
||||
// activity, realized core, unrealized core are summed from age_range).
|
||||
self.realized
|
||||
.min_stateful_len()
|
||||
.min(self.unrealized.min_stateful_len())
|
||||
.min(self.cost_basis.min_stateful_len())
|
||||
}
|
||||
@@ -116,6 +115,7 @@ impl ExtendedCohortMetrics {
|
||||
|
||||
self.cost_basis.compute_prices(
|
||||
starting_indexes,
|
||||
&prices.spot.cents.height,
|
||||
&self.unrealized.invested_capital.in_profit.cents.height,
|
||||
&self.unrealized.invested_capital.in_loss.cents.height,
|
||||
&self.supply.in_profit.sats.height,
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Cents, Height, Indexes, Sats, Version};
|
||||
use brk_types::CentsSquaredSats;
|
||||
use brk_types::{BasisPoints16, Cents, Height, Indexes, Sats, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::internal::{FiatPerBlock, PerBlock, PercentPerBlock, PercentilesVecs, Price, PERCENTILES_LEN};
|
||||
use crate::internal::{
|
||||
PERCENTILES_LEN, PerBlock, PercentPerBlock, PercentilesVecs, Price,
|
||||
};
|
||||
|
||||
use super::ImportConfig;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct CostBasisSide<M: StorageMode = Rw> {
|
||||
pub per_coin: FiatPerBlock<Cents, M>,
|
||||
pub per_dollar: FiatPerBlock<Cents, M>,
|
||||
pub per_coin: Price<PerBlock<Cents, M>>,
|
||||
pub per_dollar: Price<PerBlock<Cents, M>>,
|
||||
}
|
||||
|
||||
/// Cost basis metrics: min/max + profit/loss splits + percentiles + supply density.
|
||||
@@ -31,12 +33,12 @@ impl CostBasis {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
in_profit: CostBasisSide {
|
||||
per_coin: cfg.import("cost_basis_in_profit_per_coin", Version::ZERO)?,
|
||||
per_dollar: cfg.import("cost_basis_in_profit_per_dollar", Version::ZERO)?,
|
||||
per_coin: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_profit_per_coin"), cfg.version + Version::ONE, cfg.indexes)?,
|
||||
per_dollar: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_profit_per_dollar"), cfg.version + Version::ONE, cfg.indexes)?,
|
||||
},
|
||||
in_loss: CostBasisSide {
|
||||
per_coin: cfg.import("cost_basis_in_loss_per_coin", Version::ZERO)?,
|
||||
per_dollar: cfg.import("cost_basis_in_loss_per_dollar", Version::ZERO)?,
|
||||
per_coin: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_loss_per_coin"), cfg.version + Version::ONE, cfg.indexes)?,
|
||||
per_dollar: Price::forced_import(cfg.db, &cfg.name("cost_basis_in_loss_per_dollar"), cfg.version + Version::ONE, cfg.indexes)?,
|
||||
},
|
||||
min: cfg.import("cost_basis_min", Version::ZERO)?,
|
||||
max: cfg.import("cost_basis_max", Version::ZERO)?,
|
||||
@@ -124,9 +126,11 @@ impl CostBasis {
|
||||
vecs
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compute_prices(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
spot: &impl ReadableVec<Height, Cents>,
|
||||
invested_cap_in_profit: &impl ReadableVec<Height, Cents>,
|
||||
invested_cap_in_loss: &impl ReadableVec<Height, Cents>,
|
||||
supply_in_profit_sats: &impl ReadableVec<Height, Sats>,
|
||||
@@ -135,46 +139,64 @@ impl CostBasis {
|
||||
investor_cap_in_loss_raw: &impl ReadableVec<Height, CentsSquaredSats>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.in_profit.per_coin.cents.height.compute_transform2(
|
||||
self.in_profit.per_coin.cents.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
invested_cap_in_profit,
|
||||
supply_in_profit_sats,
|
||||
|(h, invested_cents, supply_sats, ..)| {
|
||||
spot,
|
||||
|(h, invested_cents, supply_sats, spot, ..)| {
|
||||
let supply = supply_sats.as_u128();
|
||||
if supply == 0 { return (h, Cents::ZERO); }
|
||||
(h, Cents::new((invested_cents.as_u128() * Sats::ONE_BTC_U128 / supply) as u64))
|
||||
if supply == 0 {
|
||||
return (h, spot);
|
||||
}
|
||||
(
|
||||
h,
|
||||
Cents::new((invested_cents.as_u128() * Sats::ONE_BTC_U128 / supply) as u64),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
self.in_loss.per_coin.cents.height.compute_transform2(
|
||||
self.in_loss.per_coin.cents.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
invested_cap_in_loss,
|
||||
supply_in_loss_sats,
|
||||
|(h, invested_cents, supply_sats, ..)| {
|
||||
spot,
|
||||
|(h, invested_cents, supply_sats, spot, ..)| {
|
||||
let supply = supply_sats.as_u128();
|
||||
if supply == 0 { return (h, Cents::ZERO); }
|
||||
(h, Cents::new((invested_cents.as_u128() * Sats::ONE_BTC_U128 / supply) as u64))
|
||||
if supply == 0 {
|
||||
return (h, spot);
|
||||
}
|
||||
(
|
||||
h,
|
||||
Cents::new((invested_cents.as_u128() * Sats::ONE_BTC_U128 / supply) as u64),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
self.in_profit.per_dollar.cents.height.compute_transform2(
|
||||
self.in_profit.per_dollar.cents.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
investor_cap_in_profit_raw,
|
||||
invested_cap_in_profit,
|
||||
|(h, investor_cap, invested_cents, ..)| {
|
||||
spot,
|
||||
|(h, investor_cap, invested_cents, spot, ..)| {
|
||||
let invested_raw = invested_cents.as_u128() * Sats::ONE_BTC_U128;
|
||||
if invested_raw == 0 { return (h, Cents::ZERO); }
|
||||
if invested_raw == 0 {
|
||||
return (h, spot);
|
||||
}
|
||||
(h, Cents::new((investor_cap.inner() / invested_raw) as u64))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
self.in_loss.per_dollar.cents.height.compute_transform2(
|
||||
self.in_loss.per_dollar.cents.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
investor_cap_in_loss_raw,
|
||||
invested_cap_in_loss,
|
||||
|(h, investor_cap, invested_cents, ..)| {
|
||||
spot,
|
||||
|(h, investor_cap, invested_cents, spot, ..)| {
|
||||
let invested_raw = invested_cents.as_u128() * Sats::ONE_BTC_U128;
|
||||
if invested_raw == 0 { return (h, Cents::ZERO); }
|
||||
if invested_raw == 0 {
|
||||
return (h, spot);
|
||||
}
|
||||
(h, Cents::new((investor_cap.inner() / invested_raw) as u64))
|
||||
},
|
||||
exit,
|
||||
|
||||
@@ -127,7 +127,7 @@ impl RealizedFull {
|
||||
|
||||
// Peak regret
|
||||
let peak_regret = RealizedPeakRegret {
|
||||
value: cfg.import("realized_peak_regret", Version::new(2))?,
|
||||
value: cfg.import("realized_peak_regret", Version::new(3))?,
|
||||
to_rcap: cfg.import("realized_peak_regret_to_rcap", Version::new(2))?,
|
||||
};
|
||||
|
||||
|
||||
@@ -33,9 +33,7 @@ pub struct UnrealizedFull<M: StorageMode = Rw> {
|
||||
pub gross_pnl: FiatPerBlock<Cents, M>,
|
||||
pub invested_capital: UnrealizedInvestedCapital<M>,
|
||||
|
||||
#[traversable(hidden)]
|
||||
pub investor_cap_in_profit_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
|
||||
#[traversable(hidden)]
|
||||
pub investor_cap_in_loss_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
|
||||
|
||||
pub sentiment: UnrealizedSentiment<M>,
|
||||
@@ -48,18 +46,20 @@ impl UnrealizedFull {
|
||||
|
||||
let gross_pnl = cfg.import("unrealized_gross_pnl", v0)?;
|
||||
|
||||
let v1 = Version::ONE;
|
||||
|
||||
let invested_capital = UnrealizedInvestedCapital {
|
||||
in_profit: cfg.import("invested_capital_in_profit", v0)?,
|
||||
in_loss: cfg.import("invested_capital_in_loss", v0)?,
|
||||
in_profit: cfg.import("invested_capital_in_profit", v1)?,
|
||||
in_loss: cfg.import("invested_capital_in_loss", v1)?,
|
||||
};
|
||||
|
||||
let investor_cap_in_profit_raw = cfg.import("investor_cap_in_profit_raw", v0)?;
|
||||
let investor_cap_in_loss_raw = cfg.import("investor_cap_in_loss_raw", v0)?;
|
||||
|
||||
let sentiment = UnrealizedSentiment {
|
||||
pain_index: cfg.import("pain_index", v0)?,
|
||||
greed_index: cfg.import("greed_index", v0)?,
|
||||
net: cfg.import("net_sentiment", Version::ONE)?,
|
||||
pain_index: cfg.import("pain_index", v1)?,
|
||||
greed_index: cfg.import("greed_index", v1)?,
|
||||
net: cfg.import("net_sentiment", Version::new(2))?,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
@@ -73,9 +73,10 @@ impl UnrealizedFull {
|
||||
}
|
||||
|
||||
pub(crate) fn min_stateful_len(&self) -> usize {
|
||||
self.inner
|
||||
.min_stateful_len()
|
||||
.min(self.investor_cap_in_profit_raw.len())
|
||||
// Only check per-block pushed vecs (investor_cap_raw).
|
||||
// Core-level vecs (profit/loss) are aggregated from age_range, not stateful.
|
||||
self.investor_cap_in_profit_raw
|
||||
.len()
|
||||
.min(self.investor_cap_in_loss_raw.len())
|
||||
}
|
||||
|
||||
@@ -90,14 +91,8 @@ impl UnrealizedFull {
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
let mut vecs = self.inner.collect_vecs_mut();
|
||||
vecs.push(&mut self.gross_pnl.cents.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.invested_capital.in_profit.cents.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.invested_capital.in_loss.cents.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.investor_cap_in_profit_raw as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.investor_cap_in_loss_raw as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.sentiment.pain_index.cents.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.sentiment.greed_index.cents.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.sentiment.net.cents.height as &mut dyn AnyStoredVec);
|
||||
vecs
|
||||
}
|
||||
|
||||
@@ -120,30 +115,41 @@ impl UnrealizedFull {
|
||||
)?;
|
||||
|
||||
// invested_capital_in_profit = supply_profit_sats × spot / ONE_BTC - unrealized_profit
|
||||
self.invested_capital.in_profit.cents.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
supply_in_profit_sats,
|
||||
&prices.spot.cents.height,
|
||||
&self.inner.basic.profit.cents.height,
|
||||
|(h, supply_sats, spot, profit, ..): (_, Sats, Cents, Cents, _)| {
|
||||
let market_value = supply_sats.as_u128() * spot.as_u128() / Sats::ONE_BTC_U128;
|
||||
(h, Cents::new(market_value.saturating_sub(profit.as_u128()) as u64))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
self.invested_capital
|
||||
.in_profit
|
||||
.cents
|
||||
.height
|
||||
.compute_transform3(
|
||||
starting_indexes.height,
|
||||
supply_in_profit_sats,
|
||||
&prices.spot.cents.height,
|
||||
&self.inner.basic.profit.cents.height,
|
||||
|(h, supply_sats, spot, profit, ..): (_, Sats, Cents, Cents, _)| {
|
||||
let market_value = supply_sats.as_u128() * spot.as_u128() / Sats::ONE_BTC_U128;
|
||||
(
|
||||
h,
|
||||
Cents::new(market_value.saturating_sub(profit.as_u128()) as u64),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// invested_capital_in_loss = supply_loss_sats × spot / ONE_BTC + unrealized_loss
|
||||
self.invested_capital.in_loss.cents.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
supply_in_loss_sats,
|
||||
&prices.spot.cents.height,
|
||||
&self.inner.basic.loss.cents.height,
|
||||
|(h, supply_sats, spot, loss, ..): (_, Sats, Cents, Cents, _)| {
|
||||
let market_value = supply_sats.as_u128() * spot.as_u128() / Sats::ONE_BTC_U128;
|
||||
(h, Cents::new((market_value + loss.as_u128()) as u64))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
self.invested_capital
|
||||
.in_loss
|
||||
.cents
|
||||
.height
|
||||
.compute_transform3(
|
||||
starting_indexes.height,
|
||||
supply_in_loss_sats,
|
||||
&prices.spot.cents.height,
|
||||
&self.inner.basic.loss.cents.height,
|
||||
|(h, supply_sats, spot, loss, ..): (_, Sats, Cents, Cents, _)| {
|
||||
let market_value = supply_sats.as_u128() * spot.as_u128() / Sats::ONE_BTC_U128;
|
||||
(h, Cents::new((market_value + loss.as_u128()) as u64))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -171,7 +177,10 @@ impl UnrealizedFull {
|
||||
}
|
||||
let investor_price = investor_cap.inner() / invested_cap_raw;
|
||||
let spot_u128 = spot.as_u128();
|
||||
(h, Cents::new(spot_u128.saturating_sub(investor_price) as u64))
|
||||
(
|
||||
h,
|
||||
Cents::new(spot_u128.saturating_sub(investor_price) as u64),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
@@ -189,7 +198,10 @@ impl UnrealizedFull {
|
||||
}
|
||||
let investor_price = investor_cap.inner() / invested_cap_raw;
|
||||
let spot_u128 = spot.as_u128();
|
||||
(h, Cents::new(investor_price.saturating_sub(spot_u128) as u64))
|
||||
(
|
||||
h,
|
||||
Cents::new(investor_price.saturating_sub(spot_u128) as u64),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -63,7 +63,7 @@ impl UnrealizedLike for UnrealizedFull {
|
||||
&mut self.inner
|
||||
}
|
||||
fn min_stateful_len(&self) -> usize {
|
||||
self.inner.min_stateful_len()
|
||||
UnrealizedFull::min_stateful_len(self)
|
||||
}
|
||||
#[inline(always)]
|
||||
fn push_state(&mut self, state: &UnrealizedState) {
|
||||
|
||||
@@ -5,7 +5,10 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{AmountPerBlock, CachedWindowStarts, LazyRollingSumsAmountFromHeight, SatsToCents},
|
||||
internal::{
|
||||
AmountPerBlock, CachedWindowStarts, LazyRollingAvgsAmountFromHeight,
|
||||
LazyRollingSumsAmountFromHeight, SatsToCents,
|
||||
},
|
||||
prices,
|
||||
};
|
||||
|
||||
@@ -14,6 +17,7 @@ pub struct AmountPerBlockCumulativeWithSums<M: StorageMode = Rw> {
|
||||
pub base: AmountPerBlock<M>,
|
||||
pub cumulative: AmountPerBlock<M>,
|
||||
pub sum: LazyRollingSumsAmountFromHeight,
|
||||
pub average: LazyRollingAvgsAmountFromHeight,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::TWO;
|
||||
@@ -39,11 +43,20 @@ impl AmountPerBlockCumulativeWithSums {
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let average = LazyRollingAvgsAmountFromHeight::new(
|
||||
&format!("{name}_average"),
|
||||
v,
|
||||
&cumulative.sats.height,
|
||||
&cumulative.cents.height,
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
base,
|
||||
cumulative,
|
||||
sum,
|
||||
average,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
AmountPerBlock, CachedWindowStarts, LazyRollingSumsAmountFromHeight,
|
||||
RollingDistributionAmountPerBlock, SatsToCents, WindowStarts,
|
||||
AmountPerBlock, CachedWindowStarts, LazyRollingAvgsAmountFromHeight,
|
||||
LazyRollingSumsAmountFromHeight, RollingDistributionAmountPerBlock, SatsToCents,
|
||||
WindowStarts,
|
||||
},
|
||||
prices,
|
||||
};
|
||||
@@ -17,8 +18,9 @@ pub struct AmountPerBlockFull<M: StorageMode = Rw> {
|
||||
pub base: AmountPerBlock<M>,
|
||||
pub cumulative: AmountPerBlock<M>,
|
||||
pub sum: LazyRollingSumsAmountFromHeight,
|
||||
pub average: LazyRollingAvgsAmountFromHeight,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: RollingDistributionAmountPerBlock<M>,
|
||||
pub distribution: RollingDistributionAmountPerBlock<M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::TWO;
|
||||
@@ -34,12 +36,8 @@ impl AmountPerBlockFull {
|
||||
let v = version + VERSION;
|
||||
|
||||
let base = AmountPerBlock::forced_import(db, name, v, indexes)?;
|
||||
let cumulative = AmountPerBlock::forced_import(
|
||||
db,
|
||||
&format!("{name}_cumulative"),
|
||||
v,
|
||||
indexes,
|
||||
)?;
|
||||
let cumulative =
|
||||
AmountPerBlock::forced_import(db, &format!("{name}_cumulative"), v, indexes)?;
|
||||
let sum = LazyRollingSumsAmountFromHeight::new(
|
||||
&format!("{name}_sum"),
|
||||
v,
|
||||
@@ -48,14 +46,22 @@ impl AmountPerBlockFull {
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let rolling =
|
||||
RollingDistributionAmountPerBlock::forced_import(db, name, v, indexes)?;
|
||||
let average = LazyRollingAvgsAmountFromHeight::new(
|
||||
&format!("{name}_average"),
|
||||
v,
|
||||
&cumulative.sats.height,
|
||||
&cumulative.cents.height,
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let rolling = RollingDistributionAmountPerBlock::forced_import(db, name, v, indexes)?;
|
||||
|
||||
Ok(Self {
|
||||
base,
|
||||
cumulative,
|
||||
sum,
|
||||
rolling,
|
||||
average,
|
||||
distribution: rolling,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -89,7 +95,7 @@ impl AmountPerBlockFull {
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.cents.height, exit)?;
|
||||
|
||||
self.rolling.compute(
|
||||
self.distribution.compute(
|
||||
max_from,
|
||||
windows,
|
||||
&self.base.sats.height,
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Cents, Dollars, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{DeltaAvg, LazyDeltaVec, LazyVecFrom1, ReadableCloneableVec};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
CachedWindowStarts, CentsUnsignedToDollars, DerivedResolutions, LazyPerBlock,
|
||||
LazyRollingAvgFromHeight, Resolutions, SatsToBitcoin, Windows,
|
||||
},
|
||||
};
|
||||
|
||||
/// Single window slot: lazy rolling average for Amount (sats + btc + cents + usd).
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyRollingAvgAmountFromHeight {
|
||||
pub btc: LazyPerBlock<Bitcoin, Sats>,
|
||||
pub sats: LazyRollingAvgFromHeight<Sats>,
|
||||
pub usd: LazyPerBlock<Dollars, Cents>,
|
||||
pub cents: LazyRollingAvgFromHeight<Cents>,
|
||||
}
|
||||
|
||||
/// Lazy rolling averages for all 4 windows, for Amount (sats + btc + cents + usd).
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct LazyRollingAvgsAmountFromHeight(pub Windows<LazyRollingAvgAmountFromHeight>);
|
||||
|
||||
impl LazyRollingAvgsAmountFromHeight {
|
||||
pub fn new(
|
||||
name: &str,
|
||||
version: Version,
|
||||
cumulative_sats: &(impl ReadableCloneableVec<Height, Sats> + 'static),
|
||||
cumulative_cents: &(impl ReadableCloneableVec<Height, Cents> + 'static),
|
||||
cached_starts: &CachedWindowStarts,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Self {
|
||||
let cum_sats = cumulative_sats.read_only_boxed_clone();
|
||||
let cum_cents = cumulative_cents.read_only_boxed_clone();
|
||||
|
||||
let make_slot = |suffix: &str, cached_start: &vecdb::CachedVec<Height, Height>| {
|
||||
let full_name = format!("{name}_{suffix}");
|
||||
let cached = cached_start.clone();
|
||||
let starts_version = cached.version();
|
||||
|
||||
// Sats lazy rolling avg
|
||||
let sats_avg = LazyDeltaVec::<Height, Sats, Sats, DeltaAvg>::new(
|
||||
&format!("{full_name}_sats"),
|
||||
version,
|
||||
cum_sats.clone(),
|
||||
starts_version,
|
||||
{
|
||||
let cached = cached.clone();
|
||||
move || cached.get()
|
||||
},
|
||||
);
|
||||
let sats_resolutions = Resolutions::forced_import(
|
||||
&format!("{full_name}_sats"),
|
||||
sats_avg.read_only_boxed_clone(),
|
||||
version,
|
||||
indexes,
|
||||
);
|
||||
let sats = LazyRollingAvgFromHeight {
|
||||
height: sats_avg,
|
||||
resolutions: Box::new(sats_resolutions),
|
||||
};
|
||||
|
||||
// Btc lazy from sats
|
||||
let btc = LazyPerBlock {
|
||||
height: LazyVecFrom1::transformed::<SatsToBitcoin>(
|
||||
&full_name,
|
||||
version,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<SatsToBitcoin>(
|
||||
&full_name,
|
||||
version,
|
||||
&sats.resolutions,
|
||||
)),
|
||||
};
|
||||
|
||||
// Cents rolling avg
|
||||
let cents_avg = LazyDeltaVec::<Height, Cents, Cents, DeltaAvg>::new(
|
||||
&format!("{full_name}_cents"),
|
||||
version,
|
||||
cum_cents.clone(),
|
||||
starts_version,
|
||||
move || cached.get(),
|
||||
);
|
||||
let cents_resolutions = Resolutions::forced_import(
|
||||
&format!("{full_name}_cents"),
|
||||
cents_avg.read_only_boxed_clone(),
|
||||
version,
|
||||
indexes,
|
||||
);
|
||||
let cents = LazyRollingAvgFromHeight {
|
||||
height: cents_avg,
|
||||
resolutions: Box::new(cents_resolutions),
|
||||
};
|
||||
|
||||
// Usd lazy from cents
|
||||
let usd = LazyPerBlock {
|
||||
height: LazyVecFrom1::transformed::<CentsUnsignedToDollars>(
|
||||
&format!("{full_name}_usd"),
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<
|
||||
CentsUnsignedToDollars,
|
||||
>(
|
||||
&format!("{full_name}_usd"), version, ¢s.resolutions
|
||||
)),
|
||||
};
|
||||
|
||||
LazyRollingAvgAmountFromHeight {
|
||||
btc,
|
||||
sats,
|
||||
usd,
|
||||
cents,
|
||||
}
|
||||
};
|
||||
|
||||
Self(cached_starts.0.map_with_suffix(make_slot))
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ mod cumulative_sum;
|
||||
mod full;
|
||||
mod lazy;
|
||||
mod lazy_derived_resolutions;
|
||||
mod lazy_rolling_avg;
|
||||
mod lazy_rolling_sum;
|
||||
mod rolling_distribution;
|
||||
mod with_deltas;
|
||||
@@ -14,6 +15,7 @@ pub use cumulative_sum::*;
|
||||
pub use full::*;
|
||||
pub use lazy::*;
|
||||
pub use lazy_derived_resolutions::*;
|
||||
pub use lazy_rolling_avg::*;
|
||||
pub use lazy_rolling_sum::*;
|
||||
pub use rolling_distribution::*;
|
||||
pub use with_deltas::*;
|
||||
|
||||
@@ -9,9 +9,7 @@ use vecdb::{
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
CachedWindowStarts, NumericValue, PerBlock, RollingComplete, WindowStarts,
|
||||
},
|
||||
internal::{CachedWindowStarts, NumericValue, PerBlock, RollingComplete, WindowStarts},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -70,8 +68,7 @@ where
|
||||
f64: From<T>,
|
||||
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
|
||||
{
|
||||
let combined_version =
|
||||
source.version() + first_indexes.version() + count_indexes.version();
|
||||
let combined_version = source.version() + first_indexes.version() + count_indexes.version();
|
||||
|
||||
let mut index = max_from;
|
||||
index = {
|
||||
@@ -121,7 +118,7 @@ where
|
||||
);
|
||||
|
||||
self.sum.height.push(sum_val);
|
||||
cumulative_val = cumulative_val + sum_val;
|
||||
cumulative_val += sum_val;
|
||||
self.cumulative.height.push(cumulative_val);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -17,7 +17,10 @@ use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{CachedWindowStarts, PerBlock, LazyRollingSumsFromHeight, NumericValue},
|
||||
internal::{
|
||||
CachedWindowStarts, LazyRollingAvgsFromHeight, LazyRollingSumsFromHeight, NumericValue,
|
||||
PerBlock,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -29,6 +32,7 @@ where
|
||||
pub base: PerBlock<T, M>,
|
||||
pub cumulative: PerBlock<C, M>,
|
||||
pub sum: LazyRollingSumsFromHeight<C>,
|
||||
pub average: LazyRollingAvgsFromHeight<C>,
|
||||
}
|
||||
|
||||
impl<T, C> PerBlockCumulativeWithSums<T, C>
|
||||
@@ -53,11 +57,19 @@ where
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let average = LazyRollingAvgsFromHeight::new(
|
||||
&format!("{name}_average"),
|
||||
version,
|
||||
&cumulative.height,
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
base,
|
||||
cumulative,
|
||||
sum,
|
||||
average,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ where
|
||||
{
|
||||
pub base: M::Stored<EagerVec<PcoVec<Height, T>>>,
|
||||
#[traversable(hidden)]
|
||||
pub cumulative: M::Stored<EagerVec<PcoVec<Height, f64>>>,
|
||||
pub cumulative: M::Stored<EagerVec<PcoVec<Height, T>>>,
|
||||
#[traversable(flatten)]
|
||||
pub average: LazyRollingAvgsFromHeight<T>,
|
||||
}
|
||||
@@ -38,8 +38,8 @@ where
|
||||
cached_starts: &CachedWindowStarts,
|
||||
) -> Result<Self> {
|
||||
let base: EagerVec<PcoVec<Height, T>> = EagerVec::forced_import(db, name, version)?;
|
||||
let cumulative: EagerVec<PcoVec<Height, f64>> =
|
||||
EagerVec::forced_import(db, &format!("{name}_cumulative"), version)?;
|
||||
let cumulative: EagerVec<PcoVec<Height, T>> =
|
||||
EagerVec::forced_import(db, &format!("{name}_cumulative"), version + Version::ONE)?;
|
||||
let average = LazyRollingAvgsFromHeight::new(
|
||||
&format!("{name}_average"),
|
||||
version + Version::ONE,
|
||||
|
||||
@@ -12,7 +12,7 @@ pub struct LazyRollingAvgFromHeight<T>
|
||||
where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
pub height: LazyDeltaVec<Height, f64, T, DeltaAvg>,
|
||||
pub height: LazyDeltaVec<Height, T, T, DeltaAvg>,
|
||||
#[traversable(flatten)]
|
||||
pub resolutions: Box<Resolutions<T>>,
|
||||
}
|
||||
|
||||
@@ -12,10 +12,11 @@ use crate::{
|
||||
use super::LazyRollingAvgFromHeight;
|
||||
|
||||
/// Lazy rolling averages for all 4 window durations (24h, 1w, 1m, 1y),
|
||||
/// derived from an f64 cumulative vec + cached window starts.
|
||||
/// derived from a cumulative vec + cached window starts.
|
||||
///
|
||||
/// Nothing is stored on disk — all values are computed on-the-fly via
|
||||
/// `LazyDeltaVec<Height, f64, T, DeltaAvg>`: `(cum[h] - cum[start-1]) / (h - start + 1)`.
|
||||
/// `LazyDeltaVec<Height, T, T, DeltaAvg>`: `(cum[h] - cum[start-1]) / (h - start + 1)`.
|
||||
/// T is converted to f64 internally for division, then back to T.
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct LazyRollingAvgsFromHeight<T>(pub Windows<LazyRollingAvgFromHeight<T>>)
|
||||
@@ -29,7 +30,7 @@ where
|
||||
pub fn new(
|
||||
name: &str,
|
||||
version: Version,
|
||||
cumulative: &(impl ReadableCloneableVec<Height, f64> + 'static),
|
||||
cumulative: &(impl ReadableCloneableVec<Height, T> + 'static),
|
||||
cached_starts: &CachedWindowStarts,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Self {
|
||||
@@ -39,7 +40,7 @@ where
|
||||
let full_name = format!("{name}_{suffix}");
|
||||
let cached = cached_start.clone();
|
||||
let starts_version = cached.version();
|
||||
let avg = LazyDeltaVec::<Height, f64, T, DeltaAvg>::new(
|
||||
let avg = LazyDeltaVec::<Height, T, T, DeltaAvg>::new(
|
||||
&full_name,
|
||||
version,
|
||||
cum_source.clone(),
|
||||
|
||||
@@ -10,18 +10,19 @@ use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
CachedWindowStarts, NumericValue, LazyRollingSumsFromHeight, RollingDistribution,
|
||||
WindowStarts,
|
||||
CachedWindowStarts, NumericValue, LazyRollingAvgsFromHeight, LazyRollingSumsFromHeight,
|
||||
RollingDistribution, WindowStarts,
|
||||
},
|
||||
};
|
||||
|
||||
/// Lazy rolling sums + stored rolling distribution (8 stats × 4 windows).
|
||||
/// Lazy rolling sums + lazy rolling averages + stored rolling distribution (7 stats × 4 windows).
|
||||
#[derive(Traversable)]
|
||||
pub struct RollingComplete<T, M: StorageMode = Rw>
|
||||
where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
pub sum: LazyRollingSumsFromHeight<T>,
|
||||
pub average: LazyRollingAvgsFromHeight<T>,
|
||||
#[traversable(flatten)]
|
||||
pub distribution: RollingDistribution<T, M>,
|
||||
}
|
||||
@@ -45,9 +46,20 @@ where
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let average = LazyRollingAvgsFromHeight::new(
|
||||
&format!("{name}_average"),
|
||||
version,
|
||||
cumulative,
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let distribution = RollingDistribution::forced_import(db, name, version, indexes)?;
|
||||
|
||||
Ok(Self { sum, distribution })
|
||||
Ok(Self {
|
||||
sum,
|
||||
average,
|
||||
distribution,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute rolling distribution stats across all 4 windows.
|
||||
|
||||
@@ -6,12 +6,12 @@ use vecdb::{ReadableCloneableVec, UnaryTransform};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
CachedWindowStarts, ComputedVecValue, LazyRollingDistribution, LazyRollingSumsFromHeight,
|
||||
NumericValue, RollingComplete,
|
||||
CachedWindowStarts, ComputedVecValue, LazyRollingAvgsFromHeight,
|
||||
LazyRollingDistribution, LazyRollingSumsFromHeight, NumericValue, RollingComplete,
|
||||
},
|
||||
};
|
||||
|
||||
/// Lazy analog of `RollingComplete<T>`: lazy rolling sums + lazy rolling distribution.
|
||||
/// Lazy analog of `RollingComplete<T>`: lazy rolling sums + lazy rolling averages + lazy rolling distribution.
|
||||
/// Zero stored vecs.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyRollingComplete<T, S1T>
|
||||
@@ -20,6 +20,7 @@ where
|
||||
S1T: ComputedVecValue + JsonSchema,
|
||||
{
|
||||
pub sum: LazyRollingSumsFromHeight<T>,
|
||||
pub average: LazyRollingAvgsFromHeight<T>,
|
||||
#[traversable(flatten)]
|
||||
pub distribution: LazyRollingDistribution<T, S1T>,
|
||||
}
|
||||
@@ -44,11 +45,22 @@ where
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let average = LazyRollingAvgsFromHeight::new(
|
||||
&format!("{name}_average"),
|
||||
version,
|
||||
cumulative,
|
||||
cached_starts,
|
||||
indexes,
|
||||
);
|
||||
let distribution = LazyRollingDistribution::from_rolling_distribution::<F>(
|
||||
name,
|
||||
version,
|
||||
&source.distribution,
|
||||
);
|
||||
Self { sum, distribution }
|
||||
Self {
|
||||
sum,
|
||||
average,
|
||||
distribution,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ impl<T: VecValue> UnaryTransform<T, T> for Identity<T> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct HalveSats;
|
||||
|
||||
impl UnaryTransform<Sats, Sats> for HalveSats {
|
||||
|
||||
@@ -95,7 +95,7 @@ impl Vecs {
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
self.subsidy.compute(prices, starting_indexes.height, exit)?;
|
||||
self.subsidy.compute_rest(starting_indexes.height, prices, exit)?;
|
||||
|
||||
self.unclaimed.base.sats.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
|
||||
@@ -36,7 +36,9 @@ impl Vecs {
|
||||
coinbase: AmountPerBlockCumulativeWithSums::forced_import(
|
||||
db, "coinbase", version, indexes, cached_starts,
|
||||
)?,
|
||||
subsidy: AmountPerBlockCumulative::forced_import(db, "subsidy", version, indexes)?,
|
||||
subsidy: AmountPerBlockCumulativeWithSums::forced_import(
|
||||
db, "subsidy", version, indexes, cached_starts,
|
||||
)?,
|
||||
fees: AmountPerBlockFull::forced_import(db, "fees", version, indexes, cached_starts)?,
|
||||
unclaimed: AmountPerBlockCumulative::forced_import(
|
||||
db,
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::internal::{
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub coinbase: AmountPerBlockCumulativeWithSums<M>,
|
||||
pub subsidy: AmountPerBlockCumulative<M>,
|
||||
pub subsidy: AmountPerBlockCumulativeWithSums<M>,
|
||||
pub fees: AmountPerBlockFull<M>,
|
||||
pub unclaimed: AmountPerBlockCumulative<M>,
|
||||
#[traversable(wrap = "fees", rename = "dominance")]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2292,38 +2292,14 @@ class AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern:
|
||||
self.pct90: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, _m(acc, 'pct90'))
|
||||
self.sum: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, _m(acc, 'sum'))
|
||||
|
||||
class AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2:
|
||||
class GrossInvestedInvestorLossNetNuplProfitSentimentPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.average: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'average'))
|
||||
self.max: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'max'))
|
||||
self.median: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'median'))
|
||||
self.min: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'min'))
|
||||
self.pct10: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct10'))
|
||||
self.pct25: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct25'))
|
||||
self.pct75: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct75'))
|
||||
self.pct90: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct90'))
|
||||
pass
|
||||
|
||||
class BpsCentsPercentilesRatioSatsSmaStdUsdPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.average: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'average'))
|
||||
self.max: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'max'))
|
||||
self.median: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'median'))
|
||||
self.min: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'min'))
|
||||
self.pct10: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct10'))
|
||||
self.pct25: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct25'))
|
||||
self.pct75: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct75'))
|
||||
self.pct90: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct90'))
|
||||
|
||||
class _10y2y3y4y5y6y8yPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2360,13 +2336,39 @@ class CapLossMvrvNetPriceProfitSoprPattern:
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, 'mvrv'))
|
||||
self.net_pnl: BaseCumulativeDeltaSumPattern = BaseCumulativeDeltaSumPattern(client, _m(acc, 'net_realized_pnl'))
|
||||
self.price: BpsCentsRatioSatsUsdPattern = BpsCentsRatioSatsUsdPattern(client, _m(acc, 'realized_price'))
|
||||
self.profit: BaseCumulativeSumPattern4 = BaseCumulativeSumPattern4(client, _m(acc, 'realized_profit'))
|
||||
self.profit: BaseCumulativeSumPattern = BaseCumulativeSumPattern(client, _m(acc, 'realized_profit'))
|
||||
self.sopr: RatioValuePattern = RatioValuePattern(client, acc)
|
||||
|
||||
class GrossInvestedLossNetNuplProfitSentimentPattern2:
|
||||
class InInvestedMaxMinPercentilesSupplyPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class MaxMedianMinPct10Pct25Pct75Pct90Pattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.max: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'max'))
|
||||
self.median: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'median'))
|
||||
self.min: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'min'))
|
||||
self.pct10: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct10'))
|
||||
self.pct25: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct25'))
|
||||
self.pct75: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct75'))
|
||||
self.pct90: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct90'))
|
||||
|
||||
class MaxMedianMinPct10Pct25Pct75Pct90Pattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.max: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'max'))
|
||||
self.median: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'median'))
|
||||
self.min: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'min'))
|
||||
self.pct10: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct10'))
|
||||
self.pct25: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct25'))
|
||||
self.pct75: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct75'))
|
||||
self.pct90: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'pct90'))
|
||||
|
||||
class _1m1w1y2y4yAllPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2391,6 +2393,18 @@ class ActivityAddrOutputsRealizedSupplyUnrealizedPattern:
|
||||
self.supply: DeltaHalfTotalPattern = DeltaHalfTotalPattern(client, _m(acc, 'supply'))
|
||||
self.unrealized: NuplPattern = NuplPattern(client, _m(acc, 'nupl'))
|
||||
|
||||
class AverageBaseCumulativeInSumPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.average: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'average'))
|
||||
self.base: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, acc)
|
||||
self.cumulative: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'cumulative'))
|
||||
self.in_loss: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, _m(acc, 'in_loss'))
|
||||
self.in_profit: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, _m(acc, 'in_profit'))
|
||||
self.sum: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'sum'))
|
||||
|
||||
class BaseChangeCumulativeDeltaSumToPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2508,17 +2522,6 @@ class ActivityOutputsRealizedSupplyUnrealizedPattern2:
|
||||
self.supply: DeltaHalfTotalPattern = DeltaHalfTotalPattern(client, _m(acc, 'supply'))
|
||||
self.unrealized: NuplPattern = NuplPattern(client, _m(acc, 'nupl'))
|
||||
|
||||
class BaseCumulativeInSumPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.base: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, acc)
|
||||
self.cumulative: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'cumulative'))
|
||||
self.in_loss: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, _m(acc, 'in_loss'))
|
||||
self.in_profit: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, _m(acc, 'in_profit'))
|
||||
self.sum: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'sum'))
|
||||
|
||||
class BaseCumulativeNegativeSumToPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
@@ -2573,10 +2576,10 @@ class CapLossMvrvPriceProfitPattern:
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.cap: CentsDeltaUsdPattern = CentsDeltaUsdPattern(client, _m(acc, 'realized_cap'))
|
||||
self.loss: BaseCumulativeSumPattern4 = BaseCumulativeSumPattern4(client, _m(acc, 'realized_loss'))
|
||||
self.loss: BaseCumulativeSumPattern = BaseCumulativeSumPattern(client, _m(acc, 'realized_loss'))
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, 'mvrv'))
|
||||
self.price: BpsCentsRatioSatsUsdPattern = BpsCentsRatioSatsUsdPattern(client, _m(acc, 'realized_price'))
|
||||
self.profit: BaseCumulativeSumPattern4 = BaseCumulativeSumPattern4(client, _m(acc, 'realized_profit'))
|
||||
self.profit: BaseCumulativeSumPattern = BaseCumulativeSumPattern(client, _m(acc, 'realized_profit'))
|
||||
|
||||
class CentsToUsdPattern4:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -2604,10 +2607,6 @@ class EmaHistogramLineSignalPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class InvestedMaxMinPercentilesSupplyPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class PhsReboundThsPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2694,6 +2693,26 @@ class _1y2y4yAllPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class AverageBaseCumulativeSumPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.average: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, _m(acc, 'average'))
|
||||
self.base: SeriesPattern1[StoredU32] = SeriesPattern1(client, acc)
|
||||
self.cumulative: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'cumulative'))
|
||||
self.sum: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, _m(acc, 'sum'))
|
||||
|
||||
class AverageBaseCumulativeSumPattern3:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.average: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'average'))
|
||||
self.base: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, acc)
|
||||
self.cumulative: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'cumulative'))
|
||||
self.sum: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'sum'))
|
||||
|
||||
class BaseCumulativeDeltaSumPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2788,20 +2807,21 @@ class _1m1w1y24hPattern(Generic[T]):
|
||||
self._1y: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, '1y'))
|
||||
self._24h: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, '24h'))
|
||||
|
||||
class AdjustedRatioValuePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class BaseCumulativeSumPattern3:
|
||||
class AverageBaseCumulativeSumPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.base: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, acc)
|
||||
self.cumulative: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'cumulative'))
|
||||
self.sum: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'sum'))
|
||||
self.average: _1m1w1y24hPattern[T] = _1m1w1y24hPattern(client, _m(acc, 'average'))
|
||||
self.base: SeriesPattern1[T] = SeriesPattern1(client, acc)
|
||||
self.cumulative: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'cumulative'))
|
||||
self.sum: _1m1w1y24hPattern[T] = _1m1w1y24hPattern(client, _m(acc, 'sum'))
|
||||
|
||||
class BaseCumulativeSumPattern4:
|
||||
class AdjustedRatioValuePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class BaseCumulativeSumPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
@@ -2810,23 +2830,14 @@ class BaseCumulativeSumPattern4:
|
||||
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'cumulative'))
|
||||
self.sum: _1m1w1y24hPattern5 = _1m1w1y24hPattern5(client, _m(acc, 'sum'))
|
||||
|
||||
class BaseCumulativeSumPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.base: SeriesPattern1[StoredU32] = SeriesPattern1(client, acc)
|
||||
self.cumulative: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'cumulative'))
|
||||
self.sum: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, _m(acc, 'sum'))
|
||||
|
||||
class BlocksDominanceRewardsPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.blocks_mined: BaseCumulativeSumPattern2 = BaseCumulativeSumPattern2(client, _m(acc, 'blocks_mined'))
|
||||
self.blocks_mined: AverageBaseCumulativeSumPattern2 = AverageBaseCumulativeSumPattern2(client, _m(acc, 'blocks_mined'))
|
||||
self.dominance: _1m1w1y24hBpsPercentRatioPattern = _1m1w1y24hBpsPercentRatioPattern(client, _m(acc, 'dominance'))
|
||||
self.rewards: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, _m(acc, 'rewards'))
|
||||
self.rewards: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, _m(acc, 'rewards'))
|
||||
|
||||
class BpsPercentRatioPattern3:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -2958,19 +2969,10 @@ class _6bBlockTxPattern(Generic[T]):
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self._6b: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern[T] = AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern(client, _m(acc, '6b'))
|
||||
self.block: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern[T] = AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern(client, acc)
|
||||
self._6b: MaxMedianMinPct10Pct25Pct75Pct90Pattern[T] = MaxMedianMinPct10Pct25Pct75Pct90Pattern(client, _m(acc, '6b'))
|
||||
self.block: MaxMedianMinPct10Pct25Pct75Pct90Pattern[T] = MaxMedianMinPct10Pct25Pct75Pct90Pattern(client, acc)
|
||||
self.tx_index: SeriesPattern19[T] = SeriesPattern19(client, acc)
|
||||
|
||||
class BaseCumulativeSumPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.base: SeriesPattern1[T] = SeriesPattern1(client, acc)
|
||||
self.cumulative: SeriesPattern1[T] = SeriesPattern1(client, _m(acc, 'cumulative'))
|
||||
self.sum: _1m1w1y24hPattern[T] = _1m1w1y24hPattern(client, _m(acc, 'sum'))
|
||||
|
||||
class AbsoluteRatePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -3024,7 +3026,7 @@ class BlocksDominancePattern:
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.blocks_mined: BaseCumulativeSumPattern2 = BaseCumulativeSumPattern2(client, _m(acc, 'blocks_mined'))
|
||||
self.blocks_mined: AverageBaseCumulativeSumPattern2 = AverageBaseCumulativeSumPattern2(client, _m(acc, 'blocks_mined'))
|
||||
self.dominance: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'dominance'))
|
||||
|
||||
class BpsRatioPattern2:
|
||||
@@ -3064,8 +3066,8 @@ class CoindaysTransferPattern:
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.coindays_destroyed: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, _m(acc, 'coindays_destroyed'))
|
||||
self.transfer_volume: BaseCumulativeInSumPattern = BaseCumulativeInSumPattern(client, _m(acc, 'transfer_volume'))
|
||||
self.coindays_destroyed: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, _m(acc, 'coindays_destroyed'))
|
||||
self.transfer_volume: AverageBaseCumulativeInSumPattern = AverageBaseCumulativeInSumPattern(client, _m(acc, 'transfer_volume'))
|
||||
|
||||
class InPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -3075,6 +3077,14 @@ class InPattern:
|
||||
self.in_loss: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'loss'))
|
||||
self.in_profit: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'profit'))
|
||||
|
||||
class PerPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.per_coin: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'coin'))
|
||||
self.per_dollar: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'dollar'))
|
||||
|
||||
class PriceRatioPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -3089,7 +3099,7 @@ class RatioValuePattern:
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.ratio: _24hPattern = _24hPattern(client, _m(acc, 'sopr_24h'))
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, _m(acc, 'value_destroyed'))
|
||||
self.value_destroyed: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, _m(acc, 'value_destroyed'))
|
||||
|
||||
class SdSmaPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -3129,7 +3139,7 @@ class TransferPattern:
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.transfer_volume: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, acc)
|
||||
self.transfer_volume: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, acc)
|
||||
|
||||
class UnspentPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -3196,7 +3206,7 @@ class SeriesTree_Blocks_Count:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.target: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, 'block_count_target')
|
||||
self.total: BaseCumulativeSumPattern2 = BaseCumulativeSumPattern2(client, 'block_count')
|
||||
self.total: AverageBaseCumulativeSumPattern2 = AverageBaseCumulativeSumPattern2(client, 'block_count')
|
||||
|
||||
class SeriesTree_Blocks_Lookback:
|
||||
"""Series tree node."""
|
||||
@@ -3305,8 +3315,8 @@ class SeriesTree_Transactions_Size_Weight:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.tx_index: SeriesPattern19[Weight] = SeriesPattern19(client, 'tx_weight')
|
||||
self.block: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2 = AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2(client, 'tx_weight')
|
||||
self._6b: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2 = AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2(client, 'tx_weight_6b')
|
||||
self.block: MaxMedianMinPct10Pct25Pct75Pct90Pattern2 = MaxMedianMinPct10Pct25Pct75Pct90Pattern2(client, 'tx_weight')
|
||||
self._6b: MaxMedianMinPct10Pct25Pct75Pct90Pattern2 = MaxMedianMinPct10Pct25Pct75Pct90Pattern2(client, 'tx_weight_6b')
|
||||
|
||||
class SeriesTree_Transactions_Size:
|
||||
"""Series tree node."""
|
||||
@@ -3328,15 +3338,15 @@ class SeriesTree_Transactions_Versions:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.v1: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'tx_v1')
|
||||
self.v2: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'tx_v2')
|
||||
self.v3: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'tx_v3')
|
||||
self.v1: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'tx_v1')
|
||||
self.v2: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'tx_v2')
|
||||
self.v3: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'tx_v3')
|
||||
|
||||
class SeriesTree_Transactions_Volume:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.transfer_volume: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'transfer_volume_bis')
|
||||
self.transfer_volume: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'transfer_volume_bis')
|
||||
self.tx_per_sec: _1m1w1y24hPattern[StoredF32] = _1m1w1y24hPattern(client, 'tx_per_sec')
|
||||
self.outputs_per_sec: _1m1w1y24hPattern[StoredF32] = _1m1w1y24hPattern(client, 'outputs_per_sec')
|
||||
self.inputs_per_sec: _1m1w1y24hPattern[StoredF32] = _1m1w1y24hPattern(client, 'inputs_per_sec')
|
||||
@@ -3517,15 +3527,15 @@ class SeriesTree_Addrs_New:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.all: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'new_addr_count')
|
||||
self.p2pk65: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2pk65_new_addr_count')
|
||||
self.p2pk33: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2pk33_new_addr_count')
|
||||
self.p2pkh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2pkh_new_addr_count')
|
||||
self.p2sh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2sh_new_addr_count')
|
||||
self.p2wpkh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2wpkh_new_addr_count')
|
||||
self.p2wsh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2wsh_new_addr_count')
|
||||
self.p2tr: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2tr_new_addr_count')
|
||||
self.p2a: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2a_new_addr_count')
|
||||
self.all: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'new_addr_count')
|
||||
self.p2pk65: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2pk65_new_addr_count')
|
||||
self.p2pk33: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2pk33_new_addr_count')
|
||||
self.p2pkh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2pkh_new_addr_count')
|
||||
self.p2sh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2sh_new_addr_count')
|
||||
self.p2wpkh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2wpkh_new_addr_count')
|
||||
self.p2wsh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2wsh_new_addr_count')
|
||||
self.p2tr: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2tr_new_addr_count')
|
||||
self.p2a: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2a_new_addr_count')
|
||||
|
||||
class SeriesTree_Addrs_Delta:
|
||||
"""Series tree node."""
|
||||
@@ -3596,24 +3606,24 @@ class SeriesTree_Scripts_Count:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.p2a: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2a_count')
|
||||
self.p2ms: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2ms_count')
|
||||
self.p2pk33: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2pk33_count')
|
||||
self.p2pk65: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2pk65_count')
|
||||
self.p2pkh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2pkh_count')
|
||||
self.p2sh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2sh_count')
|
||||
self.p2tr: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2tr_count')
|
||||
self.p2wpkh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2wpkh_count')
|
||||
self.p2wsh: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'p2wsh_count')
|
||||
self.op_return: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'op_return_count')
|
||||
self.empty_output: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'empty_output_count')
|
||||
self.unknown_output: BaseCumulativeSumPattern[StoredU64] = BaseCumulativeSumPattern(client, 'unknown_output_count')
|
||||
self.p2a: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2a_count')
|
||||
self.p2ms: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2ms_count')
|
||||
self.p2pk33: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2pk33_count')
|
||||
self.p2pk65: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2pk65_count')
|
||||
self.p2pkh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2pkh_count')
|
||||
self.p2sh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2sh_count')
|
||||
self.p2tr: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2tr_count')
|
||||
self.p2wpkh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2wpkh_count')
|
||||
self.p2wsh: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'p2wsh_count')
|
||||
self.op_return: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'op_return_count')
|
||||
self.empty_output: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'empty_output_count')
|
||||
self.unknown_output: AverageBaseCumulativeSumPattern[StoredU64] = AverageBaseCumulativeSumPattern(client, 'unknown_output_count')
|
||||
|
||||
class SeriesTree_Scripts_Value:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.op_return: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'op_return_value')
|
||||
self.op_return: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'op_return_value')
|
||||
|
||||
class SeriesTree_Scripts:
|
||||
"""Series tree node."""
|
||||
@@ -3670,7 +3680,7 @@ class SeriesTree_Mining_Rewards:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.coinbase: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'coinbase')
|
||||
self.coinbase: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'coinbase')
|
||||
self.subsidy: SeriesTree_Mining_Rewards_Subsidy = SeriesTree_Mining_Rewards_Subsidy(client)
|
||||
self.fees: SeriesTree_Mining_Rewards_Fees = SeriesTree_Mining_Rewards_Fees(client)
|
||||
self.unclaimed: SeriesTree_Mining_Rewards_Unclaimed = SeriesTree_Mining_Rewards_Unclaimed(client)
|
||||
@@ -3719,12 +3729,12 @@ class SeriesTree_Cointime_Activity:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.coinblocks_created: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'coinblocks_created')
|
||||
self.coinblocks_stored: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'coinblocks_stored')
|
||||
self.coinblocks_created: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'coinblocks_created')
|
||||
self.coinblocks_stored: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'coinblocks_stored')
|
||||
self.liveliness: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'liveliness')
|
||||
self.vaultedness: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'vaultedness')
|
||||
self.ratio: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'activity_to_vaultedness')
|
||||
self.coinblocks_destroyed: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'coinblocks_destroyed')
|
||||
self.coinblocks_destroyed: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'coinblocks_destroyed')
|
||||
|
||||
class SeriesTree_Cointime_Supply:
|
||||
"""Series tree node."""
|
||||
@@ -3737,10 +3747,10 @@ class SeriesTree_Cointime_Value:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.destroyed: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'cointime_value_destroyed')
|
||||
self.created: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'cointime_value_created')
|
||||
self.stored: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'cointime_value_stored')
|
||||
self.vocdd: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'vocdd')
|
||||
self.destroyed: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'cointime_value_destroyed')
|
||||
self.created: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'cointime_value_created')
|
||||
self.stored: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'cointime_value_stored')
|
||||
self.vocdd: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'vocdd')
|
||||
|
||||
class SeriesTree_Cointime_Cap:
|
||||
"""Series tree node."""
|
||||
@@ -4677,7 +4687,7 @@ class SeriesTree_Supply:
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.state: SeriesPattern18[SupplyState] = SeriesPattern18(client, 'supply_state')
|
||||
self.circulating: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'circulating_supply')
|
||||
self.burned: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'unspendable_supply')
|
||||
self.burned: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'unspendable_supply')
|
||||
self.inflation_rate: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'inflation_rate')
|
||||
self.velocity: SeriesTree_Supply_Velocity = SeriesTree_Supply_Velocity(client)
|
||||
self.market_cap: CentsDeltaUsdPattern = CentsDeltaUsdPattern(client, 'market_cap')
|
||||
@@ -4698,8 +4708,8 @@ class SeriesTree_Cohorts_Utxo_All_Activity:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.transfer_volume: BaseCumulativeInSumPattern = BaseCumulativeInSumPattern(client, 'transfer_volume')
|
||||
self.coindays_destroyed: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'coindays_destroyed')
|
||||
self.transfer_volume: AverageBaseCumulativeInSumPattern = AverageBaseCumulativeInSumPattern(client, 'transfer_volume')
|
||||
self.coindays_destroyed: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'coindays_destroyed')
|
||||
self.coinyears_destroyed: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'coinyears_destroyed')
|
||||
self.dormancy: _1m1w1y24hPattern[StoredF32] = _1m1w1y24hPattern(client, 'dormancy')
|
||||
|
||||
@@ -4820,14 +4830,14 @@ class SeriesTree_Cohorts_Utxo_All_Realized_Sopr_Adjusted:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'asopr')
|
||||
self.transfer_volume: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'adj_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'adj_value_destroyed')
|
||||
self.transfer_volume: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, 'adj_value_created')
|
||||
self.value_destroyed: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, 'adj_value_destroyed')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_All_Realized_Sopr:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'value_destroyed')
|
||||
self.value_destroyed: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, 'value_destroyed')
|
||||
self.ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'sopr')
|
||||
self.adjusted: SeriesTree_Cohorts_Utxo_All_Realized_Sopr_Adjusted = SeriesTree_Cohorts_Utxo_All_Realized_Sopr_Adjusted(client)
|
||||
|
||||
@@ -4842,7 +4852,7 @@ class SeriesTree_Cohorts_Utxo_All_Realized:
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'mvrv')
|
||||
self.net_pnl: BaseChangeCumulativeDeltaSumToPattern = BaseChangeCumulativeDeltaSumToPattern(client, 'net')
|
||||
self.sopr: SeriesTree_Cohorts_Utxo_All_Realized_Sopr = SeriesTree_Cohorts_Utxo_All_Realized_Sopr(client)
|
||||
self.gross_pnl: BaseCumulativeSumPattern4 = BaseCumulativeSumPattern4(client, 'realized_gross_pnl')
|
||||
self.gross_pnl: BaseCumulativeSumPattern = BaseCumulativeSumPattern(client, 'realized_gross_pnl')
|
||||
self.sell_side_risk_ratio: _1m1w1y24hPattern6 = _1m1w1y24hPattern6(client, 'sell_side_risk_ratio')
|
||||
self.peak_regret: BaseCumulativeSumToPattern = BaseCumulativeSumToPattern(client, 'realized_peak_regret')
|
||||
self.investor: PricePattern = PricePattern(client, 'investor_price')
|
||||
@@ -4852,6 +4862,8 @@ class SeriesTree_Cohorts_Utxo_All_CostBasis:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.in_profit: PerPattern = PerPattern(client, 'cost_basis_in_profit_per')
|
||||
self.in_loss: PerPattern = PerPattern(client, 'cost_basis_in_loss_per')
|
||||
self.min: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'cost_basis_min')
|
||||
self.max: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'cost_basis_max')
|
||||
self.percentiles: Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern = Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern(client, 'cost_basis')
|
||||
@@ -4903,6 +4915,8 @@ class SeriesTree_Cohorts_Utxo_All_Unrealized:
|
||||
self.net_pnl: SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl = SeriesTree_Cohorts_Utxo_All_Unrealized_NetPnl(client)
|
||||
self.gross_pnl: CentsUsdPattern2 = CentsUsdPattern2(client, 'unrealized_gross_pnl')
|
||||
self.invested_capital: InPattern = InPattern(client, 'invested_capital_in')
|
||||
self.investor_cap_in_profit_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'investor_cap_in_profit_raw')
|
||||
self.investor_cap_in_loss_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'investor_cap_in_loss_raw')
|
||||
self.sentiment: SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_All_Unrealized_Sentiment(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_All:
|
||||
@@ -4920,8 +4934,8 @@ class SeriesTree_Cohorts_Utxo_Sth_Activity:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.transfer_volume: BaseCumulativeInSumPattern = BaseCumulativeInSumPattern(client, 'sth_transfer_volume')
|
||||
self.coindays_destroyed: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'sth_coindays_destroyed')
|
||||
self.transfer_volume: AverageBaseCumulativeInSumPattern = AverageBaseCumulativeInSumPattern(client, 'sth_transfer_volume')
|
||||
self.coindays_destroyed: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'sth_coindays_destroyed')
|
||||
self.coinyears_destroyed: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'sth_coinyears_destroyed')
|
||||
self.dormancy: _1m1w1y24hPattern[StoredF32] = _1m1w1y24hPattern(client, 'sth_dormancy')
|
||||
|
||||
@@ -5042,14 +5056,14 @@ class SeriesTree_Cohorts_Utxo_Sth_Realized_Sopr_Adjusted:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'sth_asopr')
|
||||
self.transfer_volume: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'sth_adj_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'sth_adj_value_destroyed')
|
||||
self.transfer_volume: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, 'sth_adj_value_created')
|
||||
self.value_destroyed: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, 'sth_adj_value_destroyed')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Sth_Realized_Sopr:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'sth_value_destroyed')
|
||||
self.value_destroyed: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, 'sth_value_destroyed')
|
||||
self.ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'sth_sopr')
|
||||
self.adjusted: SeriesTree_Cohorts_Utxo_Sth_Realized_Sopr_Adjusted = SeriesTree_Cohorts_Utxo_Sth_Realized_Sopr_Adjusted(client)
|
||||
|
||||
@@ -5064,7 +5078,7 @@ class SeriesTree_Cohorts_Utxo_Sth_Realized:
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'sth_mvrv')
|
||||
self.net_pnl: BaseChangeCumulativeDeltaSumToPattern = BaseChangeCumulativeDeltaSumToPattern(client, 'sth_net')
|
||||
self.sopr: SeriesTree_Cohorts_Utxo_Sth_Realized_Sopr = SeriesTree_Cohorts_Utxo_Sth_Realized_Sopr(client)
|
||||
self.gross_pnl: BaseCumulativeSumPattern4 = BaseCumulativeSumPattern4(client, 'sth_realized_gross_pnl')
|
||||
self.gross_pnl: BaseCumulativeSumPattern = BaseCumulativeSumPattern(client, 'sth_realized_gross_pnl')
|
||||
self.sell_side_risk_ratio: _1m1w1y24hPattern6 = _1m1w1y24hPattern6(client, 'sth_sell_side_risk_ratio')
|
||||
self.peak_regret: BaseCumulativeSumToPattern = BaseCumulativeSumToPattern(client, 'sth_realized_peak_regret')
|
||||
self.investor: PricePattern = PricePattern(client, 'sth_investor_price')
|
||||
@@ -5074,6 +5088,8 @@ class SeriesTree_Cohorts_Utxo_Sth_CostBasis:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.in_profit: PerPattern = PerPattern(client, 'sth_cost_basis_in_profit_per')
|
||||
self.in_loss: PerPattern = PerPattern(client, 'sth_cost_basis_in_loss_per')
|
||||
self.min: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'sth_cost_basis_min')
|
||||
self.max: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'sth_cost_basis_max')
|
||||
self.percentiles: Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern = Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern(client, 'sth_cost_basis')
|
||||
@@ -5098,6 +5114,8 @@ class SeriesTree_Cohorts_Utxo_Sth_Unrealized:
|
||||
self.net_pnl: CentsToUsdPattern3 = CentsToUsdPattern3(client, 'sth_net_unrealized_pnl')
|
||||
self.gross_pnl: CentsUsdPattern2 = CentsUsdPattern2(client, 'sth_unrealized_gross_pnl')
|
||||
self.invested_capital: InPattern = InPattern(client, 'sth_invested_capital_in')
|
||||
self.investor_cap_in_profit_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'sth_investor_cap_in_profit_raw')
|
||||
self.investor_cap_in_loss_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'sth_investor_cap_in_loss_raw')
|
||||
self.sentiment: SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Sth:
|
||||
@@ -5115,8 +5133,8 @@ class SeriesTree_Cohorts_Utxo_Lth_Activity:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.transfer_volume: BaseCumulativeInSumPattern = BaseCumulativeInSumPattern(client, 'lth_transfer_volume')
|
||||
self.coindays_destroyed: BaseCumulativeSumPattern[StoredF64] = BaseCumulativeSumPattern(client, 'lth_coindays_destroyed')
|
||||
self.transfer_volume: AverageBaseCumulativeInSumPattern = AverageBaseCumulativeInSumPattern(client, 'lth_transfer_volume')
|
||||
self.coindays_destroyed: AverageBaseCumulativeSumPattern[StoredF64] = AverageBaseCumulativeSumPattern(client, 'lth_coindays_destroyed')
|
||||
self.coinyears_destroyed: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'lth_coinyears_destroyed')
|
||||
self.dormancy: _1m1w1y24hPattern[StoredF32] = _1m1w1y24hPattern(client, 'lth_dormancy')
|
||||
|
||||
@@ -5236,7 +5254,7 @@ class SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'lth_value_destroyed')
|
||||
self.value_destroyed: AverageBaseCumulativeSumPattern[Cents] = AverageBaseCumulativeSumPattern(client, 'lth_value_destroyed')
|
||||
self.ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'lth_sopr')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Lth_Realized:
|
||||
@@ -5250,7 +5268,7 @@ class SeriesTree_Cohorts_Utxo_Lth_Realized:
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'lth_mvrv')
|
||||
self.net_pnl: BaseChangeCumulativeDeltaSumToPattern = BaseChangeCumulativeDeltaSumToPattern(client, 'lth_net')
|
||||
self.sopr: SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr = SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr(client)
|
||||
self.gross_pnl: BaseCumulativeSumPattern4 = BaseCumulativeSumPattern4(client, 'lth_realized_gross_pnl')
|
||||
self.gross_pnl: BaseCumulativeSumPattern = BaseCumulativeSumPattern(client, 'lth_realized_gross_pnl')
|
||||
self.sell_side_risk_ratio: _1m1w1y24hPattern6 = _1m1w1y24hPattern6(client, 'lth_sell_side_risk_ratio')
|
||||
self.peak_regret: BaseCumulativeSumToPattern = BaseCumulativeSumToPattern(client, 'lth_realized_peak_regret')
|
||||
self.investor: PricePattern = PricePattern(client, 'lth_investor_price')
|
||||
@@ -5260,6 +5278,8 @@ class SeriesTree_Cohorts_Utxo_Lth_CostBasis:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.in_profit: PerPattern = PerPattern(client, 'lth_cost_basis_in_profit_per')
|
||||
self.in_loss: PerPattern = PerPattern(client, 'lth_cost_basis_in_loss_per')
|
||||
self.min: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'lth_cost_basis_min')
|
||||
self.max: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'lth_cost_basis_max')
|
||||
self.percentiles: Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern = Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern(client, 'lth_cost_basis')
|
||||
@@ -5284,6 +5304,8 @@ class SeriesTree_Cohorts_Utxo_Lth_Unrealized:
|
||||
self.net_pnl: CentsToUsdPattern3 = CentsToUsdPattern3(client, 'lth_net_unrealized_pnl')
|
||||
self.gross_pnl: CentsUsdPattern2 = CentsUsdPattern2(client, 'lth_unrealized_gross_pnl')
|
||||
self.invested_capital: InPattern = InPattern(client, 'lth_invested_capital_in')
|
||||
self.investor_cap_in_profit_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'lth_investor_cap_in_profit_raw')
|
||||
self.investor_cap_in_loss_raw: SeriesPattern18[CentsSquaredSats] = SeriesPattern18(client, 'lth_investor_cap_in_loss_raw')
|
||||
self.sentiment: SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Lth:
|
||||
@@ -5549,27 +5571,27 @@ class SeriesTree_Cohorts_Utxo_Matured:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.under_1h: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_under_1h_old_matured_supply')
|
||||
self._1h_to_1d: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_1h_to_1d_old_matured_supply')
|
||||
self._1d_to_1w: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_1d_to_1w_old_matured_supply')
|
||||
self._1w_to_1m: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_1w_to_1m_old_matured_supply')
|
||||
self._1m_to_2m: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_1m_to_2m_old_matured_supply')
|
||||
self._2m_to_3m: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_2m_to_3m_old_matured_supply')
|
||||
self._3m_to_4m: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_3m_to_4m_old_matured_supply')
|
||||
self._4m_to_5m: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_4m_to_5m_old_matured_supply')
|
||||
self._5m_to_6m: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_5m_to_6m_old_matured_supply')
|
||||
self._6m_to_1y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_6m_to_1y_old_matured_supply')
|
||||
self._1y_to_2y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_1y_to_2y_old_matured_supply')
|
||||
self._2y_to_3y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_2y_to_3y_old_matured_supply')
|
||||
self._3y_to_4y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_3y_to_4y_old_matured_supply')
|
||||
self._4y_to_5y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_4y_to_5y_old_matured_supply')
|
||||
self._5y_to_6y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_5y_to_6y_old_matured_supply')
|
||||
self._6y_to_7y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_6y_to_7y_old_matured_supply')
|
||||
self._7y_to_8y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_7y_to_8y_old_matured_supply')
|
||||
self._8y_to_10y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_8y_to_10y_old_matured_supply')
|
||||
self._10y_to_12y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_10y_to_12y_old_matured_supply')
|
||||
self._12y_to_15y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_12y_to_15y_old_matured_supply')
|
||||
self.over_15y: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, 'utxos_over_15y_old_matured_supply')
|
||||
self.under_1h: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_under_1h_old_matured_supply')
|
||||
self._1h_to_1d: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_1h_to_1d_old_matured_supply')
|
||||
self._1d_to_1w: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_1d_to_1w_old_matured_supply')
|
||||
self._1w_to_1m: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_1w_to_1m_old_matured_supply')
|
||||
self._1m_to_2m: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_1m_to_2m_old_matured_supply')
|
||||
self._2m_to_3m: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_2m_to_3m_old_matured_supply')
|
||||
self._3m_to_4m: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_3m_to_4m_old_matured_supply')
|
||||
self._4m_to_5m: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_4m_to_5m_old_matured_supply')
|
||||
self._5m_to_6m: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_5m_to_6m_old_matured_supply')
|
||||
self._6m_to_1y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_6m_to_1y_old_matured_supply')
|
||||
self._1y_to_2y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_1y_to_2y_old_matured_supply')
|
||||
self._2y_to_3y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_2y_to_3y_old_matured_supply')
|
||||
self._3y_to_4y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_3y_to_4y_old_matured_supply')
|
||||
self._4y_to_5y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_4y_to_5y_old_matured_supply')
|
||||
self._5y_to_6y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_5y_to_6y_old_matured_supply')
|
||||
self._6y_to_7y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_6y_to_7y_old_matured_supply')
|
||||
self._7y_to_8y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_7y_to_8y_old_matured_supply')
|
||||
self._8y_to_10y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_8y_to_10y_old_matured_supply')
|
||||
self._10y_to_12y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_10y_to_12y_old_matured_supply')
|
||||
self._12y_to_15y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_12y_to_15y_old_matured_supply')
|
||||
self.over_15y: AverageBaseCumulativeSumPattern3 = AverageBaseCumulativeSumPattern3(client, 'utxos_over_15y_old_matured_supply')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -284,6 +284,7 @@ export function createCointimeSection() {
|
||||
name,
|
||||
color,
|
||||
base: pattern.base,
|
||||
average: pattern.average,
|
||||
rolling: pattern.sum,
|
||||
cumulative: pattern.cumulative,
|
||||
})),
|
||||
@@ -335,6 +336,7 @@ export function createCointimeSection() {
|
||||
name,
|
||||
color,
|
||||
base: pattern.base,
|
||||
average: pattern.average,
|
||||
rolling: pattern.sum,
|
||||
cumulative: pattern.cumulative,
|
||||
})),
|
||||
@@ -342,6 +344,7 @@ export function createCointimeSection() {
|
||||
name: vocdd.name,
|
||||
color: vocdd.color,
|
||||
base: vocdd.pattern.base,
|
||||
average: vocdd.pattern.average,
|
||||
rolling: vocdd.pattern.sum,
|
||||
cumulative: vocdd.pattern.cumulative,
|
||||
},
|
||||
|
||||
@@ -2,18 +2,16 @@
|
||||
* Cost Basis section builders
|
||||
*
|
||||
* Structure:
|
||||
* - Summary: Key stats (avg + median active, quartiles/extremes available)
|
||||
* - By Coin: BTC-weighted percentiles (IQR active: p25, p50, p75)
|
||||
* - By Capital: USD-weighted percentiles (IQR active: p25, p50, p75)
|
||||
* - Supply Density: Cost basis supply density percentage
|
||||
* - Per Coin: sats-weighted (profitability + distribution)
|
||||
* - Per Dollar: value-weighted (profitability + distribution)
|
||||
* - Profitability: cross-cutting (per coin + per dollar on same chart)
|
||||
* - Supply Density: cost basis supply density percentage
|
||||
*
|
||||
* Only for cohorts WITH costBasis (All, STH, LTH)
|
||||
*/
|
||||
|
||||
import { colors } from "../../utils/colors.js";
|
||||
import { entries } from "../../utils/array.js";
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { priceLines } from "../constants.js";
|
||||
import { price, percentRatio } from "../series.js";
|
||||
import { mapCohortsWithAll, flatMapCohortsWithAll } from "../shared.js";
|
||||
|
||||
@@ -24,7 +22,7 @@ const ACTIVE_PCTS = new Set(["pct75", "pct50", "pct25"]);
|
||||
* @param {(name: string) => string} [n]
|
||||
* @returns {FetchedPriceSeriesBlueprint[]}
|
||||
*/
|
||||
function createCorePercentileSeries(p, n = (x) => x) {
|
||||
function percentileSeries(p, n = (x) => x) {
|
||||
return entries(p)
|
||||
.reverse()
|
||||
.map(([key, s], i, arr) =>
|
||||
@@ -37,104 +35,46 @@ function createCorePercentileSeries(p, n = (x) => x) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CohortAll | CohortFull | CohortLongTerm} cohort
|
||||
* @returns {FetchedPriceSeriesBlueprint[]}
|
||||
*/
|
||||
function createSingleSummarySeries(cohort) {
|
||||
const { color, tree } = cohort;
|
||||
const p = tree.costBasis.percentiles;
|
||||
return [
|
||||
price({ series: tree.realized.price, name: "Average", color }),
|
||||
price({
|
||||
series: tree.costBasis.max,
|
||||
name: "Max (p100)",
|
||||
color: colors.stat.max,
|
||||
defaultActive: false,
|
||||
}),
|
||||
price({
|
||||
series: p.pct75,
|
||||
name: "Q3 (p75)",
|
||||
color: colors.stat.pct75,
|
||||
defaultActive: false,
|
||||
}),
|
||||
price({ series: p.pct50, name: "Median (p50)", color: colors.stat.median }),
|
||||
price({
|
||||
series: p.pct25,
|
||||
name: "Q1 (p25)",
|
||||
color: colors.stat.pct25,
|
||||
defaultActive: false,
|
||||
}),
|
||||
price({
|
||||
series: tree.costBasis.min,
|
||||
name: "Min (p0)",
|
||||
color: colors.stat.min,
|
||||
defaultActive: false,
|
||||
}),
|
||||
];
|
||||
}
|
||||
// ============================================================================
|
||||
// Single cohort helpers
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @param {readonly (CohortAll | CohortFull | CohortLongTerm)[]} list
|
||||
* @param {CohortAll} all
|
||||
* @returns {FetchedPriceSeriesBlueprint[]}
|
||||
* Per Coin or Per Dollar folder for a single cohort
|
||||
* @param {Object} args
|
||||
* @param {AnyPricePattern} args.avgPrice - realized price (per coin) or investor price (per dollar)
|
||||
* @param {string} args.avgName
|
||||
* @param {AnyPricePattern} args.inProfit
|
||||
* @param {AnyPricePattern} args.inLoss
|
||||
* @param {PercentilesPattern} args.percentiles
|
||||
* @param {Color} args.color
|
||||
* @param {string} args.weightLabel
|
||||
* @param {(name: string) => string} args.title
|
||||
* @param {AnyPricePattern} [args.min]
|
||||
* @param {AnyPricePattern} [args.max]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function createGroupedSummarySeries(list, all) {
|
||||
return mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ series: tree.realized.price, name, color }),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CohortAll | CohortFull | CohortLongTerm} cohort
|
||||
* @returns {FetchedPriceSeriesBlueprint[]}
|
||||
*/
|
||||
function createSingleByCoinSeries(cohort) {
|
||||
const { color, tree } = cohort;
|
||||
const cb = tree.costBasis;
|
||||
function singleWeightFolder({ avgPrice, avgName, inProfit, inLoss, percentiles, color, weightLabel, title, min, max }) {
|
||||
return [
|
||||
price({ series: tree.realized.price, name: "Average", color }),
|
||||
price({
|
||||
series: cb.max,
|
||||
name: "p100",
|
||||
color: colors.stat.max,
|
||||
defaultActive: false,
|
||||
}),
|
||||
...createCorePercentileSeries(cb.percentiles),
|
||||
price({
|
||||
series: cb.min,
|
||||
name: "p0",
|
||||
color: colors.stat.min,
|
||||
defaultActive: false,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CohortAll | CohortFull | CohortLongTerm} cohort
|
||||
* @returns {FetchedPriceSeriesBlueprint[]}
|
||||
*/
|
||||
function createSingleByCapitalSeries(cohort) {
|
||||
const { color, tree } = cohort;
|
||||
return [
|
||||
price({ series: tree.realized.investor.price, name: "Average", color }),
|
||||
...createCorePercentileSeries(tree.costBasis.investedCapital),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CohortAll | CohortFull | CohortLongTerm} cohort
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function createSingleSupplyDensitySeries(cohort) {
|
||||
const { tree } = cohort;
|
||||
return [
|
||||
...percentRatio({
|
||||
pattern: tree.costBasis.supplyDensity,
|
||||
name: "Supply Density",
|
||||
color: colors.bitcoin,
|
||||
}),
|
||||
...priceLines({ numbers: [100, 50, 0], unit: Unit.percentage }),
|
||||
{
|
||||
name: "Profitability",
|
||||
title: title(`Cost Basis Profitability (${weightLabel})`),
|
||||
top: [
|
||||
price({ series: inProfit, name: "In Profit", color: colors.profit }),
|
||||
price({ series: avgPrice, name: avgName, color }),
|
||||
price({ series: inLoss, name: "In Loss", color: colors.loss }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Distribution",
|
||||
title: title(`Cost Basis Distribution (${weightLabel})`),
|
||||
top: [
|
||||
price({ series: avgPrice, name: avgName, color }),
|
||||
...(max ? [price({ series: max, name: "p100", color: colors.stat.max, defaultActive: false })] : []),
|
||||
...percentileSeries(percentiles),
|
||||
...(min ? [price({ series: min, name: "p0", color: colors.stat.min, defaultActive: false })] : []),
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -143,125 +83,171 @@ function createSingleSupplyDensitySeries(cohort) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createCostBasisSectionWithPercentiles({ cohort, title }) {
|
||||
const { tree, color } = cohort;
|
||||
const cb = tree.costBasis;
|
||||
return {
|
||||
name: "Cost Basis",
|
||||
tree: [
|
||||
{
|
||||
name: "Summary",
|
||||
title: title("Cost Basis Summary"),
|
||||
top: createSingleSummarySeries(cohort),
|
||||
name: "Per Coin",
|
||||
tree: singleWeightFolder({
|
||||
avgPrice: tree.realized.price, avgName: "Average",
|
||||
inProfit: cb.inProfit.perCoin, inLoss: cb.inLoss.perCoin,
|
||||
percentiles: cb.percentiles, color, weightLabel: "BTC-weighted", title,
|
||||
min: cb.min, max: cb.max,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "By Coin",
|
||||
title: title("Cost Basis Distribution (BTC-weighted)"),
|
||||
top: createSingleByCoinSeries(cohort),
|
||||
name: "Per Dollar",
|
||||
tree: singleWeightFolder({
|
||||
avgPrice: tree.realized.investor.price, avgName: "Average",
|
||||
inProfit: cb.inProfit.perDollar, inLoss: cb.inLoss.perDollar,
|
||||
percentiles: cb.investedCapital, color, weightLabel: "USD-weighted", title,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "By Capital",
|
||||
title: title("Cost Basis Distribution (USD-weighted)"),
|
||||
top: createSingleByCapitalSeries(cohort),
|
||||
name: "Profitability",
|
||||
tree: [
|
||||
{
|
||||
name: "In Profit",
|
||||
title: title("Cost Basis In Profit"),
|
||||
top: [
|
||||
price({ series: cb.inProfit.perCoin, name: "Per Coin", color: colors.realized }),
|
||||
price({ series: cb.inProfit.perDollar, name: "Per Dollar", color: colors.investor }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "In Loss",
|
||||
title: title("Cost Basis In Loss"),
|
||||
top: [
|
||||
price({ series: cb.inLoss.perCoin, name: "Per Coin", color: colors.realized }),
|
||||
price({ series: cb.inLoss.perDollar, name: "Per Dollar", color: colors.investor }),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Supply Density",
|
||||
title: title("Cost Basis Supply Density"),
|
||||
bottom: createSingleSupplyDensitySeries(cohort),
|
||||
bottom: percentRatio({ pattern: cb.supplyDensity, name: "Supply Density", color: colors.bitcoin }),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Grouped cohort helpers
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Per Coin or Per Dollar folder for grouped cohorts
|
||||
* @param {Object} args
|
||||
* @param {readonly (CohortAll | CohortFull | CohortLongTerm)[]} args.list
|
||||
* @param {CohortAll} args.all
|
||||
* @param {(c: CohortAll | CohortFull | CohortLongTerm) => AnyPricePattern} args.getAvgPrice
|
||||
* @param {(c: CohortAll | CohortFull | CohortLongTerm) => AnyPricePattern} args.getInProfit
|
||||
* @param {(c: CohortAll | CohortFull | CohortLongTerm) => AnyPricePattern} args.getInLoss
|
||||
* @param {(c: CohortAll | CohortFull | CohortLongTerm) => PercentilesPattern} args.getPercentiles
|
||||
* @param {string} args.avgTitle
|
||||
* @param {string} args.weightLabel
|
||||
* @param {(name: string) => string} args.title
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function groupedWeightFolder({ list, all, getAvgPrice, getInProfit, getInLoss, getPercentiles, avgTitle, weightLabel, title }) {
|
||||
return [
|
||||
{
|
||||
name: "Profitability",
|
||||
tree: [
|
||||
{
|
||||
name: "In Profit",
|
||||
title: title(`Cost Basis In Profit (${weightLabel})`),
|
||||
top: mapCohortsWithAll(list, all, (c) =>
|
||||
price({ series: getInProfit(c), name: c.name, color: c.color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "In Loss",
|
||||
title: title(`Cost Basis In Loss (${weightLabel})`),
|
||||
top: mapCohortsWithAll(list, all, (c) =>
|
||||
price({ series: getInLoss(c), name: c.name, color: c.color }),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Distribution",
|
||||
tree: [
|
||||
{
|
||||
name: "Average",
|
||||
title: title(`${avgTitle} Comparison`),
|
||||
top: mapCohortsWithAll(list, all, (c) =>
|
||||
price({ series: getAvgPrice(c), name: c.name, color: c.color }),
|
||||
),
|
||||
},
|
||||
...(/** @type {const} */ ([
|
||||
["pct50", "Median"],
|
||||
["pct75", "Q3"],
|
||||
["pct25", "Q1"],
|
||||
])).map(([pct, label]) => ({
|
||||
name: label,
|
||||
title: title(`Cost Basis ${label} (${weightLabel})`),
|
||||
top: mapCohortsWithAll(list, all, (c) =>
|
||||
price({ series: getPercentiles(c)[pct], name: c.name, color: c.color }),
|
||||
),
|
||||
})),
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ list: readonly (CohortAll | CohortFull | CohortLongTerm)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedCostBasisSectionWithPercentiles({
|
||||
list,
|
||||
all,
|
||||
title,
|
||||
}) {
|
||||
export function createGroupedCostBasisSectionWithPercentiles({ list, all, title }) {
|
||||
return {
|
||||
name: "Cost Basis",
|
||||
tree: [
|
||||
{
|
||||
name: "Summary",
|
||||
title: title("Cost Basis Summary"),
|
||||
top: createGroupedSummarySeries(list, all),
|
||||
name: "Per Coin",
|
||||
tree: groupedWeightFolder({
|
||||
list, all, title,
|
||||
getAvgPrice: (c) => c.tree.realized.price,
|
||||
getInProfit: (c) => c.tree.costBasis.inProfit.perCoin,
|
||||
getInLoss: (c) => c.tree.costBasis.inLoss.perCoin,
|
||||
getPercentiles: (c) => c.tree.costBasis.percentiles,
|
||||
avgTitle: "Average", weightLabel: "BTC-weighted",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "By Coin",
|
||||
tree: [
|
||||
{
|
||||
name: "Average",
|
||||
title: title("Realized Price Comparison"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ series: tree.realized.price, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Median",
|
||||
title: title("Cost Basis Median (BTC-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ series: tree.costBasis.percentiles.pct50, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Q3",
|
||||
title: title("Cost Basis Q3 (BTC-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ series: tree.costBasis.percentiles.pct75, name, color }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Q1",
|
||||
title: title("Cost Basis Q1 (BTC-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ series: tree.costBasis.percentiles.pct25, name, color }),
|
||||
),
|
||||
},
|
||||
],
|
||||
name: "Per Dollar",
|
||||
tree: groupedWeightFolder({
|
||||
list, all, title,
|
||||
getAvgPrice: (c) => c.tree.realized.investor.price,
|
||||
getInProfit: (c) => c.tree.costBasis.inProfit.perDollar,
|
||||
getInLoss: (c) => c.tree.costBasis.inLoss.perDollar,
|
||||
getPercentiles: (c) => c.tree.costBasis.investedCapital,
|
||||
avgTitle: "Average", weightLabel: "USD-weighted",
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "By Capital",
|
||||
name: "Profitability",
|
||||
tree: [
|
||||
{
|
||||
name: "Average",
|
||||
title: title("Investor Price Comparison"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({ series: tree.realized.investor.price, name, color }),
|
||||
),
|
||||
name: "In Profit",
|
||||
title: title("Cost Basis In Profit"),
|
||||
top: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
price({ series: tree.costBasis.inProfit.perCoin, name: `${name} (coin)`, color }),
|
||||
price({ series: tree.costBasis.inProfit.perDollar, name: `${name} (dollar)`, color }),
|
||||
]),
|
||||
},
|
||||
{
|
||||
name: "Median",
|
||||
title: title("Cost Basis Median (USD-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({
|
||||
series: tree.costBasis.investedCapital.pct50,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Q3",
|
||||
title: title("Cost Basis Q3 (USD-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({
|
||||
series: tree.costBasis.investedCapital.pct75,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Q1",
|
||||
title: title("Cost Basis Q1 (USD-weighted)"),
|
||||
top: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
price({
|
||||
series: tree.costBasis.investedCapital.pct25,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
),
|
||||
name: "In Loss",
|
||||
title: title("Cost Basis In Loss"),
|
||||
top: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
|
||||
price({ series: tree.costBasis.inLoss.perCoin, name: `${name} (coin)`, color }),
|
||||
price({ series: tree.costBasis.inLoss.perDollar, name: `${name} (dollar)`, color }),
|
||||
]),
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -269,11 +255,7 @@ export function createGroupedCostBasisSectionWithPercentiles({
|
||||
name: "Supply Density",
|
||||
title: title("Cost Basis Supply Density"),
|
||||
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
percentRatio({
|
||||
pattern: tree.costBasis.supplyDensity,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
percentRatio({ pattern: tree.costBasis.supplyDensity, name, color }),
|
||||
),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -510,6 +510,7 @@ export function createNetworkSection() {
|
||||
name: "Created",
|
||||
color: colors.entity.output,
|
||||
base: outputs.count.total.sum,
|
||||
average: outputs.count.total.rolling.average,
|
||||
rolling: outputs.count.total.rolling.sum,
|
||||
cumulative: outputs.count.total.cumulative,
|
||||
},
|
||||
@@ -517,6 +518,7 @@ export function createNetworkSection() {
|
||||
name: "Spent",
|
||||
color: colors.entity.input,
|
||||
base: inputs.count.sum,
|
||||
average: inputs.count.rolling.average,
|
||||
rolling: inputs.count.rolling.sum,
|
||||
cumulative: inputs.count.cumulative,
|
||||
},
|
||||
|
||||
@@ -84,12 +84,13 @@ export function price({
|
||||
|
||||
/**
|
||||
* Create percentile series (max/min/median/pct75/pct25/pct90/pct10) from any stats pattern
|
||||
* @param {DistributionStats} pattern
|
||||
* @param {Unit} unit
|
||||
* @param {string} title
|
||||
* @param {Object} args
|
||||
* @param {DistributionStats} args.pattern
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.title]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function percentileSeries(pattern, unit, title) {
|
||||
function percentileSeries({ pattern, unit, title = "" }) {
|
||||
const { stat } = colors;
|
||||
return [
|
||||
dots({
|
||||
@@ -418,9 +419,7 @@ export function fromBaseStatsPattern({
|
||||
unit,
|
||||
title = "",
|
||||
baseColor,
|
||||
avgActive = true,
|
||||
}) {
|
||||
const { stat } = colors;
|
||||
const stats = statsAtWindow(pattern, window);
|
||||
return [
|
||||
dots({
|
||||
@@ -429,46 +428,17 @@ export function fromBaseStatsPattern({
|
||||
color: baseColor,
|
||||
unit,
|
||||
}),
|
||||
dots({
|
||||
series: stats.average,
|
||||
name: `${title} avg`.trim(),
|
||||
color: stat.avg,
|
||||
unit,
|
||||
defaultActive: avgActive,
|
||||
}),
|
||||
...percentileSeries(stats, unit, title),
|
||||
...percentileSeries({ pattern: stats, unit, title }),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create series from a flat stats pattern (average + pct percentiles as single series)
|
||||
* Use statsAtWindow() to extract from patterns with _1y24h30d7dPattern stats
|
||||
* @param {Object} args
|
||||
* @param {{ average: AnySeriesPattern, median: AnySeriesPattern, max: AnySeriesPattern, min: AnySeriesPattern, pct75: AnySeriesPattern, pct25: AnySeriesPattern, pct90: AnySeriesPattern, pct10: AnySeriesPattern }} args.pattern
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.title]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function fromStatsPattern({ pattern, unit, title = "" }) {
|
||||
return [
|
||||
{
|
||||
type: "Dots",
|
||||
series: pattern.average,
|
||||
title: `${title} avg`.trim(),
|
||||
unit,
|
||||
},
|
||||
...percentileSeries(pattern, unit, title),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract stats at a specific rolling window from patterns with _1y24h30d7dPattern stats
|
||||
* @param {Record<string, any>} pattern - Pattern with pct10/pct25/pct75/pct90 and average/median/max/min as _1y24h30d7dPattern
|
||||
* Extract stats at a specific rolling window
|
||||
* @param {Record<string, any>} pattern - Pattern with pct10/pct25/pct75/pct90 and median/max/min as _1y24h30d7dPattern
|
||||
* @param {string} window
|
||||
*/
|
||||
export function statsAtWindow(pattern, window) {
|
||||
return {
|
||||
average: pattern.average[window],
|
||||
median: pattern.median[window],
|
||||
max: pattern.max[window],
|
||||
min: pattern.min[window],
|
||||
@@ -601,10 +571,10 @@ export function distributionWindowsTree({ pattern, base, title, unit }) {
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: `${title} Average`,
|
||||
title: `${title} Median`,
|
||||
bottom: ROLLING_WINDOWS.map((w) =>
|
||||
line({
|
||||
series: pattern.average[w.key],
|
||||
series: pattern.median[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
unit,
|
||||
@@ -616,10 +586,7 @@ export function distributionWindowsTree({ pattern, base, title, unit }) {
|
||||
title: `${title} Distribution (${w.title})`,
|
||||
bottom: [
|
||||
...(base ? [line({ series: base, name: "base", unit })] : []),
|
||||
...fromStatsPattern({
|
||||
pattern: statsAtWindow(pattern, w.key),
|
||||
unit,
|
||||
}),
|
||||
...percentileSeries({ pattern: statsAtWindow(pattern, w.key), unit }),
|
||||
],
|
||||
})),
|
||||
],
|
||||
@@ -628,12 +595,11 @@ export function distributionWindowsTree({ pattern, base, title, unit }) {
|
||||
|
||||
/**
|
||||
* Map a rolling window slot's stats to a specific unit, producing a stats-compatible pattern
|
||||
* @param {{ average: Record<string, AnySeriesPattern>, median: Record<string, AnySeriesPattern>, max: Record<string, AnySeriesPattern>, min: Record<string, AnySeriesPattern>, pct75: Record<string, AnySeriesPattern>, pct25: Record<string, AnySeriesPattern>, pct90: Record<string, AnySeriesPattern>, pct10: Record<string, AnySeriesPattern> }} slot - Rolling window slot with multi-currency stats
|
||||
* @param {{ median: Record<string, AnySeriesPattern>, max: Record<string, AnySeriesPattern>, min: Record<string, AnySeriesPattern>, pct75: Record<string, AnySeriesPattern>, pct25: Record<string, AnySeriesPattern>, pct90: Record<string, AnySeriesPattern>, pct10: Record<string, AnySeriesPattern> }} slot - Rolling window slot with multi-currency stats
|
||||
* @param {BtcSatsUsdKey} unitKey
|
||||
*/
|
||||
function rollingSlotForUnit(slot, unitKey) {
|
||||
return {
|
||||
average: slot.average[unitKey],
|
||||
median: slot.median[unitKey],
|
||||
max: slot.max[unitKey],
|
||||
min: slot.min[unitKey],
|
||||
@@ -646,19 +612,19 @@ function rollingSlotForUnit(slot, unitKey) {
|
||||
|
||||
/**
|
||||
* Create distribution series for btc/sats/usd from a rolling window slot
|
||||
* @param {{ average: Record<string, AnySeriesPattern>, median: Record<string, AnySeriesPattern>, max: Record<string, AnySeriesPattern>, min: Record<string, AnySeriesPattern>, pct75: Record<string, AnySeriesPattern>, pct25: Record<string, AnySeriesPattern>, pct90: Record<string, AnySeriesPattern>, pct10: Record<string, AnySeriesPattern> }} slot - Rolling window slot with multi-currency stats
|
||||
* @param {{ median: Record<string, AnySeriesPattern>, max: Record<string, AnySeriesPattern>, min: Record<string, AnySeriesPattern>, pct75: Record<string, AnySeriesPattern>, pct25: Record<string, AnySeriesPattern>, pct90: Record<string, AnySeriesPattern>, pct10: Record<string, AnySeriesPattern> }} slot - Rolling window slot with multi-currency stats
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export const distributionBtcSatsUsd = (slot) => [
|
||||
...fromStatsPattern({
|
||||
...percentileSeries({
|
||||
pattern: rollingSlotForUnit(slot, "btc"),
|
||||
unit: Unit.btc,
|
||||
}),
|
||||
...fromStatsPattern({
|
||||
...percentileSeries({
|
||||
pattern: rollingSlotForUnit(slot, "sats"),
|
||||
unit: Unit.sats,
|
||||
}),
|
||||
...fromStatsPattern({
|
||||
...percentileSeries({
|
||||
pattern: rollingSlotForUnit(slot, "usd"),
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
@@ -907,11 +873,7 @@ export function chartsFromFull({
|
||||
? `${title} ${distributionSuffix}`
|
||||
: title;
|
||||
return [
|
||||
{
|
||||
name: "Per Block",
|
||||
title,
|
||||
bottom: [{ series: pattern.base, title: "base", unit }],
|
||||
},
|
||||
averagesTree({ windows: pattern.average, title, unit }),
|
||||
sumsTree({ windows: pattern.sum, title, unit }),
|
||||
distributionWindowsTree({ pattern, title: distTitle, unit }),
|
||||
{
|
||||
@@ -948,16 +910,11 @@ export function chartsFromAggregated({
|
||||
unit,
|
||||
distributionSuffix = "",
|
||||
}) {
|
||||
const { stat } = colors;
|
||||
const distTitle = distributionSuffix
|
||||
? `${title} ${distributionSuffix}`
|
||||
: title;
|
||||
return [
|
||||
{
|
||||
name: "Per Block",
|
||||
title,
|
||||
bottom: [{ series: pattern.sum, title: "base", color: stat.sum, unit }],
|
||||
},
|
||||
averagesTree({ windows: pattern.rolling.average, title, unit }),
|
||||
sumsTree({ windows: pattern.rolling.sum, title, unit }),
|
||||
distributionWindowsTree({
|
||||
pattern: pattern.rolling,
|
||||
@@ -996,12 +953,12 @@ export function chartsFromBlockAnd6b({ pattern, title, unit }) {
|
||||
{
|
||||
name: "Block",
|
||||
title: `${title} (Block)`,
|
||||
bottom: fromStatsPattern({ pattern: pattern.block, unit }),
|
||||
bottom: percentileSeries({ pattern: pattern.block, unit }),
|
||||
},
|
||||
{
|
||||
name: "Hourly",
|
||||
title: `${title} (Hourly)`,
|
||||
bottom: fromStatsPattern({ pattern: pattern._6b, unit }),
|
||||
bottom: percentileSeries({ pattern: pattern._6b, unit }),
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -1037,11 +994,7 @@ export function chartsFromSumsCumulative({ pattern, title, unit, color }) {
|
||||
*/
|
||||
export function chartsFromCount({ pattern, title, unit, color }) {
|
||||
return [
|
||||
{
|
||||
name: "Per Block",
|
||||
title,
|
||||
bottom: [{ series: pattern.base, title: "base", color, unit }],
|
||||
},
|
||||
averagesTree({ windows: pattern.average, title, unit }),
|
||||
...chartsFromSumsCumulative({ pattern, title, unit, color }),
|
||||
];
|
||||
}
|
||||
@@ -1060,6 +1013,7 @@ export function chartsFromCountEntries({ entries, title, unit }) {
|
||||
name,
|
||||
color: colors.at(i, arr.length),
|
||||
base: data.base,
|
||||
average: data.average,
|
||||
rolling: data.sum,
|
||||
cumulative: data.cumulative,
|
||||
})),
|
||||
@@ -1071,7 +1025,7 @@ export function chartsFromCountEntries({ entries, title, unit }) {
|
||||
/**
|
||||
* Per Block + Sums + Cumulative tree for multiple named series shown side-by-side
|
||||
* @param {Object} args
|
||||
* @param {Array<{ name: string, color: Color, base: AnySeriesPattern, rolling: { _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }, cumulative: AnySeriesPattern }>} args.entries
|
||||
* @param {Array<{ name: string, color: Color, base: AnySeriesPattern, average: { _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }, rolling: { _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }, cumulative: AnySeriesPattern }>} args.entries
|
||||
* @param {string} args.title
|
||||
* @param {Unit} args.unit
|
||||
* @returns {PartialOptionsTree}
|
||||
@@ -1079,10 +1033,17 @@ export function chartsFromCountEntries({ entries, title, unit }) {
|
||||
export function multiSeriesTree({ entries, title, unit }) {
|
||||
return [
|
||||
{
|
||||
name: "Per Block",
|
||||
title,
|
||||
bottom: entries.map((e) =>
|
||||
line({ series: e.base, name: e.name, color: e.color, unit }),
|
||||
name: "Compare",
|
||||
title: `${title} Average`,
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
entries.map((e) =>
|
||||
line({
|
||||
series: e.average[w.key],
|
||||
name: `${e.name} ${w.name}`,
|
||||
color: e.color,
|
||||
unit,
|
||||
}),
|
||||
),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
|
||||
@@ -224,21 +224,35 @@ export function satsBtcUsdRolling({ pattern, name, color, defaultActive }) {
|
||||
* @param {Color} [args.color]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
export function satsBtcUsdFullTree({ pattern, name, title, color }) {
|
||||
export function satsBtcUsdFullTree({ pattern, title, color }) {
|
||||
return [
|
||||
{
|
||||
name: "Per Block",
|
||||
title,
|
||||
bottom: satsBtcUsd({ pattern: pattern.base, name, color }),
|
||||
name: "Compare",
|
||||
title: `${title} Average`,
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
satsBtcUsd({
|
||||
pattern: pattern.average[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: `${title} ${w.title} Sum`,
|
||||
bottom: satsBtcUsd({
|
||||
pattern: pattern.sum[w.key],
|
||||
name: w.name,
|
||||
color: w.color,
|
||||
}),
|
||||
title: `${title} ${w.title}`,
|
||||
bottom: [
|
||||
...satsBtcUsd({
|
||||
pattern: pattern.sum[w.key],
|
||||
name: "Sum",
|
||||
color: w.color,
|
||||
}),
|
||||
...satsBtcUsd({
|
||||
pattern: pattern.average[w.key],
|
||||
name: "Avg",
|
||||
color: w.color,
|
||||
defaultActive: false,
|
||||
}),
|
||||
],
|
||||
})),
|
||||
{
|
||||
name: "Cumulative",
|
||||
|
||||
@@ -58,10 +58,10 @@
|
||||
* @typedef {Brk.BpsCentsPercentilesRatioSatsUsdPattern} PriceRatioPercentilesPattern
|
||||
* AnyRatioPattern: full ratio pattern with percentiles, SMAs, and std dev bands
|
||||
* @typedef {Brk.BpsCentsPercentilesRatioSatsSmaStdUsdPattern} AnyRatioPattern
|
||||
* FullValuePattern: base + cumulative + rolling windows (sats/btc/cents/usd)
|
||||
* @typedef {Brk.BaseCumulativeSumPattern3} FullValuePattern
|
||||
* RollingWindowSlot: a single rolling window with stats (average, pct10, pct25, median, pct75, pct90, max, min) per unit
|
||||
* @typedef {Brk.AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern<number>} RollingWindowSlot
|
||||
* FullValuePattern: base + cumulative + sum + average rolling windows (sats/btc/cents/usd)
|
||||
* @typedef {Brk.AverageBaseCumulativeSumPattern3} FullValuePattern
|
||||
* RollingWindowSlot: a single rolling window with stats (pct10, pct25, median, pct75, pct90, max, min) per unit
|
||||
* @typedef {Brk.MaxMedianMinPct10Pct25Pct75Pct90Pattern<number>} RollingWindowSlot
|
||||
* @typedef {Brk.AnySeriesPattern} AnySeriesPattern
|
||||
* @typedef {Brk.CentsSatsUsdPattern} ActivePricePattern
|
||||
* @typedef {Brk.AnySeriesEndpoint} AnySeriesEndpoint
|
||||
@@ -73,9 +73,9 @@
|
||||
* - FullRelativePattern: has BOTH RelToMarketCap AND RelToOwnMarketCap
|
||||
* @typedef {Brk.LossNetNuplProfitPattern} BasicRelativePattern
|
||||
* @typedef {Brk.LossNetNuplProfitPattern} GlobalRelativePattern
|
||||
* @typedef {Brk.GrossInvestedLossNetNuplProfitSentimentPattern2} OwnRelativePattern
|
||||
* @typedef {Brk.GrossInvestedLossNetNuplProfitSentimentPattern2} FullRelativePattern
|
||||
* @typedef {Brk.GrossInvestedLossNetNuplProfitSentimentPattern2} UnrealizedPattern
|
||||
* @typedef {Brk.GrossInvestedInvestorLossNetNuplProfitSentimentPattern2} OwnRelativePattern
|
||||
* @typedef {Brk.GrossInvestedInvestorLossNetNuplProfitSentimentPattern2} FullRelativePattern
|
||||
* @typedef {Brk.GrossInvestedInvestorLossNetNuplProfitSentimentPattern2} UnrealizedPattern
|
||||
*
|
||||
* Profitability bucket pattern (supply + realized_cap + nupl)
|
||||
* @typedef {Brk.NuplRealizedSupplyPattern} RealizedSupplyPattern
|
||||
@@ -87,10 +87,10 @@
|
||||
* @typedef {Brk.CapGrossInvestorLossMvrvNetPeakPriceProfitSellSoprPattern} RealizedPattern4
|
||||
*
|
||||
* Transfer volume pattern (base + cumulative + inProfit/inLoss + sum windows)
|
||||
* @typedef {Brk.BaseCumulativeInSumPattern} TransferVolumePattern
|
||||
* @typedef {Brk.AverageBaseCumulativeInSumPattern} TransferVolumePattern
|
||||
*
|
||||
* Realized profit/loss pattern (base + cumulative + sum windows, cents/usd)
|
||||
* @typedef {Brk.BaseCumulativeSumPattern4} RealizedProfitLossPattern
|
||||
* @typedef {Brk.BaseCumulativeSumPattern} RealizedProfitLossPattern
|
||||
*
|
||||
* Full activity pattern (coindays, coinyears, dormancy, transfer volume)
|
||||
* @typedef {Brk.CoindaysCoinyearsDormancyTransferPattern} FullActivityPattern
|
||||
@@ -136,11 +136,11 @@
|
||||
*/
|
||||
/**
|
||||
* Stats pattern: average, min, max, percentiles (height-only indexes, NO base)
|
||||
* @typedef {Brk.AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern<number>} StatsPattern
|
||||
* @typedef {Brk.MaxMedianMinPct10Pct25Pct75Pct90Pattern<number>} StatsPattern
|
||||
*/
|
||||
/**
|
||||
* Base stats pattern: average, min, max, percentiles
|
||||
* @typedef {Brk.AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern<number>} BaseStatsPattern
|
||||
* @typedef {Brk.MaxMedianMinPct10Pct25Pct75Pct90Pattern<number>} BaseStatsPattern
|
||||
*/
|
||||
/**
|
||||
* Full stats pattern: cumulative, sum, average, min, max, percentiles + rolling
|
||||
@@ -161,7 +161,7 @@
|
||||
/**
|
||||
* Count pattern: height, cumulative, and rolling sum windows
|
||||
* @template T
|
||||
* @typedef {Brk.BaseCumulativeSumPattern<T>} CountPattern
|
||||
* @typedef {Brk.AverageBaseCumulativeSumPattern<T>} CountPattern
|
||||
*/
|
||||
/**
|
||||
* Full per-block pattern: height, cumulative, sum, and distribution stats (all flat)
|
||||
@@ -172,8 +172,8 @@
|
||||
* @typedef {FullStatsPattern | BtcFullStatsPattern} AnyStatsPattern
|
||||
*/
|
||||
/**
|
||||
* Distribution stats: 8 series fields (average, min, max, median, pct10/25/75/90)
|
||||
* @typedef {{ average: AnySeriesPattern, min: AnySeriesPattern, max: AnySeriesPattern, median: AnySeriesPattern, pct10: AnySeriesPattern, pct25: AnySeriesPattern, pct75: AnySeriesPattern, pct90: AnySeriesPattern }} DistributionStats
|
||||
* Distribution stats: min, max, median, pct10/25/75/90
|
||||
* @typedef {{ min: AnySeriesPattern, max: AnySeriesPattern, median: AnySeriesPattern, pct10: AnySeriesPattern, pct25: AnySeriesPattern, pct75: AnySeriesPattern, pct90: AnySeriesPattern }} DistributionStats
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user