global: snapshot

This commit is contained in:
nym21
2026-03-06 23:46:10 +01:00
parent 9a2ee0273f
commit 9507eb3de5
36 changed files with 2447 additions and 3861 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,68 +1,37 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Height, Indexes, Sats, StoredF64, Version};
use derive_more::{Deref, DerefMut};
use brk_types::{Height, Indexes, Sats, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::internal::ComputedFromHeightCumulativeSum;
use crate::internal::{RollingEmas2w, ValueFromHeightCumulative};
use crate::{blocks, distribution::metrics::ImportConfig, prices};
use super::ActivityCore;
#[derive(Deref, DerefMut, Traversable)]
pub struct ActivityMetrics<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub core: ActivityCore<M>,
pub coinblocks_destroyed: ComputedFromHeightCumulativeSum<StoredF64, M>,
pub coindays_destroyed: ComputedFromHeightCumulativeSum<StoredF64, M>,
#[derive(Traversable)]
pub struct ActivityBase<M: StorageMode = Rw> {
pub sent: ValueFromHeightCumulative<M>,
pub sent_ema: RollingEmas2w<M>,
}
impl ActivityMetrics {
impl ActivityBase {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
core: ActivityCore::forced_import(cfg)?,
coinblocks_destroyed: cfg
.import_cumulative_sum("coinblocks_destroyed", Version::ONE)?,
coindays_destroyed: cfg.import_cumulative_sum("coindays_destroyed", Version::ONE)?,
sent: cfg.import_value_cumulative("sent", Version::ZERO)?,
sent_ema: cfg.import_emas_2w("sent", Version::ZERO)?,
})
}
pub(crate) fn min_len(&self) -> usize {
self.core
.min_len()
.min(self.coinblocks_destroyed.height.len())
.min(self.coindays_destroyed.height.len())
self.sent.base.sats.height.len()
}
pub(crate) fn truncate_push(
&mut self,
height: Height,
sent: Sats,
satblocks_destroyed: Sats,
satdays_destroyed: Sats,
) -> Result<()> {
self.core.truncate_push(height, sent)?;
self.coinblocks_destroyed.height.truncate_push(
height,
StoredF64::from(Bitcoin::from(satblocks_destroyed)),
)?;
self.coindays_destroyed.height.truncate_push(
height,
StoredF64::from(Bitcoin::from(satdays_destroyed)),
)?;
pub(crate) fn truncate_push(&mut self, height: Height, sent: Sats) -> Result<()> {
self.sent.base.sats.height.truncate_push(height, sent)?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.core.sent.base.sats.height as &mut dyn AnyStoredVec,
&mut self.coinblocks_destroyed.height as &mut dyn AnyStoredVec,
&mut self.coindays_destroyed.height as &mut dyn AnyStoredVec,
]
vec![&mut self.sent.base.sats.height as &mut dyn AnyStoredVec]
}
pub(crate) fn validate_computed_versions(&mut self, _base_version: Version) -> Result<()> {
@@ -75,12 +44,14 @@ impl ActivityMetrics {
others: &[&Self],
exit: &Exit,
) -> Result<()> {
let core_refs: Vec<&ActivityCore> = others.iter().map(|o| &o.core).collect();
self.core
.compute_from_stateful(starting_indexes, &core_refs, exit)?;
sum_others!(self, starting_indexes, others, exit; coinblocks_destroyed.height);
sum_others!(self, starting_indexes, others, exit; coindays_destroyed.height);
self.sent.base.sats.height.compute_sum_of_others(
starting_indexes.height,
&others
.iter()
.map(|v| &v.sent.base.sats.height)
.collect::<Vec<_>>(),
exit,
)?;
Ok(())
}
@@ -91,16 +62,16 @@ impl ActivityMetrics {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.core
.compute_rest_part1(blocks, prices, starting_indexes, exit)?;
self.sent
.compute(prices, starting_indexes.height, exit)?;
let window_starts = blocks.count.window_starts();
self.coinblocks_destroyed
.compute_rest(starting_indexes.height, &window_starts, exit)?;
self.coindays_destroyed
.compute_rest(starting_indexes.height, &window_starts, exit)?;
self.sent_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent.base.sats.height,
&self.sent.base.cents.height,
exit,
)?;
Ok(())
}

View File

@@ -1,78 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, Sats, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::internal::{RollingEmas2w, ValueFromHeightCumulative};
use crate::{blocks, distribution::metrics::ImportConfig, prices};
#[derive(Traversable)]
pub struct ActivityCore<M: StorageMode = Rw> {
pub sent: ValueFromHeightCumulative<M>,
pub sent_ema: RollingEmas2w<M>,
}
impl ActivityCore {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
sent: cfg.import_value_cumulative("sent", Version::ZERO)?,
sent_ema: cfg.import_emas_2w("sent", Version::ZERO)?,
})
}
pub(crate) fn min_len(&self) -> usize {
self.sent.base.sats.height.len()
}
pub(crate) fn truncate_push(&mut self, height: Height, sent: Sats) -> Result<()> {
self.sent.base.sats.height.truncate_push(height, sent)?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![&mut self.sent.base.sats.height as &mut dyn AnyStoredVec]
}
pub(crate) fn validate_computed_versions(&mut self, _base_version: Version) -> Result<()> {
Ok(())
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
self.sent.base.sats.height.compute_sum_of_others(
starting_indexes.height,
&others
.iter()
.map(|v| &v.sent.base.sats.height)
.collect::<Vec<_>>(),
exit,
)?;
Ok(())
}
pub(crate) fn compute_rest_part1(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.sent
.compute(prices, starting_indexes.height, exit)?;
self.sent_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent.base.sats.height,
&self.sent.base.cents.height,
exit,
)?;
Ok(())
}
}

View File

@@ -0,0 +1,107 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Height, Indexes, Sats, StoredF64, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::internal::ComputedFromHeightCumulativeSum;
use crate::{blocks, distribution::metrics::ImportConfig, prices};
use super::ActivityBase;
#[derive(Deref, DerefMut, Traversable)]
pub struct ActivityFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: ActivityBase<M>,
pub coinblocks_destroyed: ComputedFromHeightCumulativeSum<StoredF64, M>,
pub coindays_destroyed: ComputedFromHeightCumulativeSum<StoredF64, M>,
}
impl ActivityFull {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: ActivityBase::forced_import(cfg)?,
coinblocks_destroyed: cfg
.import_cumulative_sum("coinblocks_destroyed", Version::ONE)?,
coindays_destroyed: cfg.import_cumulative_sum("coindays_destroyed", Version::ONE)?,
})
}
pub(crate) fn min_len(&self) -> usize {
self.base
.min_len()
.min(self.coinblocks_destroyed.height.len())
.min(self.coindays_destroyed.height.len())
}
pub(crate) fn truncate_push(
&mut self,
height: Height,
sent: Sats,
satblocks_destroyed: Sats,
satdays_destroyed: Sats,
) -> Result<()> {
self.base.truncate_push(height, sent)?;
self.coinblocks_destroyed.height.truncate_push(
height,
StoredF64::from(Bitcoin::from(satblocks_destroyed)),
)?;
self.coindays_destroyed.height.truncate_push(
height,
StoredF64::from(Bitcoin::from(satdays_destroyed)),
)?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.base.sent.base.sats.height as &mut dyn AnyStoredVec,
&mut self.coinblocks_destroyed.height as &mut dyn AnyStoredVec,
&mut self.coindays_destroyed.height as &mut dyn AnyStoredVec,
]
}
pub(crate) fn validate_computed_versions(&mut self, _base_version: Version) -> Result<()> {
Ok(())
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
let core_refs: Vec<&ActivityBase> = others.iter().map(|o| &o.base).collect();
self.base
.compute_from_stateful(starting_indexes, &core_refs, exit)?;
sum_others!(self, starting_indexes, others, exit; coinblocks_destroyed.height);
sum_others!(self, starting_indexes, others, exit; coindays_destroyed.height);
Ok(())
}
pub(crate) fn compute_rest_part1(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.base
.compute_rest_part1(blocks, prices, starting_indexes, exit)?;
let window_starts = blocks.count.window_starts();
self.coinblocks_destroyed
.compute_rest(starting_indexes.height, &window_starts, exit)?;
self.coindays_destroyed
.compute_rest(starting_indexes.height, &window_starts, exit)?;
Ok(())
}
}

View File

@@ -1,5 +1,5 @@
mod base;
mod core;
mod full;
pub use base::*;
pub use core::*;
pub use full::*;

View File

@@ -9,8 +9,8 @@ use crate::{blocks, prices};
use crate::internal::ComputedFromHeight;
use crate::distribution::metrics::{
ActivityMetrics, CostBasisWithExtended, ImportConfig, OutputsMetrics, RealizedAdjusted,
RealizedWithExtended, RelativeForAll, SupplyMetrics, UnrealizedFull,
ActivityFull, CostBasisWithExtended, ImportConfig, OutputsMetrics, RealizedAdjusted,
RealizedFull, RelativeForAll, SupplyMetrics, UnrealizedFull,
};
/// All-cohort metrics: extended realized + adjusted (as composable add-on),
@@ -22,8 +22,8 @@ pub struct AllCohortMetrics<M: StorageMode = Rw> {
pub filter: Filter,
pub supply: Box<SupplyMetrics<M>>,
pub outputs: Box<OutputsMetrics<M>>,
pub activity: Box<ActivityMetrics<M>>,
pub realized: Box<RealizedWithExtended<M>>,
pub activity: Box<ActivityFull<M>>,
pub realized: Box<RealizedFull<M>>,
pub cost_basis: Box<CostBasisWithExtended<M>>,
pub unrealized: Box<UnrealizedFull<M>>,
pub adjusted: Box<RealizedAdjusted<M>>,
@@ -44,7 +44,7 @@ impl AllCohortMetrics {
supply: SupplyMetrics,
) -> Result<Self> {
let unrealized = UnrealizedFull::forced_import(cfg)?;
let realized = RealizedWithExtended::forced_import(cfg)?;
let realized = RealizedFull::forced_import(cfg)?;
let adjusted = RealizedAdjusted::forced_import(cfg)?;
let relative = RelativeForAll::forced_import(cfg)?;
@@ -53,7 +53,7 @@ impl AllCohortMetrics {
filter: cfg.filter.clone(),
supply: Box::new(supply),
outputs: Box::new(OutputsMetrics::forced_import(cfg)?),
activity: Box::new(ActivityMetrics::forced_import(cfg)?),
activity: Box::new(ActivityFull::forced_import(cfg)?),
realized: Box::new(realized),
cost_basis: Box::new(CostBasisWithExtended::forced_import(cfg)?),
unrealized: Box::new(unrealized),
@@ -97,7 +97,7 @@ impl AllCohortMetrics {
self.relative.compute(
starting_indexes.height,
&self.unrealized,
&self.realized.base,
&self.realized,
&self.supply.total.sats.height,
height_to_market_cap,
exit,

View File

@@ -7,20 +7,20 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, prices};
use crate::distribution::metrics::{
ActivityMetrics, CostBasisBase, ImportConfig, OutputsMetrics, RealizedFull,
ActivityFull, CostBasisBase, ImportConfig, OutputsMetrics, RealizedBase,
RelativeWithRelToAll, SupplyMetrics, UnrealizedFull,
};
/// Basic cohort metrics: no extensions, with relative (rel_to_all).
/// Used by: epoch, year, type (spendable), amount, address cohorts.
/// Used by: age_range cohorts.
#[derive(Traversable)]
pub struct BasicCohortMetrics<M: StorageMode = Rw> {
#[traversable(skip)]
pub filter: Filter,
pub supply: Box<SupplyMetrics<M>>,
pub outputs: Box<OutputsMetrics<M>>,
pub activity: Box<ActivityMetrics<M>>,
pub realized: Box<RealizedFull<M>>,
pub activity: Box<ActivityFull<M>>,
pub realized: Box<RealizedBase<M>>,
pub cost_basis: Box<CostBasisBase<M>>,
pub unrealized: Box<UnrealizedFull<M>>,
pub relative: Box<RelativeWithRelToAll<M>>,
@@ -32,7 +32,7 @@ impl BasicCohortMetrics {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let supply = SupplyMetrics::forced_import(cfg)?;
let unrealized = UnrealizedFull::forced_import(cfg)?;
let realized = RealizedFull::forced_import(cfg)?;
let realized = RealizedBase::forced_import(cfg)?;
let relative = RelativeWithRelToAll::forced_import(cfg)?;
@@ -40,7 +40,7 @@ impl BasicCohortMetrics {
filter: cfg.filter.clone(),
supply: Box::new(supply),
outputs: Box::new(OutputsMetrics::forced_import(cfg)?),
activity: Box::new(ActivityMetrics::forced_import(cfg)?),
activity: Box::new(ActivityFull::forced_import(cfg)?),
realized: Box::new(realized),
cost_basis: Box::new(CostBasisBase::forced_import(cfg)?),
unrealized: Box::new(unrealized),
@@ -62,7 +62,6 @@ impl BasicCohortMetrics {
prices,
starting_indexes,
&self.supply.total.btc.height,
height_to_market_cap,
exit,
)?;

View File

@@ -7,8 +7,8 @@ use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, prices};
use crate::distribution::metrics::{
ActivityCore, CohortMetricsBase, RealizedCore, ImportConfig, OutputsMetrics,
RelativeCompleteWithRelToAll, SupplyMetrics, UnrealizedComplete,
ActivityBase, CohortMetricsBase, RealizedBase, ImportConfig, OutputsMetrics,
RelativeBaseWithRelToAll, SupplyMetrics, UnrealizedBase,
};
#[derive(Traversable)]
@@ -17,10 +17,10 @@ pub struct CoreCohortMetrics<M: StorageMode = Rw> {
pub filter: Filter,
pub supply: Box<SupplyMetrics<M>>,
pub outputs: Box<OutputsMetrics<M>>,
pub activity: Box<ActivityCore<M>>,
pub realized: Box<RealizedCore<M>>,
pub unrealized: Box<UnrealizedComplete<M>>,
pub relative: Box<RelativeCompleteWithRelToAll<M>>,
pub activity: Box<ActivityBase<M>>,
pub realized: Box<RealizedBase<M>>,
pub unrealized: Box<UnrealizedBase<M>>,
pub relative: Box<RelativeBaseWithRelToAll<M>>,
}
impl CoreCohortMetrics {
@@ -29,10 +29,10 @@ impl CoreCohortMetrics {
filter: cfg.filter.clone(),
supply: Box::new(SupplyMetrics::forced_import(cfg)?),
outputs: Box::new(OutputsMetrics::forced_import(cfg)?),
activity: Box::new(ActivityCore::forced_import(cfg)?),
realized: Box::new(RealizedCore::forced_import(cfg)?),
unrealized: Box::new(UnrealizedComplete::forced_import(cfg)?),
relative: Box::new(RelativeCompleteWithRelToAll::forced_import(cfg)?),
activity: Box::new(ActivityBase::forced_import(cfg)?),
realized: Box::new(RealizedBase::forced_import(cfg)?),
unrealized: Box::new(UnrealizedBase::forced_import(cfg)?),
relative: Box::new(RelativeBaseWithRelToAll::forced_import(cfg)?),
})
}
@@ -80,17 +80,17 @@ impl CoreCohortMetrics {
)?;
self.activity.compute_from_stateful(
starting_indexes,
&others.iter().map(|v| &v.activity().core).collect::<Vec<_>>(),
&others.iter().map(|v| &v.activity().base).collect::<Vec<_>>(),
exit,
)?;
self.realized.compute_from_stateful(
starting_indexes,
&others.iter().map(|v| &v.realized_full().core).collect::<Vec<_>>(),
&others.iter().map(|v| v.realized_base()).collect::<Vec<_>>(),
exit,
)?;
self.unrealized.compute_from_stateful(
starting_indexes,
&others.iter().map(|v| &v.unrealized_full().complete).collect::<Vec<_>>(),
&others.iter().map(|v| &v.unrealized_full().base).collect::<Vec<_>>(),
exit,
)?;
@@ -114,6 +114,12 @@ impl CoreCohortMetrics {
self.activity
.compute_rest_part1(blocks, prices, starting_indexes, exit)?;
self.realized
.sent_in_profit
.compute(prices, starting_indexes.height, exit)?;
self.realized
.sent_in_loss
.compute(prices, starting_indexes.height, exit)?;
self.realized
.compute_rest_part1(starting_indexes, exit)?;

View File

@@ -9,8 +9,8 @@ use crate::{blocks, prices};
use crate::internal::ComputedFromHeight;
use crate::distribution::metrics::{
ActivityMetrics, CostBasisWithExtended, ImportConfig, OutputsMetrics,
RealizedWithExtended, RelativeWithExtended, SupplyMetrics, UnrealizedFull,
ActivityFull, CostBasisWithExtended, ImportConfig, OutputsMetrics,
RealizedFull, RelativeWithExtended, SupplyMetrics, UnrealizedFull,
};
/// Cohort metrics with extended realized + extended cost basis (no adjusted).
@@ -21,8 +21,8 @@ pub struct ExtendedCohortMetrics<M: StorageMode = Rw> {
pub filter: Filter,
pub supply: Box<SupplyMetrics<M>>,
pub outputs: Box<OutputsMetrics<M>>,
pub activity: Box<ActivityMetrics<M>>,
pub realized: Box<RealizedWithExtended<M>>,
pub activity: Box<ActivityFull<M>>,
pub realized: Box<RealizedFull<M>>,
pub cost_basis: Box<CostBasisWithExtended<M>>,
pub unrealized: Box<UnrealizedFull<M>>,
pub relative: Box<RelativeWithExtended<M>>,
@@ -36,7 +36,7 @@ impl ExtendedCohortMetrics {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let supply = SupplyMetrics::forced_import(cfg)?;
let unrealized = UnrealizedFull::forced_import(cfg)?;
let realized = RealizedWithExtended::forced_import(cfg)?;
let realized = RealizedFull::forced_import(cfg)?;
let relative = RelativeWithExtended::forced_import(cfg)?;
@@ -44,7 +44,7 @@ impl ExtendedCohortMetrics {
filter: cfg.filter.clone(),
supply: Box::new(supply),
outputs: Box::new(OutputsMetrics::forced_import(cfg)?),
activity: Box::new(ActivityMetrics::forced_import(cfg)?),
activity: Box::new(ActivityFull::forced_import(cfg)?),
realized: Box::new(realized),
cost_basis: Box::new(CostBasisWithExtended::forced_import(cfg)?),
unrealized: Box::new(unrealized),
@@ -75,7 +75,7 @@ impl ExtendedCohortMetrics {
self.relative.compute(
starting_indexes.height,
&self.unrealized,
&self.realized.base,
&self.realized,
&self.supply.total.sats.height,
height_to_market_cap,
all_supply_sats,

View File

@@ -2,36 +2,22 @@ use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
BasisPoints16, BasisPoints32, Bitcoin, Cents, Dollars, Height, Indexes, Sats, StoredF32,
Version,
BasisPoints16, Height, Indexes, Sats, Version,
};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, WritableVec};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{blocks, prices};
use crate::internal::{
CentsUnsignedToDollars, ComputedFromHeight, ComputedFromHeightCumulative,
ComputedFromHeightRatio, Identity, LazyFromHeight, PercentFromHeight, Price, RatioSatsBp16,
PercentFromHeight, RatioSatsBp16,
ValueFromHeight,
};
use crate::distribution::{
metrics::{ActivityCore, ImportConfig, OutputsMetrics, SupplyMetrics},
state::{RealizedOps, UnrealizedState},
metrics::{ActivityBase, ImportConfig, OutputsMetrics, RealizedMinimal, SupplyMetrics},
state::UnrealizedState,
};
/// Minimal realized metrics: realized cap, realized price, MVRV, and realized P/L.
#[derive(Traversable)]
pub struct MinimalRealized<M: StorageMode = Rw> {
pub realized_cap_cents: ComputedFromHeight<Cents, M>,
pub realized_profit: ComputedFromHeightCumulative<Cents, M>,
pub realized_loss: ComputedFromHeightCumulative<Cents, M>,
pub realized_cap: LazyFromHeight<Dollars, Cents>,
pub realized_price: Price<ComputedFromHeight<Cents, M>>,
pub realized_price_ratio: ComputedFromHeightRatio<M>,
pub mvrv: LazyFromHeight<StoredF32>,
}
/// Minimal unrealized metrics: supply in profit/loss only.
#[derive(Traversable)]
pub struct MinimalUnrealized<M: StorageMode = Rw> {
@@ -57,135 +43,12 @@ pub struct MinimalCohortMetrics<M: StorageMode = Rw> {
pub filter: Filter,
pub supply: Box<SupplyMetrics<M>>,
pub outputs: Box<OutputsMetrics<M>>,
pub activity: Box<ActivityCore<M>>,
pub realized: Box<MinimalRealized<M>>,
pub activity: Box<ActivityBase<M>>,
pub realized: Box<RealizedMinimal<M>>,
pub unrealized: Box<MinimalUnrealized<M>>,
pub relative: Box<MinimalRelative<M>>,
}
impl MinimalRealized {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let realized_cap_cents = cfg.import_computed("realized_cap_cents", Version::ZERO)?;
let realized_cap = LazyFromHeight::from_computed::<CentsUnsignedToDollars>(
&cfg.name("realized_cap"),
cfg.version,
realized_cap_cents.height.read_only_boxed_clone(),
&realized_cap_cents,
);
let realized_profit = cfg.import_cumulative("realized_profit", Version::ZERO)?;
let realized_loss = cfg.import_cumulative("realized_loss", Version::ZERO)?;
let realized_price = cfg.import_price("realized_price", Version::ONE)?;
let realized_price_ratio = cfg.import_ratio("realized_price", Version::ONE)?;
let mvrv = LazyFromHeight::from_lazy::<Identity<StoredF32>, BasisPoints32>(
&cfg.name("mvrv"),
cfg.version,
&realized_price_ratio.ratio,
);
Ok(Self {
realized_cap_cents,
realized_profit,
realized_loss,
realized_cap,
realized_price,
realized_price_ratio,
mvrv,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.realized_cap_cents
.height
.len()
.min(self.realized_profit.height.len())
.min(self.realized_loss.height.len())
}
pub(crate) fn truncate_push(
&mut self,
height: Height,
state: &impl RealizedOps,
) -> Result<()> {
self.realized_cap_cents
.height
.truncate_push(height, state.cap())?;
self.realized_profit
.height
.truncate_push(height, state.profit())?;
self.realized_loss
.height
.truncate_push(height, state.loss())?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.realized_cap_cents.height as &mut dyn AnyStoredVec,
&mut self.realized_profit.height,
&mut self.realized_loss.height,
]
}
pub(crate) fn compute_from_sources(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
sum_others!(self, starting_indexes, others, exit; realized_cap_cents.height);
sum_others!(self, starting_indexes, others, exit; realized_profit.height);
sum_others!(self, starting_indexes, others, exit; realized_loss.height);
Ok(())
}
pub(crate) fn compute_rest_part1(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.realized_profit
.compute_rest(starting_indexes.height, exit)?;
self.realized_loss
.compute_rest(starting_indexes.height, exit)?;
Ok(())
}
pub(crate) fn compute_rest_part2(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
exit: &Exit,
) -> Result<()> {
self.realized_price.cents.height.compute_transform2(
starting_indexes.height,
&self.realized_cap_cents.height,
height_to_supply,
|(i, cap_cents, supply, ..)| {
let cap = cap_cents.as_u128();
let supply_sats = Sats::from(supply).as_u128();
if supply_sats == 0 {
(i, Cents::ZERO)
} else {
(i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats))
}
},
exit,
)?;
self.realized_price_ratio.compute_ratio(
starting_indexes,
&prices.price.cents.height,
&self.realized_price.cents.height,
exit,
)?;
Ok(())
}
}
impl MinimalUnrealized {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
@@ -292,8 +155,8 @@ impl MinimalCohortMetrics {
filter: cfg.filter.clone(),
supply: Box::new(SupplyMetrics::forced_import(cfg)?),
outputs: Box::new(OutputsMetrics::forced_import(cfg)?),
activity: Box::new(ActivityCore::forced_import(cfg)?),
realized: Box::new(MinimalRealized::forced_import(cfg)?),
activity: Box::new(ActivityBase::forced_import(cfg)?),
realized: Box::new(RealizedMinimal::forced_import(cfg)?),
unrealized: Box::new(MinimalUnrealized::forced_import(cfg)?),
relative: Box::new(MinimalRelative::forced_import(cfg)?),
})
@@ -345,7 +208,7 @@ impl MinimalCohortMetrics {
&others.iter().map(|v| v.activity.as_ref()).collect::<Vec<_>>(),
exit,
)?;
self.realized.compute_from_sources(
self.realized.compute_from_stateful(
starting_indexes,
&others
.iter()

View File

@@ -68,6 +68,104 @@ macro_rules! impl_cohort_metrics_base {
Ok(())
}
fn min_stateful_height_len(&self) -> usize {
self.supply.min_len()
.min(self.outputs.min_len())
.min(self.activity.min_len())
.min(self.realized.min_stateful_height_len())
.min(self.unrealized_full().min_stateful_height_len())
.min(self.cost_basis_base().min_stateful_height_len())
}
fn truncate_push(
&mut self,
height: brk_types::Height,
state: &$crate::distribution::state::CohortState<$crate::distribution::state::RealizedState>,
) -> brk_error::Result<()> {
self.supply_mut()
.truncate_push(height, state.supply.value)?;
self.outputs_mut()
.truncate_push(height, state.supply.utxo_count)?;
self.activity_mut().truncate_push(
height,
state.sent,
state.satblocks_destroyed,
state.satdays_destroyed,
)?;
self.realized.truncate_push(height, &state.realized)?;
Ok(())
}
fn compute_base_from_others<T: $crate::distribution::metrics::CohortMetricsBase>(
&mut self,
starting_indexes: &brk_types::Indexes,
others: &[&T],
exit: &vecdb::Exit,
) -> brk_error::Result<()> {
self.supply_mut().compute_from_stateful(
starting_indexes,
&others.iter().map(|v| v.supply()).collect::<Vec<_>>(),
exit,
)?;
self.outputs_mut().compute_from_stateful(
starting_indexes,
&others.iter().map(|v| v.outputs()).collect::<Vec<_>>(),
exit,
)?;
self.activity_mut().compute_from_stateful(
starting_indexes,
&others.iter().map(|v| v.activity()).collect::<Vec<_>>(),
exit,
)?;
self.realized.compute_from_stateful(
starting_indexes,
&others.iter().map(|v| v.realized_base()).collect::<Vec<_>>(),
exit,
)?;
self.unrealized_full_mut().compute_from_stateful(
starting_indexes,
&others.iter().map(|v| v.unrealized_full()).collect::<Vec<_>>(),
exit,
)?;
self.cost_basis_base_mut().compute_from_stateful(
starting_indexes,
&others.iter().map(|v| v.cost_basis_base()).collect::<Vec<_>>(),
exit,
)?;
Ok(())
}
fn compute_rest_part1(
&mut self,
blocks: &$crate::blocks::Vecs,
prices: &$crate::prices::Vecs,
starting_indexes: &brk_types::Indexes,
exit: &vecdb::Exit,
) -> brk_error::Result<()> {
self.supply_mut()
.compute(prices, starting_indexes.height, exit)?;
self.supply_mut()
.compute_rest_part1(blocks, starting_indexes, exit)?;
self.outputs_mut()
.compute_rest(blocks, starting_indexes, exit)?;
self.activity_mut()
.sent
.compute(prices, starting_indexes.height, exit)?;
self.activity_mut()
.compute_rest_part1(blocks, prices, starting_indexes, exit)?;
self.realized.sent_in_profit
.compute(prices, starting_indexes.height, exit)?;
self.realized.sent_in_loss
.compute(prices, starting_indexes.height, exit)?;
self.realized.compute_rest_part1(starting_indexes, exit)?;
self.unrealized_full_mut()
.compute_rest(prices, starting_indexes, exit)?;
Ok(())
}
fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn vecdb::AnyStoredVec> {
let mut vecs: Vec<&mut dyn vecdb::AnyStoredVec> = Vec::new();
vecs.extend(self.supply.collect_vecs_mut());
@@ -103,6 +201,37 @@ macro_rules! impl_cohort_metrics_base {
)
}
fn min_stateful_height_len(&self) -> usize {
self.inner.min_stateful_height_len()
}
fn truncate_push(
&mut self,
height: brk_types::Height,
state: &$crate::distribution::state::CohortState<$crate::distribution::state::RealizedState>,
) -> brk_error::Result<()> {
self.inner.truncate_push(height, state)
}
fn compute_rest_part1(
&mut self,
blocks: &$crate::blocks::Vecs,
prices: &$crate::prices::Vecs,
starting_indexes: &brk_types::Indexes,
exit: &vecdb::Exit,
) -> brk_error::Result<()> {
self.inner.compute_rest_part1(blocks, prices, starting_indexes, exit)
}
fn compute_base_from_others<T: $crate::distribution::metrics::CohortMetricsBase>(
&mut self,
starting_indexes: &brk_types::Indexes,
others: &[&T],
exit: &vecdb::Exit,
) -> brk_error::Result<()> {
self.inner.compute_base_from_others(starting_indexes, others, exit)
}
fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn vecdb::AnyStoredVec> {
self.inner.collect_all_vecs_mut()
}
@@ -115,10 +244,10 @@ macro_rules! impl_cohort_metrics_base {
fn supply_mut(&mut self) -> &mut $crate::distribution::metrics::SupplyMetrics { &mut self.supply }
fn outputs(&self) -> &$crate::distribution::metrics::OutputsMetrics { &self.outputs }
fn outputs_mut(&mut self) -> &mut $crate::distribution::metrics::OutputsMetrics { &mut self.outputs }
fn activity(&self) -> &$crate::distribution::metrics::ActivityMetrics { &self.activity }
fn activity_mut(&mut self) -> &mut $crate::distribution::metrics::ActivityMetrics { &mut self.activity }
fn realized_full(&self) -> &$crate::distribution::metrics::RealizedFull { &self.realized }
fn realized_full_mut(&mut self) -> &mut $crate::distribution::metrics::RealizedFull { &mut self.realized }
fn activity(&self) -> &$crate::distribution::metrics::ActivityFull { &self.activity }
fn activity_mut(&mut self) -> &mut $crate::distribution::metrics::ActivityFull { &mut self.activity }
fn realized_base(&self) -> &$crate::distribution::metrics::RealizedBase { &self.realized }
fn realized_base_mut(&mut self) -> &mut $crate::distribution::metrics::RealizedBase { &mut self.realized }
fn unrealized_full(&self) -> &$crate::distribution::metrics::UnrealizedFull { &self.unrealized }
fn unrealized_full_mut(&mut self) -> &mut $crate::distribution::metrics::UnrealizedFull { &mut self.unrealized }
fn cost_basis_base(&self) -> &$crate::distribution::metrics::CostBasisBase { &self.cost_basis }
@@ -131,10 +260,10 @@ macro_rules! impl_cohort_metrics_base {
fn supply_mut(&mut self) -> &mut $crate::distribution::metrics::SupplyMetrics { self.inner.supply_mut() }
fn outputs(&self) -> &$crate::distribution::metrics::OutputsMetrics { self.inner.outputs() }
fn outputs_mut(&mut self) -> &mut $crate::distribution::metrics::OutputsMetrics { self.inner.outputs_mut() }
fn activity(&self) -> &$crate::distribution::metrics::ActivityMetrics { self.inner.activity() }
fn activity_mut(&mut self) -> &mut $crate::distribution::metrics::ActivityMetrics { self.inner.activity_mut() }
fn realized_full(&self) -> &$crate::distribution::metrics::RealizedFull { self.inner.realized_full() }
fn realized_full_mut(&mut self) -> &mut $crate::distribution::metrics::RealizedFull { self.inner.realized_full_mut() }
fn activity(&self) -> &$crate::distribution::metrics::ActivityFull { self.inner.activity() }
fn activity_mut(&mut self) -> &mut $crate::distribution::metrics::ActivityFull { self.inner.activity_mut() }
fn realized_base(&self) -> &$crate::distribution::metrics::RealizedBase { self.inner.realized_base() }
fn realized_base_mut(&mut self) -> &mut $crate::distribution::metrics::RealizedBase { self.inner.realized_base_mut() }
fn unrealized_full(&self) -> &$crate::distribution::metrics::UnrealizedFull { self.inner.unrealized_full() }
fn unrealized_full_mut(&mut self) -> &mut $crate::distribution::metrics::UnrealizedFull { self.inner.unrealized_full_mut() }
fn cost_basis_base(&self) -> &$crate::distribution::metrics::CostBasisBase { self.inner.cost_basis_base() }
@@ -197,10 +326,10 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState> + Send
fn supply_mut(&mut self) -> &mut SupplyMetrics;
fn outputs(&self) -> &OutputsMetrics;
fn outputs_mut(&mut self) -> &mut OutputsMetrics;
fn activity(&self) -> &ActivityMetrics;
fn activity_mut(&mut self) -> &mut ActivityMetrics;
fn realized_full(&self) -> &RealizedFull;
fn realized_full_mut(&mut self) -> &mut RealizedFull;
fn activity(&self) -> &ActivityFull;
fn activity_mut(&mut self) -> &mut ActivityFull;
fn realized_base(&self) -> &RealizedBase;
fn realized_base_mut(&mut self) -> &mut RealizedBase;
fn unrealized_full(&self) -> &UnrealizedFull;
fn unrealized_full_mut(&mut self) -> &mut UnrealizedFull;
fn cost_basis_base(&self) -> &CostBasisBase;
@@ -242,7 +371,7 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState> + Send
.min_len()
.min(self.outputs().min_len())
.min(self.activity().min_len())
.min(self.realized_full().min_stateful_height_len())
.min(self.realized_base().min_stateful_height_len())
.min(self.unrealized_full().min_stateful_height_len())
.min(self.cost_basis_base().min_stateful_height_len())
}
@@ -258,7 +387,7 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState> + Send
state.satblocks_destroyed,
state.satdays_destroyed,
)?;
self.realized_full_mut()
self.realized_base_mut()
.truncate_push(height, &state.realized)?;
Ok(())
}
@@ -272,7 +401,7 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState> + Send
) -> Result<()> {
let weights: Vec<_> = others
.iter()
.map(|o| &o.realized_full().realized_cap.height)
.map(|o| &o.realized_base().realized_cap.height)
.collect();
let values: Vec<_> = others
.iter()
@@ -308,13 +437,13 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState> + Send
self.activity_mut()
.compute_rest_part1(blocks, prices, starting_indexes, exit)?;
self.realized_full_mut()
self.realized_base_mut()
.sent_in_profit
.compute(prices, starting_indexes.height, exit)?;
self.realized_full_mut()
self.realized_base_mut()
.sent_in_loss
.compute(prices, starting_indexes.height, exit)?;
self.realized_full_mut()
self.realized_base_mut()
.compute_rest_part1(starting_indexes, exit)?;
self.unrealized_full_mut()
@@ -354,7 +483,7 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState> + Send
aggregate!(supply_mut, supply);
aggregate!(outputs_mut, outputs);
aggregate!(activity_mut, activity);
aggregate!(realized_full_mut, realized_full);
aggregate!(realized_base_mut, realized_base);
aggregate!(unrealized_full_mut, unrealized_full);
aggregate!(cost_basis_base_mut, cost_basis_base);
Ok(())

View File

@@ -1,124 +1,172 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
BasisPoints32, Bitcoin, Cents, CentsSats, CentsSquaredSats, Dollars, Height, Indexes, Version,
BasisPoints32, BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Dollars, Height, Indexes,
StoredF64, Version,
};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use vecdb::{
AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, WritableVec,
};
use crate::{
blocks,
distribution::state::RealizedState,
distribution::state::RealizedOps,
internal::{
ComputedFromHeight, ComputedFromHeightCumulative, ComputedFromHeightRatio,
PercentFromHeight, PercentRollingEmas1w1m, PercentRollingWindows, Price, RatioCentsBp32,
ComputedFromHeight, ComputedFromHeightCumulative,
ComputedFromHeightRatioPercentiles, FiatFromHeight,
LazyFromHeight, NegCentsUnsignedToDollars, PercentFromHeight, RatioCents64,
RatioCentsBp32, RatioCentsSignedCentsBps32, RollingEmas1w1m, RollingEmas2w,
RollingWindows, ValueFromHeightCumulative,
},
prices,
};
use crate::distribution::metrics::ImportConfig;
use super::RealizedComplete;
use super::RealizedMinimal;
/// Full realized metrics (Source/Extended tier).
///
/// Contains all Complete-tier fields (via Deref to RealizedComplete) plus:
/// - Source-only: peak_regret, peak_regret_rel_to_realized_cap
/// - Extended-only: investor_price, price bands, cap_raw, sell_side_risk_ratio
#[derive(Deref, DerefMut, Traversable)]
pub struct RealizedFull<M: StorageMode = Rw> {
pub struct RealizedBase<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub complete: RealizedComplete<M>,
pub minimal: RealizedMinimal<M>,
// --- Extended-only fields ---
pub investor_price: Price<ComputedFromHeight<Cents, M>>,
pub investor_price_ratio: ComputedFromHeightRatio<M>,
pub realized_cap_change_1m: ComputedFromHeight<CentsSigned, M>,
pub lower_price_band: Price<ComputedFromHeight<Cents, M>>,
pub upper_price_band: Price<ComputedFromHeight<Cents, M>>,
pub neg_realized_loss: LazyFromHeight<Dollars, Cents>,
pub net_realized_pnl: ComputedFromHeightCumulative<CentsSigned, M>,
pub net_realized_pnl_ema_1w: ComputedFromHeight<CentsSigned, M>,
pub gross_pnl: FiatFromHeight<Cents, M>,
pub cap_raw: M::Stored<BytesVec<Height, CentsSats>>,
pub investor_cap_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
pub realized_profit_ema_1w: ComputedFromHeight<Cents, M>,
pub realized_loss_ema_1w: ComputedFromHeight<Cents, M>,
pub sell_side_risk_ratio: PercentRollingWindows<BasisPoints32, M>,
pub sell_side_risk_ratio_24h_ema: PercentRollingEmas1w1m<BasisPoints32, M>,
pub realized_profit_rel_to_realized_cap: PercentFromHeight<BasisPoints32, M>,
pub realized_loss_rel_to_realized_cap: PercentFromHeight<BasisPoints32, M>,
pub net_realized_pnl_rel_to_realized_cap: PercentFromHeight<BasisPointsSigned32, M>,
// --- Source-only fields ---
pub peak_regret: ComputedFromHeightCumulative<Cents, M>,
pub peak_regret_rel_to_realized_cap: PercentFromHeight<BasisPoints32, M>,
pub value_created: ComputedFromHeight<Cents, M>,
pub value_destroyed: ComputedFromHeight<Cents, M>,
pub value_created_sum: RollingWindows<Cents, M>,
pub value_destroyed_sum: RollingWindows<Cents, M>,
pub sopr: RollingWindows<StoredF64, M>,
pub sopr_24h_ema: RollingEmas1w1m<StoredF64, M>,
pub realized_price_ratio_percentiles: ComputedFromHeightRatioPercentiles<M>,
pub sent_in_profit: ValueFromHeightCumulative<M>,
pub sent_in_loss: ValueFromHeightCumulative<M>,
pub sent_in_profit_ema: RollingEmas2w<M>,
pub sent_in_loss_ema: RollingEmas2w<M>,
}
impl RealizedFull {
impl RealizedBase {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
let v1 = Version::ONE;
let complete = RealizedComplete::forced_import(cfg)?;
let minimal = RealizedMinimal::forced_import(cfg)?;
let investor_price = cfg.import_price("investor_price", v0)?;
let investor_price_ratio = cfg.import_ratio("investor_price", v0)?;
let lower_price_band = cfg.import_price("lower_price_band", v0)?;
let upper_price_band = cfg.import_price("upper_price_band", v0)?;
let neg_realized_loss = LazyFromHeight::from_height_source::<NegCentsUnsignedToDollars>(
&cfg.name("neg_realized_loss"),
cfg.version + Version::ONE,
minimal.realized_loss.height.read_only_boxed_clone(),
cfg.indexes,
);
let cap_raw = cfg.import_bytes("cap_raw", v0)?;
let investor_cap_raw = cfg.import_bytes("investor_cap_raw", v0)?;
let realized_profit_ema_1w = cfg.import_computed("realized_profit_ema_1w", v0)?;
let realized_loss_ema_1w = cfg.import_computed("realized_loss_ema_1w", v0)?;
let sell_side_risk_ratio =
cfg.import_percent_rolling_bp32("sell_side_risk_ratio", Version::new(2))?;
let sell_side_risk_ratio_24h_ema =
cfg.import_percent_emas_1w_1m_bp32("sell_side_risk_ratio_24h", Version::new(2))?;
let net_realized_pnl = cfg.import_cumulative("net_realized_pnl", v0)?;
let net_realized_pnl_ema_1w = cfg.import_computed("net_realized_pnl_ema_1w", v0)?;
let gross_pnl = cfg.import_fiat("realized_gross_pnl", v0)?;
let peak_regret = cfg.import_cumulative("realized_peak_regret", Version::new(2))?;
let peak_regret_rel_to_realized_cap =
cfg.import_percent_bp32("realized_peak_regret_rel_to_realized_cap", Version::new(2))?;
let realized_profit_rel_to_realized_cap =
cfg.import_percent_bp32("realized_profit_rel_to_realized_cap", Version::new(2))?;
let realized_loss_rel_to_realized_cap =
cfg.import_percent_bp32("realized_loss_rel_to_realized_cap", Version::new(2))?;
let net_realized_pnl_rel_to_realized_cap =
cfg.import_percent_bps32("net_realized_pnl_rel_to_realized_cap", Version::new(2))?;
let value_created = cfg.import_computed("value_created", v0)?;
let value_destroyed = cfg.import_computed("value_destroyed", v0)?;
let value_created_sum = cfg.import_rolling("value_created", v1)?;
let value_destroyed_sum = cfg.import_rolling("value_destroyed", v1)?;
let sopr = cfg.import_rolling("sopr", v1)?;
let sopr_24h_ema = cfg.import_emas_1w_1m("sopr_24h", v1)?;
let realized_price_ratio_percentiles =
ComputedFromHeightRatioPercentiles::forced_import(
cfg.db,
&cfg.name("realized_price"),
cfg.version + v1,
cfg.indexes,
)?;
Ok(Self {
complete,
investor_price,
investor_price_ratio,
lower_price_band,
upper_price_band,
cap_raw,
investor_cap_raw,
sell_side_risk_ratio,
sell_side_risk_ratio_24h_ema,
peak_regret,
peak_regret_rel_to_realized_cap,
minimal,
realized_cap_change_1m: cfg.import_computed("realized_cap_change_1m", v0)?,
neg_realized_loss,
net_realized_pnl,
net_realized_pnl_ema_1w,
gross_pnl,
realized_profit_ema_1w,
realized_loss_ema_1w,
realized_profit_rel_to_realized_cap,
realized_loss_rel_to_realized_cap,
net_realized_pnl_rel_to_realized_cap,
value_created,
value_destroyed,
value_created_sum,
value_destroyed_sum,
sopr,
sopr_24h_ema,
realized_price_ratio_percentiles,
sent_in_profit: cfg.import_value_cumulative("sent_in_profit", v0)?,
sent_in_loss: cfg.import_value_cumulative("sent_in_loss", v0)?,
sent_in_profit_ema: cfg.import_emas_2w("sent_in_profit", v0)?,
sent_in_loss_ema: cfg.import_emas_2w("sent_in_loss", v0)?,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.complete
self.minimal
.min_stateful_height_len()
.min(self.investor_price.cents.height.len())
.min(self.cap_raw.len())
.min(self.investor_cap_raw.len())
.min(self.peak_regret.height.len())
.min(self.value_created.height.len())
.min(self.value_destroyed.height.len())
.min(self.sent_in_profit.base.sats.height.len())
.min(self.sent_in_loss.base.sats.height.len())
}
pub(crate) fn truncate_push(&mut self, height: Height, state: &RealizedState) -> Result<()> {
self.complete.truncate_push(height, state)?;
self.investor_price
.cents
pub(crate) fn truncate_push(&mut self, height: Height, state: &impl RealizedOps) -> Result<()> {
self.minimal.truncate_push(height, state)?;
self.value_created
.height
.truncate_push(height, state.investor_price())?;
self.cap_raw.truncate_push(height, state.cap_raw())?;
self.investor_cap_raw
.truncate_push(height, state.investor_cap_raw())?;
self.peak_regret
.truncate_push(height, state.value_created())?;
self.value_destroyed
.height
.truncate_push(height, state.peak_regret())?;
.truncate_push(height, state.value_destroyed())?;
self.sent_in_profit
.base
.sats
.height
.truncate_push(height, state.sent_in_profit())?;
self.sent_in_loss
.base
.sats
.height
.truncate_push(height, state.sent_in_loss())?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.complete.collect_vecs_mut();
vecs.push(&mut self.investor_price.cents.height as &mut dyn AnyStoredVec);
vecs.push(&mut self.cap_raw as &mut dyn AnyStoredVec);
vecs.push(&mut self.investor_cap_raw as &mut dyn AnyStoredVec);
vecs.push(&mut self.peak_regret.height as &mut dyn AnyStoredVec);
let mut vecs = self.minimal.collect_vecs_mut();
vecs.push(&mut self.value_created.height as &mut dyn AnyStoredVec);
vecs.push(&mut self.value_destroyed.height);
vecs.push(&mut self.sent_in_profit.base.sats.height as &mut dyn AnyStoredVec);
vecs.push(&mut self.sent_in_loss.base.sats.height);
vecs
}
@@ -128,80 +176,14 @@ impl RealizedFull {
others: &[&Self],
exit: &Exit,
) -> Result<()> {
// Delegate Complete-tier aggregation
let complete_refs: Vec<&RealizedComplete> =
others.iter().map(|o| &o.complete).collect();
self.complete
.compute_from_stateful(starting_indexes, &complete_refs, exit)?;
let minimal_refs: Vec<&RealizedMinimal> = others.iter().map(|o| &o.minimal).collect();
self.minimal
.compute_from_stateful(starting_indexes, &minimal_refs, exit)?;
// Aggregate raw values for investor_price computation
let investor_price_dep_version = others
.iter()
.map(|o| o.investor_price.cents.height.version())
.fold(vecdb::Version::ZERO, |acc, v| acc + v);
self.investor_price
.cents
.height
.validate_computed_version_or_reset(investor_price_dep_version)?;
let start = self
.cap_raw
.len()
.min(self.investor_cap_raw.len())
.min(self.investor_price.cents.height.len());
let end = others.iter().map(|o| o.cap_raw.len()).min().unwrap_or(0);
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
let cap_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| o.cap_raw.collect_range_at(start, end))
.collect();
let investor_cap_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_raw.collect_range_at(start, end))
.collect();
for i in start..end {
let height = Height::from(i);
let local_i = i - start;
let mut sum_cap = CentsSats::ZERO;
let mut sum_investor_cap = CentsSquaredSats::ZERO;
for idx in 0..others.len() {
sum_cap += cap_ranges[idx][local_i];
sum_investor_cap += investor_cap_ranges[idx][local_i];
}
self.cap_raw.truncate_push(height, sum_cap)?;
self.investor_cap_raw
.truncate_push(height, sum_investor_cap)?;
let investor_price = if sum_cap.inner() == 0 {
Cents::ZERO
} else {
Cents::new((sum_investor_cap / sum_cap.inner()) as u64)
};
self.investor_price
.cents
.height
.truncate_push(height, investor_price)?;
}
{
let _lock = exit.lock();
self.investor_price.cents.height.write()?;
}
// Source-only: peak_regret
self.peak_regret.height.compute_sum_of_others(
starting_indexes.height,
&others
.iter()
.map(|v| &v.peak_regret.height)
.collect::<Vec<_>>(),
exit,
)?;
sum_others!(self, starting_indexes, others, exit; value_created.height);
sum_others!(self, starting_indexes, others, exit; value_destroyed.height);
sum_others!(self, starting_indexes, others, exit; sent_in_profit.base.sats.height);
sum_others!(self, starting_indexes, others, exit; sent_in_loss.base.sats.height);
Ok(())
}
@@ -211,10 +193,31 @@ impl RealizedFull {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.complete.compute_rest_part1(starting_indexes, exit)?;
self.minimal.compute_rest_part1(starting_indexes, exit)?;
self.peak_regret
.compute_rest(starting_indexes.height, exit)?;
self.net_realized_pnl
.compute(starting_indexes.height, exit, |vec| {
vec.compute_transform2(
starting_indexes.height,
&self.minimal.realized_profit.height,
&self.minimal.realized_loss.height,
|(i, profit, loss, ..)| {
(
i,
CentsSigned::new(profit.inner() as i64 - loss.inner() as i64),
)
},
exit,
)?;
Ok(())
})?;
self.gross_pnl.cents.height.compute_add(
starting_indexes.height,
&self.minimal.realized_profit.height,
&self.minimal.realized_loss.height,
exit,
)?;
Ok(())
}
@@ -225,91 +228,121 @@ impl RealizedFull {
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
// Compute all Complete-tier fields
self.complete.compute_rest_part2(
blocks,
prices,
starting_indexes,
height_to_supply,
height_to_market_cap,
exit,
)?;
self.minimal
.compute_rest_part2(prices, starting_indexes, height_to_supply, exit)?;
// Extended-only: investor_price ratio and price bands
self.investor_price_ratio.compute_ratio(
starting_indexes,
&prices.price.cents.height,
&self.investor_price.cents.height,
exit,
)?;
self.lower_price_band.cents.height.compute_transform2(
self.realized_cap_change_1m.height.compute_rolling_change(
starting_indexes.height,
&self.complete.realized_price.cents.height,
&self.investor_price.cents.height,
|(i, rp, ip, ..)| {
let rp = rp.as_u128();
let ip = ip.as_u128();
if ip == 0 {
(i, Cents::ZERO)
} else {
(i, Cents::from(rp * rp / ip))
}
},
&blocks.count.height_1m_ago,
&self.minimal.realized_cap_cents.height,
exit,
)?;
self.upper_price_band.cents.height.compute_transform2(
self.realized_profit_ema_1w.height.compute_rolling_ema(
starting_indexes.height,
&self.investor_price.cents.height,
&self.complete.realized_price.cents.height,
|(i, ip, rp, ..)| {
let ip = ip.as_u128();
let rp = rp.as_u128();
if rp == 0 {
(i, Cents::ZERO)
} else {
(i, Cents::from(ip * ip / rp))
}
},
&blocks.count.height_1w_ago,
&self.minimal.realized_profit.height,
exit,
)?;
self.realized_loss_ema_1w.height.compute_rolling_ema(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.minimal.realized_loss.height,
exit,
)?;
self.net_realized_pnl_ema_1w.height.compute_rolling_ema(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.net_realized_pnl.height,
exit,
)?;
// Extended-only: sell-side risk ratios
for (ssrr, rv) in self
.sell_side_risk_ratio
self.realized_profit_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(
starting_indexes.height,
&self.minimal.realized_profit.height,
&self.minimal.realized_cap_cents.height,
exit,
)?;
self.realized_loss_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(
starting_indexes.height,
&self.minimal.realized_loss.height,
&self.minimal.realized_cap_cents.height,
exit,
)?;
self.net_realized_pnl_rel_to_realized_cap
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps32>(
starting_indexes.height,
&self.net_realized_pnl.height,
&self.minimal.realized_cap_cents.height,
exit,
)?;
// SOPR: rolling sums of stateful value_created/destroyed, then ratio, then EMAs
let window_starts = blocks.count.window_starts();
self.value_created_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&self.value_created.height,
exit,
)?;
self.value_destroyed_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&self.value_destroyed.height,
exit,
)?;
for ((sopr, vc), vd) in self
.sopr
.as_mut_array()
.into_iter()
.zip(self.complete.gross_pnl_sum.as_array())
.zip(self.value_created_sum.as_array())
.zip(self.value_destroyed_sum.as_array())
{
ssrr.compute_binary::<Cents, Cents, RatioCentsBp32>(
sopr.compute_binary::<Cents, Cents, RatioCents64>(
starting_indexes.height,
&rv.height,
&self.complete.realized_cap_cents.height,
&vc.height,
&vd.height,
exit,
)?;
}
// Extended-only: sell side risk EMAs
self.sell_side_risk_ratio_24h_ema.compute_from_24h(
self.sopr_24h_ema.compute_from_24h(
starting_indexes.height,
&blocks.count.height_1w_ago,
&blocks.count.height_1m_ago,
&self.sell_side_risk_ratio._24h.bps.height,
&self.sopr._24h.height,
exit,
)?;
// Source-only: peak_regret relative to realized cap
self.peak_regret_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(
starting_indexes.height,
&self.peak_regret.height,
&self.complete.realized_cap_cents.height,
exit,
)?;
// Realized price ratio percentiles
self.realized_price_ratio_percentiles.compute(
blocks,
starting_indexes,
exit,
&self.minimal.realized_price_ratio.ratio.height,
&self.minimal.realized_price.cents.height,
)?;
// Sent in profit/loss EMAs
self.sent_in_profit_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent_in_profit.base.sats.height,
&self.sent_in_profit.base.cents.height,
exit,
)?;
self.sent_in_loss_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent_in_loss.base.sats.height,
&self.sent_in_loss.base.cents.height,
exit,
)?;
Ok(())
}

View File

@@ -1,245 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Dollars, Height, Indexes, Version,
};
use derive_more::{Deref, DerefMut};
use vecdb::{
AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, WritableVec,
};
use crate::{
blocks,
distribution::state::RealizedState,
internal::{
CentsUnsignedToDollars, ComputedFromHeight, LazyFromHeight, PercentFromHeight,
RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32, RollingEmas2w, RollingWindows,
ValueFromHeightCumulative,
},
prices,
};
use crate::distribution::metrics::ImportConfig;
use super::RealizedCore;
#[derive(Deref, DerefMut, Traversable)]
pub struct RealizedComplete<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub core: RealizedCore<M>,
pub profit_value_created: ComputedFromHeight<Cents, M>,
pub profit_value_destroyed: ComputedFromHeight<Cents, M>,
pub loss_value_created: ComputedFromHeight<Cents, M>,
pub loss_value_destroyed: ComputedFromHeight<Cents, M>,
pub capitulation_flow: LazyFromHeight<Dollars, Cents>,
pub profit_flow: LazyFromHeight<Dollars, Cents>,
pub gross_pnl_sum: RollingWindows<Cents, M>,
pub net_pnl_change_1m: ComputedFromHeight<CentsSigned, M>,
pub net_pnl_change_1m_rel_to_realized_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub net_pnl_change_1m_rel_to_market_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub sent_in_profit: ValueFromHeightCumulative<M>,
pub sent_in_profit_ema: RollingEmas2w<M>,
pub sent_in_loss: ValueFromHeightCumulative<M>,
pub sent_in_loss_ema: RollingEmas2w<M>,
}
impl RealizedComplete {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
let core = RealizedCore::forced_import(cfg)?;
let profit_value_created = cfg.import_computed("profit_value_created", v0)?;
let profit_value_destroyed = cfg.import_computed("profit_value_destroyed", v0)?;
let loss_value_created = cfg.import_computed("loss_value_created", v0)?;
let loss_value_destroyed = cfg.import_computed("loss_value_destroyed", v0)?;
let capitulation_flow = LazyFromHeight::from_computed::<CentsUnsignedToDollars>(
&cfg.name("capitulation_flow"),
cfg.version,
loss_value_destroyed.height.read_only_boxed_clone(),
&loss_value_destroyed,
);
let profit_flow = LazyFromHeight::from_computed::<CentsUnsignedToDollars>(
&cfg.name("profit_flow"),
cfg.version,
profit_value_destroyed.height.read_only_boxed_clone(),
&profit_value_destroyed,
);
let gross_pnl_sum = cfg.import_rolling("gross_pnl_sum", Version::ONE)?;
Ok(Self {
core,
profit_value_created,
profit_value_destroyed,
loss_value_created,
loss_value_destroyed,
capitulation_flow,
profit_flow,
gross_pnl_sum,
net_pnl_change_1m: cfg.import_computed("net_pnl_change_1m", Version::new(3))?,
net_pnl_change_1m_rel_to_realized_cap: cfg
.import_percent_bps32("net_pnl_change_1m_rel_to_realized_cap", Version::new(4))?,
net_pnl_change_1m_rel_to_market_cap: cfg
.import_percent_bps32("net_pnl_change_1m_rel_to_market_cap", Version::new(4))?,
sent_in_profit: cfg.import_value_cumulative("sent_in_profit", v0)?,
sent_in_profit_ema: cfg.import_emas_2w("sent_in_profit", v0)?,
sent_in_loss: cfg.import_value_cumulative("sent_in_loss", v0)?,
sent_in_loss_ema: cfg.import_emas_2w("sent_in_loss", v0)?,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.core
.min_stateful_height_len()
.min(self.profit_value_created.height.len())
.min(self.profit_value_destroyed.height.len())
.min(self.loss_value_created.height.len())
.min(self.loss_value_destroyed.height.len())
.min(self.sent_in_profit.base.sats.height.len())
.min(self.sent_in_loss.base.sats.height.len())
}
pub(crate) fn truncate_push(&mut self, height: Height, state: &RealizedState) -> Result<()> {
self.core.truncate_push(height, state)?;
self.profit_value_created
.height
.truncate_push(height, state.profit_value_created())?;
self.profit_value_destroyed
.height
.truncate_push(height, state.profit_value_destroyed())?;
self.loss_value_created
.height
.truncate_push(height, state.loss_value_created())?;
self.loss_value_destroyed
.height
.truncate_push(height, state.loss_value_destroyed())?;
self.sent_in_profit
.base
.sats
.height
.truncate_push(height, state.sent_in_profit())?;
self.sent_in_loss
.base
.sats
.height
.truncate_push(height, state.sent_in_loss())?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.core.collect_vecs_mut();
vecs.push(&mut self.profit_value_created.height as &mut dyn AnyStoredVec);
vecs.push(&mut self.profit_value_destroyed.height);
vecs.push(&mut self.loss_value_created.height);
vecs.push(&mut self.loss_value_destroyed.height);
vecs.push(&mut self.sent_in_profit.base.sats.height);
vecs.push(&mut self.sent_in_loss.base.sats.height);
vecs
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
let core_refs: Vec<&RealizedCore> = others.iter().map(|o| &o.core).collect();
self.core
.compute_from_stateful(starting_indexes, &core_refs, exit)?;
sum_others!(self, starting_indexes, others, exit; profit_value_created.height);
sum_others!(self, starting_indexes, others, exit; profit_value_destroyed.height);
sum_others!(self, starting_indexes, others, exit; loss_value_created.height);
sum_others!(self, starting_indexes, others, exit; loss_value_destroyed.height);
sum_others!(self, starting_indexes, others, exit; sent_in_profit.base.sats.height);
sum_others!(self, starting_indexes, others, exit; sent_in_loss.base.sats.height);
Ok(())
}
pub(crate) fn compute_rest_part1(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.core.compute_rest_part1(starting_indexes, exit)?;
Ok(())
}
pub(crate) fn compute_rest_part2(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.core.compute_rest_part2(
blocks,
prices,
starting_indexes,
height_to_supply,
exit,
)?;
let window_starts = blocks.count.window_starts();
self.gross_pnl_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&self.core.gross_pnl.cents.height,
exit,
)?;
self.sent_in_profit_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent_in_profit.base.sats.height,
&self.sent_in_profit.base.cents.height,
exit,
)?;
self.sent_in_loss_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent_in_loss.base.sats.height,
&self.sent_in_loss.base.cents.height,
exit,
)?;
self.net_pnl_change_1m.height.compute_rolling_change(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.core.net_realized_pnl.cumulative.height,
exit,
)?;
self.net_pnl_change_1m_rel_to_realized_cap
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps32>(
starting_indexes.height,
&self.net_pnl_change_1m.height,
&self.core.realized_cap_cents.height,
exit,
)?;
self.net_pnl_change_1m_rel_to_market_cap
.compute_binary::<CentsSigned, Dollars, RatioCentsSignedDollarsBps32>(
starting_indexes.height,
&self.net_pnl_change_1m.height,
height_to_market_cap,
exit,
)?;
Ok(())
}
}

View File

@@ -1,347 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
BasisPoints32, BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Dollars, Height, Indexes,
Sats, StoredF32, StoredF64, Version,
};
use vecdb::{
AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, WritableVec,
};
use crate::{
blocks,
distribution::state::RealizedOps,
internal::{
CentsUnsignedToDollars, ComputedFromHeight, ComputedFromHeightCumulative,
ComputedFromHeightRatio, FiatFromHeight, Identity, LazyFromHeight,
NegCentsUnsignedToDollars, PercentFromHeight, Price, RatioCents64, RatioCentsBp32,
RatioCentsSignedCentsBps32, RollingEmas1w1m, RollingWindows,
},
prices,
};
use crate::distribution::metrics::ImportConfig;
#[derive(Traversable)]
pub struct RealizedCore<M: StorageMode = Rw> {
pub realized_cap_cents: ComputedFromHeight<Cents, M>,
pub realized_profit: ComputedFromHeightCumulative<Cents, M>,
pub realized_loss: ComputedFromHeightCumulative<Cents, M>,
pub realized_cap: LazyFromHeight<Dollars, Cents>,
pub realized_price: Price<ComputedFromHeight<Cents, M>>,
pub realized_price_ratio: ComputedFromHeightRatio<M>,
pub realized_cap_change_1m: ComputedFromHeight<CentsSigned, M>,
pub mvrv: LazyFromHeight<StoredF32>,
pub neg_realized_loss: LazyFromHeight<Dollars, Cents>,
pub net_realized_pnl: ComputedFromHeightCumulative<CentsSigned, M>,
pub net_realized_pnl_ema_1w: ComputedFromHeight<CentsSigned, M>,
pub gross_pnl: FiatFromHeight<Cents, M>,
pub realized_profit_ema_1w: ComputedFromHeight<Cents, M>,
pub realized_loss_ema_1w: ComputedFromHeight<Cents, M>,
pub realized_profit_rel_to_realized_cap: PercentFromHeight<BasisPoints32, M>,
pub realized_loss_rel_to_realized_cap: PercentFromHeight<BasisPoints32, M>,
pub net_realized_pnl_rel_to_realized_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub value_created: ComputedFromHeight<Cents, M>,
pub value_destroyed: ComputedFromHeight<Cents, M>,
pub value_created_sum: RollingWindows<Cents, M>,
pub value_destroyed_sum: RollingWindows<Cents, M>,
pub sopr: RollingWindows<StoredF64, M>,
pub sopr_24h_ema: RollingEmas1w1m<StoredF64, M>,
}
impl RealizedCore {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
let v1 = Version::ONE;
let realized_cap_cents = cfg.import_computed("realized_cap_cents", v0)?;
let realized_cap = LazyFromHeight::from_computed::<CentsUnsignedToDollars>(
&cfg.name("realized_cap"),
cfg.version,
realized_cap_cents.height.read_only_boxed_clone(),
&realized_cap_cents,
);
let realized_profit = cfg.import_cumulative("realized_profit", v0)?;
let realized_profit_ema_1w = cfg.import_computed("realized_profit_ema_1w", v0)?;
let realized_loss = cfg.import_cumulative("realized_loss", v0)?;
let realized_loss_ema_1w = cfg.import_computed("realized_loss_ema_1w", v0)?;
let neg_realized_loss = LazyFromHeight::from_height_source::<NegCentsUnsignedToDollars>(
&cfg.name("neg_realized_loss"),
cfg.version + Version::ONE,
realized_loss.height.read_only_boxed_clone(),
cfg.indexes,
);
let net_realized_pnl = cfg.import_cumulative("net_realized_pnl", v0)?;
let net_realized_pnl_ema_1w = cfg.import_computed("net_realized_pnl_ema_1w", v0)?;
let gross_pnl = cfg.import_fiat("realized_gross_pnl", v0)?;
let realized_profit_rel_to_realized_cap =
cfg.import_percent_bp32("realized_profit_rel_to_realized_cap", Version::new(2))?;
let realized_loss_rel_to_realized_cap =
cfg.import_percent_bp32("realized_loss_rel_to_realized_cap", Version::new(2))?;
let net_realized_pnl_rel_to_realized_cap =
cfg.import_percent_bps32("net_realized_pnl_rel_to_realized_cap", Version::new(2))?;
let realized_price = cfg.import_price("realized_price", v1)?;
let realized_price_ratio = cfg.import_ratio("realized_price", v1)?;
let mvrv = LazyFromHeight::from_lazy::<Identity<StoredF32>, BasisPoints32>(
&cfg.name("mvrv"),
cfg.version,
&realized_price_ratio.ratio,
);
let value_created = cfg.import_computed("value_created", v0)?;
let value_destroyed = cfg.import_computed("value_destroyed", v0)?;
let value_created_sum = cfg.import_rolling("value_created", v1)?;
let value_destroyed_sum = cfg.import_rolling("value_destroyed", v1)?;
let sopr = cfg.import_rolling("sopr", v1)?;
let sopr_24h_ema = cfg.import_emas_1w_1m("sopr_24h", v1)?;
Ok(Self {
realized_cap_cents,
realized_cap,
realized_price,
realized_price_ratio,
realized_cap_change_1m: cfg.import_computed("realized_cap_change_1m", v0)?,
mvrv,
realized_profit,
realized_profit_ema_1w,
realized_loss,
realized_loss_ema_1w,
neg_realized_loss,
net_realized_pnl,
net_realized_pnl_ema_1w,
gross_pnl,
realized_profit_rel_to_realized_cap,
realized_loss_rel_to_realized_cap,
net_realized_pnl_rel_to_realized_cap,
value_created,
value_destroyed,
value_created_sum,
value_destroyed_sum,
sopr,
sopr_24h_ema,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.realized_cap_cents
.height
.len()
.min(self.realized_profit.height.len())
.min(self.realized_loss.height.len())
.min(self.value_created.height.len())
.min(self.value_destroyed.height.len())
}
pub(crate) fn truncate_push(&mut self, height: Height, state: &impl RealizedOps) -> Result<()> {
self.realized_cap_cents
.height
.truncate_push(height, state.cap())?;
self.realized_profit
.height
.truncate_push(height, state.profit())?;
self.realized_loss
.height
.truncate_push(height, state.loss())?;
self.value_created
.height
.truncate_push(height, state.value_created())?;
self.value_destroyed
.height
.truncate_push(height, state.value_destroyed())?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.realized_cap_cents.height as &mut dyn AnyStoredVec,
&mut self.realized_profit.height,
&mut self.realized_loss.height,
&mut self.value_created.height,
&mut self.value_destroyed.height,
]
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
sum_others!(self, starting_indexes, others, exit; realized_cap_cents.height);
sum_others!(self, starting_indexes, others, exit; realized_profit.height);
sum_others!(self, starting_indexes, others, exit; realized_loss.height);
sum_others!(self, starting_indexes, others, exit; value_created.height);
sum_others!(self, starting_indexes, others, exit; value_destroyed.height);
Ok(())
}
pub(crate) fn compute_rest_part1(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.realized_profit
.compute_rest(starting_indexes.height, exit)?;
self.realized_loss
.compute_rest(starting_indexes.height, exit)?;
self.net_realized_pnl
.compute(starting_indexes.height, exit, |vec| {
vec.compute_transform2(
starting_indexes.height,
&self.realized_profit.height,
&self.realized_loss.height,
|(i, profit, loss, ..)| {
(
i,
CentsSigned::new(profit.inner() as i64 - loss.inner() as i64),
)
},
exit,
)?;
Ok(())
})?;
self.gross_pnl.cents.height.compute_add(
starting_indexes.height,
&self.realized_profit.height,
&self.realized_loss.height,
exit,
)?;
Ok(())
}
pub(crate) fn compute_rest_part2(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
exit: &Exit,
) -> Result<()> {
self.realized_price.cents.height.compute_transform2(
starting_indexes.height,
&self.realized_cap_cents.height,
height_to_supply,
|(i, cap_cents, supply, ..)| {
let cap = cap_cents.as_u128();
let supply_sats = Sats::from(supply).as_u128();
if supply_sats == 0 {
(i, Cents::ZERO)
} else {
(i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats))
}
},
exit,
)?;
self.realized_price_ratio.compute_ratio(
starting_indexes,
&prices.price.cents.height,
&self.realized_price.cents.height,
exit,
)?;
self.realized_cap_change_1m.height.compute_rolling_change(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.realized_cap_cents.height,
exit,
)?;
self.realized_profit_ema_1w.height.compute_rolling_ema(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.realized_profit.height,
exit,
)?;
self.realized_loss_ema_1w.height.compute_rolling_ema(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.realized_loss.height,
exit,
)?;
self.net_realized_pnl_ema_1w.height.compute_rolling_ema(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.net_realized_pnl.height,
exit,
)?;
self.realized_profit_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(
starting_indexes.height,
&self.realized_profit.height,
&self.realized_cap_cents.height,
exit,
)?;
self.realized_loss_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(
starting_indexes.height,
&self.realized_loss.height,
&self.realized_cap_cents.height,
exit,
)?;
self.net_realized_pnl_rel_to_realized_cap
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps32>(
starting_indexes.height,
&self.net_realized_pnl.height,
&self.realized_cap_cents.height,
exit,
)?;
// SOPR: rolling sums of stateful value_created/destroyed, then ratio, then EMAs
let window_starts = blocks.count.window_starts();
self.value_created_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&self.value_created.height,
exit,
)?;
self.value_destroyed_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&self.value_destroyed.height,
exit,
)?;
for ((sopr, vc), vd) in self
.sopr
.as_mut_array()
.into_iter()
.zip(self.value_created_sum.as_array())
.zip(self.value_destroyed_sum.as_array())
{
sopr.compute_binary::<Cents, Cents, RatioCents64>(
starting_indexes.height,
&vc.height,
&vd.height,
exit,
)?;
}
self.sopr_24h_ema.compute_from_24h(
starting_indexes.height,
&blocks.count.height_1w_ago,
&blocks.count.height_1m_ago,
&self.sopr._24h.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,160 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints32, Cents, Dollars, Height, Indexes, StoredF64, Version};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{
blocks,
internal::{
ComputedFromHeightRatioPercentiles, ComputedFromHeightRatioStdDevBands,
PercentFromHeight, RatioCents64, RatioDollarsBp32, RollingWindows,
},
prices,
};
use crate::distribution::metrics::ImportConfig;
use super::RealizedFull;
#[derive(Traversable)]
pub struct RealizedExtended<M: StorageMode = Rw> {
pub realized_cap_rel_to_own_market_cap: PercentFromHeight<BasisPoints32, M>,
pub realized_profit_sum: RollingWindows<Cents, M>,
pub realized_loss_sum: RollingWindows<Cents, M>,
pub realized_profit_to_loss_ratio: RollingWindows<StoredF64, M>,
pub realized_price_ratio_percentiles: ComputedFromHeightRatioPercentiles<M>,
pub realized_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands<M>,
pub investor_price_ratio_percentiles: ComputedFromHeightRatioPercentiles<M>,
pub investor_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands<M>,
}
impl RealizedExtended {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let realized_price_name = cfg.name("realized_price");
let realized_price_version = cfg.version + Version::ONE;
let investor_price_name = cfg.name("investor_price");
let investor_price_version = cfg.version;
Ok(RealizedExtended {
realized_cap_rel_to_own_market_cap: cfg
.import_percent_bp32("realized_cap_rel_to_own_market_cap", Version::ONE)?,
realized_profit_sum: cfg.import_rolling("realized_profit", Version::ONE)?,
realized_loss_sum: cfg.import_rolling("realized_loss", Version::ONE)?,
realized_profit_to_loss_ratio: cfg
.import_rolling("realized_profit_to_loss_ratio", Version::ONE)?,
realized_price_ratio_percentiles: ComputedFromHeightRatioPercentiles::forced_import(
cfg.db,
&realized_price_name,
realized_price_version,
cfg.indexes,
)?,
realized_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
cfg.db,
&realized_price_name,
realized_price_version,
cfg.indexes,
)?,
investor_price_ratio_percentiles: ComputedFromHeightRatioPercentiles::forced_import(
cfg.db,
&investor_price_name,
investor_price_version,
cfg.indexes,
)?,
investor_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
cfg.db,
&investor_price_name,
investor_price_version,
cfg.indexes,
)?,
})
}
pub(crate) fn compute_rest_part2(
&mut self,
base: &RealizedFull,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
// Realized profit/loss rolling sums
let window_starts = blocks.count.window_starts();
self.realized_profit_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&base.realized_profit.height,
exit,
)?;
self.realized_loss_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&base.realized_loss.height,
exit,
)?;
// Realized cap relative to own market cap
self.realized_cap_rel_to_own_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
starting_indexes.height,
&base.realized_cap.height,
height_to_market_cap,
exit,
)?;
// Realized profit to loss ratios
for ((ratio, profit), loss) in self
.realized_profit_to_loss_ratio
.as_mut_array()
.into_iter()
.zip(self.realized_profit_sum.as_array())
.zip(self.realized_loss_sum.as_array())
{
ratio.compute_binary::<Cents, Cents, RatioCents64>(
starting_indexes.height,
&profit.height,
&loss.height,
exit,
)?;
}
// Realized price: percentiles + stddev bands
let realized_price = &base.realized_price.cents.height;
self.realized_price_ratio_percentiles.compute(
blocks,
starting_indexes,
exit,
&base.realized_price_ratio.ratio.height,
realized_price,
)?;
self.realized_price_ratio_std_dev.compute(
blocks,
starting_indexes,
exit,
&base.realized_price_ratio.ratio.height,
realized_price,
)?;
// Investor price: percentiles + stddev bands
let investor_price = &base.investor_price.cents.height;
self.investor_price_ratio_percentiles.compute(
blocks,
starting_indexes,
exit,
&base.investor_price_ratio.ratio.height,
investor_price,
)?;
self.investor_price_ratio_std_dev.compute(
blocks,
starting_indexes,
exit,
&base.investor_price_ratio.ratio.height,
investor_price,
)?;
Ok(())
}
}

View File

@@ -2,7 +2,7 @@ use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
BasisPoints32, BasisPointsSigned32, Bitcoin, Cents, CentsSats, CentsSigned, CentsSquaredSats,
Dollars, Height, Indexes, Version,
Dollars, Height, Indexes, StoredF64, Version,
};
use derive_more::{Deref, DerefMut};
use vecdb::{
@@ -15,26 +15,26 @@ use crate::{
distribution::state::RealizedState,
internal::{
CentsUnsignedToDollars, ComputedFromHeight, ComputedFromHeightCumulative,
ComputedFromHeightRatio, ComputedFromHeightRatioPercentiles, LazyFromHeight,
PercentFromHeight, PercentRollingEmas1w1m, PercentRollingWindows, Price, RatioCentsBp32,
RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32, RollingEmas2w, RollingWindows,
ValueFromHeightCumulative,
ComputedFromHeightRatio, ComputedFromHeightRatioPercentiles,
ComputedFromHeightRatioStdDevBands, LazyFromHeight, PercentFromHeight,
PercentRollingEmas1w1m, PercentRollingWindows, Price, RatioCents64, RatioCentsBp32,
RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32, RatioDollarsBp32,
RollingWindows,
},
prices,
};
use crate::distribution::metrics::ImportConfig;
use super::RealizedCore;
use super::RealizedBase;
#[derive(Deref, DerefMut, Traversable)]
pub struct RealizedBasic<M: StorageMode = Rw> {
pub struct RealizedFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub core: RealizedCore<M>,
pub core: RealizedBase<M>,
// --- Stateful fields ---
pub profit_value_created: ComputedFromHeight<Cents, M>,
pub profit_value_destroyed: ComputedFromHeight<Cents, M>,
pub loss_value_created: ComputedFromHeight<Cents, M>,
@@ -49,12 +49,6 @@ pub struct RealizedBasic<M: StorageMode = Rw> {
pub net_pnl_change_1m_rel_to_realized_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub net_pnl_change_1m_rel_to_market_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub sent_in_profit: ValueFromHeightCumulative<M>,
pub sent_in_profit_ema: RollingEmas2w<M>,
pub sent_in_loss: ValueFromHeightCumulative<M>,
pub sent_in_loss_ema: RollingEmas2w<M>,
// --- Investor price & price bands ---
pub investor_price: Price<ComputedFromHeight<Cents, M>>,
pub investor_price_ratio: ComputedFromHeightRatio<M>,
@@ -67,22 +61,27 @@ pub struct RealizedBasic<M: StorageMode = Rw> {
pub sell_side_risk_ratio: PercentRollingWindows<BasisPoints32, M>,
pub sell_side_risk_ratio_24h_ema: PercentRollingEmas1w1m<BasisPoints32, M>,
// --- Peak regret ---
pub peak_regret: ComputedFromHeightCumulative<Cents, M>,
pub peak_regret_rel_to_realized_cap: PercentFromHeight<BasisPoints32, M>,
// --- Realized price ratio percentiles ---
pub realized_price_ratio_percentiles: ComputedFromHeightRatioPercentiles<M>,
pub realized_cap_rel_to_own_market_cap: PercentFromHeight<BasisPoints32, M>,
pub realized_profit_sum: RollingWindows<Cents, M>,
pub realized_loss_sum: RollingWindows<Cents, M>,
pub realized_profit_to_loss_ratio: RollingWindows<StoredF64, M>,
pub realized_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands<M>,
pub investor_price_ratio_percentiles: ComputedFromHeightRatioPercentiles<M>,
pub investor_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands<M>,
}
impl RealizedBasic {
impl RealizedFull {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
let v1 = Version::ONE;
let core = RealizedCore::forced_import(cfg)?;
let core = RealizedBase::forced_import(cfg)?;
// Stateful fields
let profit_value_created = cfg.import_computed("profit_value_created", v0)?;
let profit_value_destroyed = cfg.import_computed("profit_value_destroyed", v0)?;
let loss_value_created = cfg.import_computed("loss_value_created", v0)?;
@@ -101,9 +100,8 @@ impl RealizedBasic {
&profit_value_destroyed,
);
let gross_pnl_sum = cfg.import_rolling("gross_pnl_sum", v1)?;
let gross_pnl_sum = cfg.import_rolling("gross_pnl_sum", Version::ONE)?;
// Investor price & price bands
let investor_price = cfg.import_price("investor_price", v0)?;
let investor_price_ratio = cfg.import_ratio("investor_price", v0)?;
let lower_price_band = cfg.import_price("lower_price_band", v0)?;
@@ -117,19 +115,14 @@ impl RealizedBasic {
let sell_side_risk_ratio_24h_ema =
cfg.import_percent_emas_1w_1m_bp32("sell_side_risk_ratio_24h", Version::new(2))?;
// Peak regret
let peak_regret = cfg.import_cumulative("realized_peak_regret", Version::new(2))?;
let peak_regret_rel_to_realized_cap =
cfg.import_percent_bp32("realized_peak_regret_rel_to_realized_cap", Version::new(2))?;
// Realized price ratio percentiles
let realized_price_ratio_percentiles =
ComputedFromHeightRatioPercentiles::forced_import(
cfg.db,
&cfg.name("realized_price"),
cfg.version + v1,
cfg.indexes,
)?;
let realized_price_name = cfg.name("realized_price");
let realized_price_version = cfg.version + v1;
let investor_price_name = cfg.name("investor_price");
let investor_price_version = cfg.version;
Ok(Self {
core,
@@ -145,10 +138,6 @@ impl RealizedBasic {
.import_percent_bps32("net_pnl_change_1m_rel_to_realized_cap", Version::new(4))?,
net_pnl_change_1m_rel_to_market_cap: cfg
.import_percent_bps32("net_pnl_change_1m_rel_to_market_cap", Version::new(4))?,
sent_in_profit: cfg.import_value_cumulative("sent_in_profit", v0)?,
sent_in_profit_ema: cfg.import_emas_2w("sent_in_profit", v0)?,
sent_in_loss: cfg.import_value_cumulative("sent_in_loss", v0)?,
sent_in_loss_ema: cfg.import_emas_2w("sent_in_loss", v0)?,
investor_price,
investor_price_ratio,
lower_price_band,
@@ -159,7 +148,30 @@ impl RealizedBasic {
sell_side_risk_ratio_24h_ema,
peak_regret,
peak_regret_rel_to_realized_cap,
realized_price_ratio_percentiles,
realized_cap_rel_to_own_market_cap: cfg
.import_percent_bp32("realized_cap_rel_to_own_market_cap", v1)?,
realized_profit_sum: cfg.import_rolling("realized_profit", v1)?,
realized_loss_sum: cfg.import_rolling("realized_loss", v1)?,
realized_profit_to_loss_ratio: cfg
.import_rolling("realized_profit_to_loss_ratio", v1)?,
realized_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
cfg.db,
&realized_price_name,
realized_price_version,
cfg.indexes,
)?,
investor_price_ratio_percentiles: ComputedFromHeightRatioPercentiles::forced_import(
cfg.db,
&investor_price_name,
investor_price_version,
cfg.indexes,
)?,
investor_price_ratio_std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
cfg.db,
&investor_price_name,
investor_price_version,
cfg.indexes,
)?,
})
}
@@ -170,8 +182,6 @@ impl RealizedBasic {
.min(self.profit_value_destroyed.height.len())
.min(self.loss_value_created.height.len())
.min(self.loss_value_destroyed.height.len())
.min(self.sent_in_profit.base.sats.height.len())
.min(self.sent_in_loss.base.sats.height.len())
.min(self.investor_price.cents.height.len())
.min(self.cap_raw.len())
.min(self.investor_cap_raw.len())
@@ -192,16 +202,6 @@ impl RealizedBasic {
self.loss_value_destroyed
.height
.truncate_push(height, state.loss_value_destroyed())?;
self.sent_in_profit
.base
.sats
.height
.truncate_push(height, state.sent_in_profit())?;
self.sent_in_loss
.base
.sats
.height
.truncate_push(height, state.sent_in_loss())?;
self.investor_price
.cents
.height
@@ -222,8 +222,6 @@ impl RealizedBasic {
vecs.push(&mut self.profit_value_destroyed.height);
vecs.push(&mut self.loss_value_created.height);
vecs.push(&mut self.loss_value_destroyed.height);
vecs.push(&mut self.sent_in_profit.base.sats.height);
vecs.push(&mut self.sent_in_loss.base.sats.height);
vecs.push(&mut self.investor_price.cents.height);
vecs.push(&mut self.cap_raw as &mut dyn AnyStoredVec);
vecs.push(&mut self.investor_cap_raw as &mut dyn AnyStoredVec);
@@ -231,92 +229,16 @@ impl RealizedBasic {
vecs
}
/// Aggregate Core-level fields from source cohorts.
/// investor_price, cap_raw, investor_cap_raw come from the stateful scan, not aggregated.
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
others: &[&RealizedBase],
exit: &Exit,
) -> Result<()> {
// Core aggregation
let core_refs: Vec<&RealizedCore> = others.iter().map(|o| &o.core).collect();
self.core
.compute_from_stateful(starting_indexes, &core_refs, exit)?;
// Stateful field aggregation
sum_others!(self, starting_indexes, others, exit; profit_value_created.height);
sum_others!(self, starting_indexes, others, exit; profit_value_destroyed.height);
sum_others!(self, starting_indexes, others, exit; loss_value_created.height);
sum_others!(self, starting_indexes, others, exit; loss_value_destroyed.height);
sum_others!(self, starting_indexes, others, exit; sent_in_profit.base.sats.height);
sum_others!(self, starting_indexes, others, exit; sent_in_loss.base.sats.height);
// Investor price aggregation from raw values
let investor_price_dep_version = others
.iter()
.map(|o| o.investor_price.cents.height.version())
.fold(vecdb::Version::ZERO, |acc, v| acc + v);
self.investor_price
.cents
.height
.validate_computed_version_or_reset(investor_price_dep_version)?;
let start = self
.cap_raw
.len()
.min(self.investor_cap_raw.len())
.min(self.investor_price.cents.height.len());
let end = others.iter().map(|o| o.cap_raw.len()).min().unwrap_or(0);
let cap_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| o.cap_raw.collect_range_at(start, end))
.collect();
let investor_cap_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_raw.collect_range_at(start, end))
.collect();
for i in start..end {
let height = Height::from(i);
let local_i = i - start;
let mut sum_cap = CentsSats::ZERO;
let mut sum_investor_cap = CentsSquaredSats::ZERO;
for idx in 0..others.len() {
sum_cap += cap_ranges[idx][local_i];
sum_investor_cap += investor_cap_ranges[idx][local_i];
}
self.cap_raw.truncate_push(height, sum_cap)?;
self.investor_cap_raw
.truncate_push(height, sum_investor_cap)?;
let investor_price = if sum_cap.inner() == 0 {
Cents::ZERO
} else {
Cents::new((sum_investor_cap / sum_cap.inner()) as u64)
};
self.investor_price
.cents
.height
.truncate_push(height, investor_price)?;
}
{
let _lock = exit.lock();
self.investor_price.cents.height.write()?;
}
// Peak regret aggregation
self.peak_regret.height.compute_sum_of_others(
starting_indexes.height,
&others
.iter()
.map(|v| &v.peak_regret.height)
.collect::<Vec<_>>(),
exit,
)?;
.compute_from_stateful(starting_indexes, others, exit)?;
Ok(())
}
@@ -329,7 +251,6 @@ impl RealizedBasic {
self.core.compute_rest_part1(starting_indexes, exit)?;
self.peak_regret
.compute_rest(starting_indexes.height, exit)?;
Ok(())
}
@@ -342,7 +263,6 @@ impl RealizedBasic {
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
// Core computation
self.core.compute_rest_part2(
blocks,
prices,
@@ -351,7 +271,7 @@ impl RealizedBasic {
exit,
)?;
// Gross PnL rolling sums
// Gross PnL rolling sum
let window_starts = blocks.count.window_starts();
self.gross_pnl_sum.compute_rolling_sum(
starting_indexes.height,
@@ -360,22 +280,6 @@ impl RealizedBasic {
exit,
)?;
// Sent in profit/loss EMAs
self.sent_in_profit_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent_in_profit.base.sats.height,
&self.sent_in_profit.base.cents.height,
exit,
)?;
self.sent_in_loss_ema.compute(
starting_indexes.height,
&blocks.count.height_2w_ago,
&self.sent_in_loss.base.sats.height,
&self.sent_in_loss.base.cents.height,
exit,
)?;
// Net PnL change 1m
self.net_pnl_change_1m.height.compute_rolling_change(
starting_indexes.height,
@@ -383,15 +287,13 @@ impl RealizedBasic {
&self.core.net_realized_pnl.cumulative.height,
exit,
)?;
self.net_pnl_change_1m_rel_to_realized_cap
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps32>(
starting_indexes.height,
&self.net_pnl_change_1m.height,
&self.core.realized_cap_cents.height,
&self.core.minimal.realized_cap_cents.height,
exit,
)?;
self.net_pnl_change_1m_rel_to_market_cap
.compute_binary::<CentsSigned, Dollars, RatioCentsSignedDollarsBps32>(
starting_indexes.height,
@@ -400,6 +302,15 @@ impl RealizedBasic {
exit,
)?;
// Peak regret
self.peak_regret_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(
starting_indexes.height,
&self.peak_regret.height,
&self.core.minimal.realized_cap_cents.height,
exit,
)?;
// Investor price ratio and price bands
self.investor_price_ratio.compute_ratio(
starting_indexes,
@@ -408,9 +319,10 @@ impl RealizedBasic {
exit,
)?;
// Use explicit field paths for split borrows
self.lower_price_band.cents.height.compute_transform2(
starting_indexes.height,
&self.core.realized_price.cents.height,
&self.core.minimal.realized_price.cents.height,
&self.investor_price.cents.height,
|(i, rp, ip, ..)| {
let rp = rp.as_u128();
@@ -427,7 +339,7 @@ impl RealizedBasic {
self.upper_price_band.cents.height.compute_transform2(
starting_indexes.height,
&self.investor_price.cents.height,
&self.core.realized_price.cents.height,
&self.core.minimal.realized_price.cents.height,
|(i, ip, rp, ..)| {
let ip = ip.as_u128();
let rp = rp.as_u128();
@@ -450,7 +362,7 @@ impl RealizedBasic {
ssrr.compute_binary::<Cents, Cents, RatioCentsBp32>(
starting_indexes.height,
&rv.height,
&self.core.realized_cap_cents.height,
&self.core.minimal.realized_cap_cents.height,
exit,
)?;
}
@@ -463,22 +375,70 @@ impl RealizedBasic {
exit,
)?;
// Peak regret relative to realized cap
self.peak_regret_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(
// Extended: realized profit/loss rolling sums
let window_starts = blocks.count.window_starts();
self.realized_profit_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&self.core.minimal.realized_profit.height,
exit,
)?;
self.realized_loss_sum.compute_rolling_sum(
starting_indexes.height,
&window_starts,
&self.core.minimal.realized_loss.height,
exit,
)?;
// Realized cap relative to own market cap
self.realized_cap_rel_to_own_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
starting_indexes.height,
&self.peak_regret.height,
&self.core.realized_cap_cents.height,
&self.core.minimal.realized_cap.height,
height_to_market_cap,
exit,
)?;
// Realized price ratio percentiles
self.realized_price_ratio_percentiles.compute(
// Realized profit to loss ratios
for ((ratio, profit), loss) in self
.realized_profit_to_loss_ratio
.as_mut_array()
.into_iter()
.zip(self.realized_profit_sum.as_array())
.zip(self.realized_loss_sum.as_array())
{
ratio.compute_binary::<Cents, Cents, RatioCents64>(
starting_indexes.height,
&profit.height,
&loss.height,
exit,
)?;
}
// Realized price stddev bands
self.realized_price_ratio_std_dev.compute(
blocks,
starting_indexes,
exit,
&self.core.realized_price_ratio.ratio.height,
&self.core.realized_price.cents.height,
&self.core.minimal.realized_price_ratio.ratio.height,
&self.core.minimal.realized_price.cents.height,
)?;
// Investor price: percentiles + stddev bands
let investor_price = &self.investor_price.cents.height;
self.investor_price_ratio_percentiles.compute(
blocks,
starting_indexes,
exit,
&self.investor_price_ratio.ratio.height,
investor_price,
)?;
self.investor_price_ratio_std_dev.compute(
blocks,
starting_indexes,
exit,
&self.investor_price_ratio.ratio.height,
investor_price,
)?;
Ok(())

View File

@@ -0,0 +1,151 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
BasisPoints32, Bitcoin, Cents, Dollars, Height, Indexes, Sats, StoredF32, Version,
};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{
distribution::state::RealizedOps,
internal::{
CentsUnsignedToDollars, ComputedFromHeight, ComputedFromHeightCumulative,
ComputedFromHeightRatio, Identity, LazyFromHeight, Price,
},
prices,
};
use crate::distribution::metrics::ImportConfig;
#[derive(Traversable)]
pub struct RealizedMinimal<M: StorageMode = Rw> {
pub realized_cap_cents: ComputedFromHeight<Cents, M>,
pub realized_profit: ComputedFromHeightCumulative<Cents, M>,
pub realized_loss: ComputedFromHeightCumulative<Cents, M>,
pub realized_cap: LazyFromHeight<Dollars, Cents>,
pub realized_price: Price<ComputedFromHeight<Cents, M>>,
pub realized_price_ratio: ComputedFromHeightRatio<M>,
pub mvrv: LazyFromHeight<StoredF32>,
}
impl RealizedMinimal {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let realized_cap_cents = cfg.import_computed("realized_cap_cents", Version::ZERO)?;
let realized_cap = LazyFromHeight::from_computed::<CentsUnsignedToDollars>(
&cfg.name("realized_cap"),
cfg.version,
realized_cap_cents.height.read_only_boxed_clone(),
&realized_cap_cents,
);
let realized_profit = cfg.import_cumulative("realized_profit", Version::ZERO)?;
let realized_loss = cfg.import_cumulative("realized_loss", Version::ZERO)?;
let realized_price = cfg.import_price("realized_price", Version::ONE)?;
let realized_price_ratio = cfg.import_ratio("realized_price", Version::ONE)?;
let mvrv = LazyFromHeight::from_lazy::<Identity<StoredF32>, BasisPoints32>(
&cfg.name("mvrv"),
cfg.version,
&realized_price_ratio.ratio,
);
Ok(Self {
realized_cap_cents,
realized_profit,
realized_loss,
realized_cap,
realized_price,
realized_price_ratio,
mvrv,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.realized_cap_cents
.height
.len()
.min(self.realized_profit.height.len())
.min(self.realized_loss.height.len())
}
pub(crate) fn truncate_push(
&mut self,
height: Height,
state: &impl RealizedOps,
) -> Result<()> {
self.realized_cap_cents
.height
.truncate_push(height, state.cap())?;
self.realized_profit
.height
.truncate_push(height, state.profit())?;
self.realized_loss
.height
.truncate_push(height, state.loss())?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.realized_cap_cents.height as &mut dyn AnyStoredVec,
&mut self.realized_profit.height,
&mut self.realized_loss.height,
]
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
sum_others!(self, starting_indexes, others, exit; realized_cap_cents.height);
sum_others!(self, starting_indexes, others, exit; realized_profit.height);
sum_others!(self, starting_indexes, others, exit; realized_loss.height);
Ok(())
}
pub(crate) fn compute_rest_part1(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.realized_profit
.compute_rest(starting_indexes.height, exit)?;
self.realized_loss
.compute_rest(starting_indexes.height, exit)?;
Ok(())
}
pub(crate) fn compute_rest_part2(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
exit: &Exit,
) -> Result<()> {
self.realized_price.cents.height.compute_transform2(
starting_indexes.height,
&self.realized_cap_cents.height,
height_to_supply,
|(i, cap_cents, supply, ..)| {
let cap = cap_cents.as_u128();
let supply_sats = Sats::from(supply).as_u128();
if supply_sats == 0 {
(i, Cents::ZERO)
} else {
(i, Cents::from(cap * Sats::ONE_BTC_U128 / supply_sats))
}
},
exit,
)?;
self.realized_price_ratio.compute_ratio(
starting_indexes,
&prices.price.cents.height,
&self.realized_price.cents.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,15 +1,9 @@
mod adjusted;
mod base;
mod complete;
mod core;
mod extended;
mod with_extended;
mod full;
mod minimal;
pub use adjusted::*;
pub use base::*;
pub use complete::*;
pub use core::*;
pub use extended::*;
pub use with_extended::*;
pub use full::*;
pub use minimal::*;

View File

@@ -1,60 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Indexes};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, prices};
use crate::distribution::metrics::ImportConfig;
use super::{RealizedFull, RealizedExtended};
/// Realized metrics with guaranteed extended (no Option).
#[derive(Deref, DerefMut, Traversable)]
pub struct RealizedWithExtended<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RealizedFull<M>,
#[traversable(flatten)]
pub extended: RealizedExtended<M>,
}
impl RealizedWithExtended {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let base = RealizedFull::forced_import(cfg)?;
let extended = RealizedExtended::forced_import(cfg)?;
Ok(Self { base, extended })
}
pub(crate) fn compute_rest_part2(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base.compute_rest_part2(
blocks,
prices,
starting_indexes,
height_to_supply,
height_to_market_cap,
exit,
)?;
self.extended.compute_rest_part2(
&self.base,
blocks,
prices,
starting_indexes,
height_to_market_cap,
exit,
)?;
Ok(())
}
}

View File

@@ -1,71 +1,107 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, BasisPointsSigned32, Dollars, Height, Sats, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use brk_types::{BasisPoints16, BasisPointsSigned32, Dollars, Height, Sats, StoredF32, Version};
use vecdb::{Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::internal::{NegRatioDollarsBps32, PercentFromHeight, RatioDollarsBp16};
use crate::internal::{
Bps32ToFloat, LazyFromHeight, NegRatioDollarsBps32, PercentFromHeight, RatioDollarsBp16,
RatioDollarsBps32, RatioSatsBp16,
};
use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
use super::RelativeComplete;
/// Full relative metrics (Source/Extended tier).
/// Relative metrics for the Complete tier (~6 fields).
///
/// Contains all Complete-tier fields (via Deref to RelativeComplete) plus:
/// - Source-only: neg_unrealized_loss_rel_to_market_cap, invested_capital_in_profit/loss_rel_to_realized_cap
#[derive(Deref, DerefMut, Traversable)]
/// Excludes source-only fields (invested_capital_in_profit/loss_rel_to_realized_cap).
#[derive(Traversable)]
pub struct RelativeBase<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub complete: RelativeComplete<M>,
pub supply_in_profit_rel_to_own_supply: PercentFromHeight<BasisPoints16, M>,
pub supply_in_loss_rel_to_own_supply: PercentFromHeight<BasisPoints16, M>,
// --- Source-only fields ---
pub unrealized_profit_rel_to_market_cap: PercentFromHeight<BasisPoints16, M>,
pub unrealized_loss_rel_to_market_cap: PercentFromHeight<BasisPoints16, M>,
pub net_unrealized_pnl_rel_to_market_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub neg_unrealized_loss_rel_to_market_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub invested_capital_in_profit_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
pub invested_capital_in_loss_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
pub nupl: LazyFromHeight<StoredF32, BasisPointsSigned32>,
}
impl RelativeBase {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let complete = RelativeComplete::forced_import(cfg)?;
let v1 = Version::ONE;
let v2 = Version::new(2);
let net_unrealized_pnl_rel_to_market_cap =
cfg.import_percent_bps32("net_unrealized_pnl_rel_to_market_cap", Version::new(3))?;
let nupl = LazyFromHeight::from_computed::<Bps32ToFloat>(
&cfg.name("nupl"),
cfg.version + Version::new(3),
net_unrealized_pnl_rel_to_market_cap
.bps
.height
.read_only_boxed_clone(),
&net_unrealized_pnl_rel_to_market_cap.bps,
);
Ok(Self {
complete,
supply_in_profit_rel_to_own_supply: cfg
.import_percent_bp16("supply_in_profit_rel_to_own_supply", v1)?,
supply_in_loss_rel_to_own_supply: cfg
.import_percent_bp16("supply_in_loss_rel_to_own_supply", v1)?,
unrealized_profit_rel_to_market_cap: cfg
.import_percent_bp16("unrealized_profit_rel_to_market_cap", v2)?,
unrealized_loss_rel_to_market_cap: cfg
.import_percent_bp16("unrealized_loss_rel_to_market_cap", v2)?,
net_unrealized_pnl_rel_to_market_cap,
neg_unrealized_loss_rel_to_market_cap: cfg
.import_percent_bps32("neg_unrealized_loss_rel_to_market_cap", Version::new(3))?,
invested_capital_in_profit_rel_to_realized_cap: cfg.import_percent_bp16(
"invested_capital_in_profit_rel_to_realized_cap",
Version::ZERO,
)?,
invested_capital_in_loss_rel_to_realized_cap: cfg.import_percent_bp16(
"invested_capital_in_loss_rel_to_realized_cap",
Version::ZERO,
)?,
nupl,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
unrealized: &UnrealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
// Compute Complete-tier fields
self.complete.compute(
max_from,
&unrealized.complete,
supply_total_sats,
market_cap,
exit,
)?;
// Source-only
self.supply_in_profit_rel_to_own_supply
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&unrealized.supply_in_profit.sats.height,
supply_total_sats,
exit,
)?;
self.supply_in_loss_rel_to_own_supply
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&unrealized.supply_in_loss.sats.height,
supply_total_sats,
exit,
)?;
self.unrealized_profit_rel_to_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.unrealized_profit.usd.height,
market_cap,
exit,
)?;
self.unrealized_loss_rel_to_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.unrealized_loss.usd.height,
market_cap,
exit,
)?;
self.net_unrealized_pnl_rel_to_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBps32>(
max_from,
&unrealized.net_unrealized_pnl.usd.height,
market_cap,
exit,
)?;
self.neg_unrealized_loss_rel_to_market_cap
.compute_binary::<Dollars, Dollars, NegRatioDollarsBps32>(
max_from,
@@ -73,20 +109,6 @@ impl RelativeBase {
market_cap,
exit,
)?;
self.invested_capital_in_profit_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.invested_capital_in_profit.usd.height,
&realized.realized_cap.height,
exit,
)?;
self.invested_capital_in_loss_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.invested_capital_in_loss.usd.height,
&realized.realized_cap.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,105 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, BasisPointsSigned32, Dollars, Height, Sats, StoredF32, Version};
use vecdb::{Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::internal::{
Bps32ToFloat, LazyFromHeight, PercentFromHeight, RatioDollarsBp16, RatioDollarsBps32,
RatioSatsBp16,
};
use crate::distribution::metrics::{ImportConfig, UnrealizedComplete};
/// Relative metrics for the Complete tier (~6 fields).
///
/// Excludes source-only fields (invested_capital_in_profit/loss_rel_to_realized_cap,
/// neg_unrealized_loss_rel_to_market_cap).
#[derive(Traversable)]
pub struct RelativeComplete<M: StorageMode = Rw> {
pub supply_in_profit_rel_to_own_supply: PercentFromHeight<BasisPoints16, M>,
pub supply_in_loss_rel_to_own_supply: PercentFromHeight<BasisPoints16, M>,
pub unrealized_profit_rel_to_market_cap: PercentFromHeight<BasisPoints16, M>,
pub unrealized_loss_rel_to_market_cap: PercentFromHeight<BasisPoints16, M>,
pub net_unrealized_pnl_rel_to_market_cap: PercentFromHeight<BasisPointsSigned32, M>,
pub nupl: LazyFromHeight<StoredF32, BasisPointsSigned32>,
}
impl RelativeComplete {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v1 = Version::ONE;
let v2 = Version::new(2);
let net_unrealized_pnl_rel_to_market_cap =
cfg.import_percent_bps32("net_unrealized_pnl_rel_to_market_cap", Version::new(3))?;
let nupl = LazyFromHeight::from_computed::<Bps32ToFloat>(
&cfg.name("nupl"),
cfg.version + Version::new(3),
net_unrealized_pnl_rel_to_market_cap
.bps
.height
.read_only_boxed_clone(),
&net_unrealized_pnl_rel_to_market_cap.bps,
);
Ok(Self {
supply_in_profit_rel_to_own_supply: cfg
.import_percent_bp16("supply_in_profit_rel_to_own_supply", v1)?,
supply_in_loss_rel_to_own_supply: cfg
.import_percent_bp16("supply_in_loss_rel_to_own_supply", v1)?,
unrealized_profit_rel_to_market_cap: cfg
.import_percent_bp16("unrealized_profit_rel_to_market_cap", v2)?,
unrealized_loss_rel_to_market_cap: cfg
.import_percent_bp16("unrealized_loss_rel_to_market_cap", v2)?,
net_unrealized_pnl_rel_to_market_cap,
nupl,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedComplete,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.supply_in_profit_rel_to_own_supply
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&unrealized.supply_in_profit.sats.height,
supply_total_sats,
exit,
)?;
self.supply_in_loss_rel_to_own_supply
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&unrealized.supply_in_loss.sats.height,
supply_total_sats,
exit,
)?;
self.unrealized_profit_rel_to_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.unrealized_profit.usd.height,
market_cap,
exit,
)?;
self.unrealized_loss_rel_to_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.unrealized_loss.usd.height,
market_cap,
exit,
)?;
self.net_unrealized_pnl_rel_to_market_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBps32>(
max_from,
&unrealized.net_unrealized_pnl.usd.height,
market_cap,
exit,
)?;
Ok(())
}
}

View File

@@ -4,9 +4,9 @@ use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedFull};
use super::{RelativeBase, RelativeExtendedOwnPnl};
use super::{RelativeFull, RelativeExtendedOwnPnl};
/// Relative metrics for the "all" cohort (base + own_pnl, NO rel_to_all).
#[derive(Deref, DerefMut, Traversable)]
@@ -14,7 +14,7 @@ pub struct RelativeForAll<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase<M>,
pub base: RelativeFull<M>,
#[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
}
@@ -22,7 +22,7 @@ pub struct RelativeForAll<M: StorageMode = Rw> {
impl RelativeForAll {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeBase::forced_import(cfg)?,
base: RelativeFull::forced_import(cfg)?,
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?,
})
}
@@ -31,7 +31,7 @@ impl RelativeForAll {
&mut self,
max_from: Height,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,

View File

@@ -0,0 +1,81 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, Dollars, Height, Sats, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::{PercentFromHeight, RatioDollarsBp16};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedFull};
use super::RelativeBase;
/// Full relative metrics (Source/Extended tier).
///
/// Contains all Complete-tier fields (via Deref to RelativeBase) plus:
/// - Source-only: invested_capital_in_profit/loss_rel_to_realized_cap
#[derive(Deref, DerefMut, Traversable)]
pub struct RelativeFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase<M>,
// --- Source-only fields ---
pub invested_capital_in_profit_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
pub invested_capital_in_loss_rel_to_realized_cap: PercentFromHeight<BasisPoints16, M>,
}
impl RelativeFull {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let base = RelativeBase::forced_import(cfg)?;
Ok(Self {
base,
invested_capital_in_profit_rel_to_realized_cap: cfg.import_percent_bp16(
"invested_capital_in_profit_rel_to_realized_cap",
Version::ZERO,
)?,
invested_capital_in_loss_rel_to_realized_cap: cfg.import_percent_bp16(
"invested_capital_in_loss_rel_to_realized_cap",
Version::ZERO,
)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedFull,
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
// Compute Complete-tier fields
self.base.compute(
max_from,
&unrealized.base,
supply_total_sats,
market_cap,
exit,
)?;
// Source-only
self.invested_capital_in_profit_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.invested_capital_in_profit.usd.height,
&realized.realized_cap.height,
exit,
)?;
self.invested_capital_in_loss_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from,
&unrealized.invested_capital_in_loss.usd.height,
&realized.realized_cap.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,21 +1,21 @@
mod base;
mod complete;
mod extended_own_market_cap;
mod extended_own_pnl;
mod for_all;
mod full;
mod to_all;
mod with_extended;
mod with_rel_to_all;
mod with_rel_to_all_complete;
mod with_rel_to_all_base;
pub use base::*;
pub use complete::*;
pub use extended_own_market_cap::*;
pub use extended_own_pnl::*;
pub use for_all::*;
pub use full::*;
pub use to_all::*;
pub use with_extended::*;
pub use with_rel_to_all::*;
pub use with_rel_to_all_complete::*;
pub use with_rel_to_all_base::*;

View File

@@ -4,9 +4,9 @@ use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedFull};
use super::{RelativeBase, RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeToAll};
use super::{RelativeFull, RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeToAll};
/// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl).
/// Used by: sth, lth, age_range cohorts.
@@ -15,7 +15,7 @@ pub struct RelativeWithExtended<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase<M>,
pub base: RelativeFull<M>,
#[traversable(flatten)]
pub rel_to_all: RelativeToAll<M>,
#[traversable(flatten)]
@@ -27,7 +27,7 @@ pub struct RelativeWithExtended<M: StorageMode = Rw> {
impl RelativeWithExtended {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeBase::forced_import(cfg)?,
base: RelativeFull::forced_import(cfg)?,
rel_to_all: RelativeToAll::forced_import(cfg)?,
extended_own_market_cap: RelativeExtendedOwnMarketCap::forced_import(cfg)?,
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?,
@@ -39,7 +39,7 @@ impl RelativeWithExtended {
&mut self,
max_from: Height,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,

View File

@@ -4,9 +4,9 @@ use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedFull};
use super::{RelativeBase, RelativeToAll};
use super::{RelativeFull, RelativeToAll};
/// Relative metrics with rel_to_all (no extended, no peak_regret).
/// Used by: epoch, year, type, amount, address cohorts.
@@ -15,7 +15,7 @@ pub struct RelativeWithRelToAll<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase<M>,
pub base: RelativeFull<M>,
#[traversable(flatten)]
pub rel_to_all: RelativeToAll<M>,
}
@@ -23,7 +23,7 @@ pub struct RelativeWithRelToAll<M: StorageMode = Rw> {
impl RelativeWithRelToAll {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeBase::forced_import(cfg)?,
base: RelativeFull::forced_import(cfg)?,
rel_to_all: RelativeToAll::forced_import(cfg)?,
})
}
@@ -33,7 +33,7 @@ impl RelativeWithRelToAll {
&mut self,
max_from: Height,
unrealized: &UnrealizedFull,
realized: &RealizedFull,
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,

View File

@@ -4,26 +4,26 @@ use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, UnrealizedComplete};
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
use super::{RelativeComplete, RelativeToAll};
use super::{RelativeBase, RelativeToAll};
/// Complete relative metrics with rel_to_all.
/// Used by CompleteCohortMetrics (epoch, class, min_age, max_age).
#[derive(Deref, DerefMut, Traversable)]
pub struct RelativeCompleteWithRelToAll<M: StorageMode = Rw> {
pub struct RelativeBaseWithRelToAll<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeComplete<M>,
pub base: RelativeBase<M>,
#[traversable(flatten)]
pub rel_to_all: RelativeToAll<M>,
}
impl RelativeCompleteWithRelToAll {
impl RelativeBaseWithRelToAll {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeComplete::forced_import(cfg)?,
base: RelativeBase::forced_import(cfg)?,
rel_to_all: RelativeToAll::forced_import(cfg)?,
})
}
@@ -31,7 +31,7 @@ impl RelativeCompleteWithRelToAll {
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedComplete,
unrealized: &UnrealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,

View File

@@ -1,93 +1,78 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, CentsSats, CentsSigned, CentsSquaredSats, Height, Indexes, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use brk_types::{Cents, CentsSigned, Height, Indexes, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, Rw, StorageMode, WritableVec};
use crate::{
distribution::state::UnrealizedState,
internal::{CentsSubtractToCentsSigned, FiatFromHeight},
prices,
internal::{
CentsSubtractToCentsSigned, FiatFromHeight, LazyFromHeight, NegCentsUnsignedToDollars,
ValueFromHeight,
},
};
use brk_types::Dollars;
use crate::distribution::metrics::ImportConfig;
use super::UnrealizedComplete;
/// Full unrealized metrics (Source/Extended tier).
/// Unrealized metrics for the Complete tier (~6 fields).
///
/// Contains all Complete-tier fields (via Deref to UnrealizedComplete) plus:
/// - Source-only: invested_capital, raw BytesVecs, unrealized_gross_pnl
/// - Extended-only: pain_index, greed_index, net_sentiment
#[derive(Deref, DerefMut, Traversable)]
pub struct UnrealizedFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub complete: UnrealizedComplete<M>,
/// Excludes source-only fields (invested_capital, raw BytesVecs)
/// and extended-only fields (pain_index, greed_index, net_sentiment).
#[derive(Traversable)]
pub struct UnrealizedBase<M: StorageMode = Rw> {
pub supply_in_profit: ValueFromHeight<M>,
pub supply_in_loss: ValueFromHeight<M>,
// --- Source-only fields ---
pub invested_capital_in_profit: FiatFromHeight<Cents, M>,
pub invested_capital_in_loss: FiatFromHeight<Cents, M>,
pub unrealized_profit: FiatFromHeight<Cents, M>,
pub unrealized_loss: FiatFromHeight<Cents, M>,
pub invested_capital_in_profit_raw: M::Stored<BytesVec<Height, CentsSats>>,
pub invested_capital_in_loss_raw: M::Stored<BytesVec<Height, CentsSats>>,
pub investor_cap_in_profit_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
pub investor_cap_in_loss_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
pub neg_unrealized_loss: LazyFromHeight<Dollars, Cents>,
pub gross_pnl: FiatFromHeight<Cents, M>,
// --- Extended-only fields ---
pub pain_index: FiatFromHeight<Cents, M>,
pub greed_index: FiatFromHeight<Cents, M>,
pub net_sentiment: FiatFromHeight<CentsSigned, M>,
pub net_unrealized_pnl: FiatFromHeight<CentsSigned, M>,
}
impl UnrealizedFull {
impl UnrealizedBase {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
let supply_in_profit = cfg.import_value("supply_in_profit", v0)?;
let supply_in_loss = cfg.import_value("supply_in_loss", v0)?;
let complete = UnrealizedComplete::forced_import(cfg)?;
let unrealized_profit = cfg.import_fiat("unrealized_profit", v0)?;
let unrealized_loss = cfg.import_fiat("unrealized_loss", v0)?;
let invested_capital_in_profit = cfg.import_fiat("invested_capital_in_profit", v0)?;
let invested_capital_in_loss = cfg.import_fiat("invested_capital_in_loss", v0)?;
let invested_capital_in_profit_raw =
cfg.import_bytes("invested_capital_in_profit_raw", v0)?;
let invested_capital_in_loss_raw = cfg.import_bytes("invested_capital_in_loss_raw", v0)?;
let investor_cap_in_profit_raw = cfg.import_bytes("investor_cap_in_profit_raw", v0)?;
let investor_cap_in_loss_raw = cfg.import_bytes("investor_cap_in_loss_raw", v0)?;
let pain_index = cfg.import_fiat("pain_index", v0)?;
let greed_index = cfg.import_fiat("greed_index", v0)?;
let net_sentiment = cfg.import_fiat("net_sentiment", Version::ONE)?;
let neg_unrealized_loss = LazyFromHeight::from_computed::<NegCentsUnsignedToDollars>(
&cfg.name("neg_unrealized_loss"),
cfg.version,
unrealized_loss.cents.height.read_only_boxed_clone(),
&unrealized_loss.cents,
);
let gross_pnl = cfg.import_fiat("unrealized_gross_pnl", v0)?;
let net_unrealized_pnl = cfg.import_fiat("net_unrealized_pnl", v0)?;
Ok(Self {
complete,
invested_capital_in_profit,
invested_capital_in_loss,
invested_capital_in_profit_raw,
invested_capital_in_loss_raw,
investor_cap_in_profit_raw,
investor_cap_in_loss_raw,
pain_index,
greed_index,
net_sentiment,
supply_in_profit,
supply_in_loss,
unrealized_profit,
unrealized_loss,
neg_unrealized_loss,
gross_pnl,
net_unrealized_pnl,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.complete
.min_stateful_height_len()
.min(self.invested_capital_in_profit.cents.height.len())
.min(self.invested_capital_in_loss.cents.height.len())
.min(self.invested_capital_in_profit_raw.len())
.min(self.invested_capital_in_loss_raw.len())
.min(self.investor_cap_in_profit_raw.len())
.min(self.investor_cap_in_loss_raw.len())
self.supply_in_profit
.sats
.height
.len()
.min(self.supply_in_loss.sats.height.len())
.min(self.unrealized_profit.cents.height.len())
.min(self.unrealized_loss.cents.height.len())
}
pub(crate) fn truncate_push(
@@ -95,46 +80,35 @@ impl UnrealizedFull {
height: Height,
height_state: &UnrealizedState,
) -> Result<()> {
self.complete.truncate_push(height, height_state)?;
self.invested_capital_in_profit
self.supply_in_profit
.sats
.height
.truncate_push(height, height_state.supply_in_profit)?;
self.supply_in_loss
.sats
.height
.truncate_push(height, height_state.supply_in_loss)?;
self.unrealized_profit
.cents
.height
.truncate_push(height, height_state.invested_capital_in_profit)?;
self.invested_capital_in_loss
.truncate_push(height, height_state.unrealized_profit)?;
self.unrealized_loss
.cents
.height
.truncate_push(height, height_state.invested_capital_in_loss)?;
self.invested_capital_in_profit_raw.truncate_push(
height,
CentsSats::new(height_state.invested_capital_in_profit_raw),
)?;
self.invested_capital_in_loss_raw.truncate_push(
height,
CentsSats::new(height_state.invested_capital_in_loss_raw),
)?;
self.investor_cap_in_profit_raw.truncate_push(
height,
CentsSquaredSats::new(height_state.investor_cap_in_profit_raw),
)?;
self.investor_cap_in_loss_raw.truncate_push(
height,
CentsSquaredSats::new(height_state.investor_cap_in_loss_raw),
)?;
.truncate_push(height, height_state.unrealized_loss)?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.complete.collect_vecs_mut();
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.invested_capital_in_profit_raw as &mut dyn AnyStoredVec);
vecs.push(&mut self.invested_capital_in_loss_raw 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
vec![
&mut self.supply_in_profit.base.sats.height as &mut dyn AnyStoredVec,
&mut self.supply_in_profit.base.cents.height as &mut dyn AnyStoredVec,
&mut self.supply_in_loss.base.sats.height as &mut dyn AnyStoredVec,
&mut self.supply_in_loss.base.cents.height as &mut dyn AnyStoredVec,
&mut self.unrealized_profit.cents.height,
&mut self.unrealized_loss.cents.height,
]
}
pub(crate) fn compute_from_stateful(
@@ -143,149 +117,37 @@ impl UnrealizedFull {
others: &[&Self],
exit: &Exit,
) -> Result<()> {
// Delegate Complete-tier aggregation
let complete_refs: Vec<&UnrealizedComplete> =
others.iter().map(|o| &o.complete).collect();
self.complete
.compute_from_stateful(starting_indexes, &complete_refs, exit)?;
// Source-only: invested_capital
sum_others!(self, starting_indexes, others, exit; invested_capital_in_profit.cents.height);
sum_others!(self, starting_indexes, others, exit; invested_capital_in_loss.cents.height);
// Source-only: raw BytesVec aggregation
let start = self
.invested_capital_in_profit_raw
.len()
.min(self.invested_capital_in_loss_raw.len())
.min(self.investor_cap_in_profit_raw.len())
.min(self.investor_cap_in_loss_raw.len());
let end = others
.iter()
.map(|o| o.invested_capital_in_profit_raw.len())
.min()
.unwrap_or(0);
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
let invested_profit_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| {
o.invested_capital_in_profit_raw
.collect_range_at(start, end)
})
.collect();
let invested_loss_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| o.invested_capital_in_loss_raw.collect_range_at(start, end))
.collect();
let investor_profit_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_in_profit_raw.collect_range_at(start, end))
.collect();
let investor_loss_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_in_loss_raw.collect_range_at(start, end))
.collect();
for i in start..end {
let height = Height::from(i);
let local_i = i - start;
let mut sum_invested_profit = CentsSats::ZERO;
let mut sum_invested_loss = CentsSats::ZERO;
let mut sum_investor_profit = CentsSquaredSats::ZERO;
let mut sum_investor_loss = CentsSquaredSats::ZERO;
for idx in 0..others.len() {
sum_invested_profit += invested_profit_ranges[idx][local_i];
sum_invested_loss += invested_loss_ranges[idx][local_i];
sum_investor_profit += investor_profit_ranges[idx][local_i];
sum_investor_loss += investor_loss_ranges[idx][local_i];
}
self.invested_capital_in_profit_raw
.truncate_push(height, sum_invested_profit)?;
self.invested_capital_in_loss_raw
.truncate_push(height, sum_invested_loss)?;
self.investor_cap_in_profit_raw
.truncate_push(height, sum_investor_profit)?;
self.investor_cap_in_loss_raw
.truncate_push(height, sum_investor_loss)?;
}
sum_others!(self, starting_indexes, others, exit; supply_in_profit.sats.height);
sum_others!(self, starting_indexes, others, exit; supply_in_loss.sats.height);
sum_others!(self, starting_indexes, others, exit; unrealized_profit.cents.height);
sum_others!(self, starting_indexes, others, exit; unrealized_loss.cents.height);
Ok(())
}
/// Compute derived metrics from stored values + price.
/// Compute derived metrics from stored values.
pub(crate) fn compute_rest(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
// Complete-tier: net_unrealized_pnl
self.complete.compute_rest(starting_indexes, exit)?;
// Extended-only: Pain index (investor_price_of_losers - spot)
self.pain_index.cents.height.compute_transform3(
starting_indexes.height,
&self.investor_cap_in_loss_raw,
&self.invested_capital_in_loss_raw,
&prices.price.cents.height,
|(h, investor_cap, invested_cap, spot, ..)| {
if invested_cap.inner() == 0 {
return (h, Cents::ZERO);
}
let investor_price_losers = investor_cap.inner() / invested_cap.inner();
let spot_u128 = spot.as_u128();
(h, Cents::new((investor_price_losers - spot_u128) as u64))
},
exit,
)?;
// Extended-only: Greed index (spot - investor_price_of_winners)
self.greed_index.cents.height.compute_transform3(
starting_indexes.height,
&self.investor_cap_in_profit_raw,
&self.invested_capital_in_profit_raw,
&prices.price.cents.height,
|(h, investor_cap, invested_cap, spot, ..)| {
if invested_cap.inner() == 0 {
return (h, Cents::ZERO);
}
let investor_price_winners = investor_cap.inner() / invested_cap.inner();
let spot_u128 = spot.as_u128();
(h, Cents::new((spot_u128 - investor_price_winners) as u64))
},
exit,
)?;
// Source-only: unrealized gross pnl
self.gross_pnl.cents.height.compute_add(
starting_indexes.height,
&self.complete.unrealized_profit.cents.height,
&self.complete.unrealized_loss.cents.height,
&self.unrealized_profit.cents.height,
&self.unrealized_loss.cents.height,
exit,
)?;
Ok(())
}
/// Compute net_sentiment.height for separate cohorts (greed - pain).
pub(crate) fn compute_net_sentiment_height(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.net_sentiment
self.net_unrealized_pnl
.cents
.height
.compute_binary::<Cents, Cents, CentsSubtractToCentsSigned>(
starting_indexes.height,
&self.greed_index.cents.height,
&self.pain_index.cents.height,
&self.unrealized_profit.cents.height,
&self.unrealized_loss.cents.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,141 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, CentsSigned, Height, Indexes, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, Rw, StorageMode, WritableVec};
use crate::{
distribution::state::UnrealizedState,
internal::{
CentsSubtractToCentsSigned, FiatFromHeight, LazyFromHeight, NegCentsUnsignedToDollars,
ValueFromHeight,
},
};
use brk_types::Dollars;
use crate::distribution::metrics::ImportConfig;
/// Unrealized metrics for the Complete tier (~6 fields).
///
/// Excludes source-only fields (invested_capital, raw BytesVecs, unrealized_gross_pnl)
/// and extended-only fields (pain_index, greed_index, net_sentiment).
#[derive(Traversable)]
pub struct UnrealizedComplete<M: StorageMode = Rw> {
pub supply_in_profit: ValueFromHeight<M>,
pub supply_in_loss: ValueFromHeight<M>,
pub unrealized_profit: FiatFromHeight<Cents, M>,
pub unrealized_loss: FiatFromHeight<Cents, M>,
pub neg_unrealized_loss: LazyFromHeight<Dollars, Cents>,
pub net_unrealized_pnl: FiatFromHeight<CentsSigned, M>,
}
impl UnrealizedComplete {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
let supply_in_profit = cfg.import_value("supply_in_profit", v0)?;
let supply_in_loss = cfg.import_value("supply_in_loss", v0)?;
let unrealized_profit = cfg.import_fiat("unrealized_profit", v0)?;
let unrealized_loss = cfg.import_fiat("unrealized_loss", v0)?;
let neg_unrealized_loss = LazyFromHeight::from_computed::<NegCentsUnsignedToDollars>(
&cfg.name("neg_unrealized_loss"),
cfg.version,
unrealized_loss.cents.height.read_only_boxed_clone(),
&unrealized_loss.cents,
);
let net_unrealized_pnl = cfg.import_fiat("net_unrealized_pnl", v0)?;
Ok(Self {
supply_in_profit,
supply_in_loss,
unrealized_profit,
unrealized_loss,
neg_unrealized_loss,
net_unrealized_pnl,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.supply_in_profit
.sats
.height
.len()
.min(self.supply_in_loss.sats.height.len())
.min(self.unrealized_profit.cents.height.len())
.min(self.unrealized_loss.cents.height.len())
}
pub(crate) fn truncate_push(
&mut self,
height: Height,
height_state: &UnrealizedState,
) -> Result<()> {
self.supply_in_profit
.sats
.height
.truncate_push(height, height_state.supply_in_profit)?;
self.supply_in_loss
.sats
.height
.truncate_push(height, height_state.supply_in_loss)?;
self.unrealized_profit
.cents
.height
.truncate_push(height, height_state.unrealized_profit)?;
self.unrealized_loss
.cents
.height
.truncate_push(height, height_state.unrealized_loss)?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.supply_in_profit.base.sats.height as &mut dyn AnyStoredVec,
&mut self.supply_in_profit.base.cents.height as &mut dyn AnyStoredVec,
&mut self.supply_in_loss.base.sats.height as &mut dyn AnyStoredVec,
&mut self.supply_in_loss.base.cents.height as &mut dyn AnyStoredVec,
&mut self.unrealized_profit.cents.height,
&mut self.unrealized_loss.cents.height,
]
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
sum_others!(self, starting_indexes, others, exit; supply_in_profit.sats.height);
sum_others!(self, starting_indexes, others, exit; supply_in_loss.sats.height);
sum_others!(self, starting_indexes, others, exit; unrealized_profit.cents.height);
sum_others!(self, starting_indexes, others, exit; unrealized_loss.cents.height);
Ok(())
}
/// Compute derived metrics from stored values.
pub(crate) fn compute_rest(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.net_unrealized_pnl
.cents
.height
.compute_binary::<Cents, Cents, CentsSubtractToCentsSigned>(
starting_indexes.height,
&self.unrealized_profit.cents.height,
&self.unrealized_loss.cents.height,
exit,
)?;
Ok(())
}
}

View File

@@ -0,0 +1,278 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, CentsSats, CentsSigned, CentsSquaredSats, Height, Indexes, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{
distribution::state::UnrealizedState,
internal::{CentsSubtractToCentsSigned, FiatFromHeight},
prices,
};
use crate::distribution::metrics::ImportConfig;
use super::UnrealizedBase;
/// Full unrealized metrics (Source/Extended tier).
///
/// Contains all Complete-tier fields (via Deref to UnrealizedBase) plus:
/// - Source-only: invested_capital, raw BytesVecs
/// - Extended-only: pain_index, greed_index, net_sentiment
#[derive(Deref, DerefMut, Traversable)]
pub struct UnrealizedFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: UnrealizedBase<M>,
// --- Source-only fields ---
pub invested_capital_in_profit: FiatFromHeight<Cents, M>,
pub invested_capital_in_loss: FiatFromHeight<Cents, M>,
pub invested_capital_in_profit_raw: M::Stored<BytesVec<Height, CentsSats>>,
pub invested_capital_in_loss_raw: M::Stored<BytesVec<Height, CentsSats>>,
pub investor_cap_in_profit_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
pub investor_cap_in_loss_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
// --- Extended-only fields ---
pub pain_index: FiatFromHeight<Cents, M>,
pub greed_index: FiatFromHeight<Cents, M>,
pub net_sentiment: FiatFromHeight<CentsSigned, M>,
}
impl UnrealizedFull {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
let base = UnrealizedBase::forced_import(cfg)?;
let invested_capital_in_profit = cfg.import_fiat("invested_capital_in_profit", v0)?;
let invested_capital_in_loss = cfg.import_fiat("invested_capital_in_loss", v0)?;
let invested_capital_in_profit_raw =
cfg.import_bytes("invested_capital_in_profit_raw", v0)?;
let invested_capital_in_loss_raw = cfg.import_bytes("invested_capital_in_loss_raw", v0)?;
let investor_cap_in_profit_raw = cfg.import_bytes("investor_cap_in_profit_raw", v0)?;
let investor_cap_in_loss_raw = cfg.import_bytes("investor_cap_in_loss_raw", v0)?;
let pain_index = cfg.import_fiat("pain_index", v0)?;
let greed_index = cfg.import_fiat("greed_index", v0)?;
let net_sentiment = cfg.import_fiat("net_sentiment", Version::ONE)?;
Ok(Self {
base,
invested_capital_in_profit,
invested_capital_in_loss,
invested_capital_in_profit_raw,
invested_capital_in_loss_raw,
investor_cap_in_profit_raw,
investor_cap_in_loss_raw,
pain_index,
greed_index,
net_sentiment,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.base
.min_stateful_height_len()
.min(self.invested_capital_in_profit.cents.height.len())
.min(self.invested_capital_in_loss.cents.height.len())
.min(self.invested_capital_in_profit_raw.len())
.min(self.invested_capital_in_loss_raw.len())
.min(self.investor_cap_in_profit_raw.len())
.min(self.investor_cap_in_loss_raw.len())
}
pub(crate) fn truncate_push(
&mut self,
height: Height,
height_state: &UnrealizedState,
) -> Result<()> {
self.base.truncate_push(height, height_state)?;
self.invested_capital_in_profit
.cents
.height
.truncate_push(height, height_state.invested_capital_in_profit)?;
self.invested_capital_in_loss
.cents
.height
.truncate_push(height, height_state.invested_capital_in_loss)?;
self.invested_capital_in_profit_raw.truncate_push(
height,
CentsSats::new(height_state.invested_capital_in_profit_raw),
)?;
self.invested_capital_in_loss_raw.truncate_push(
height,
CentsSats::new(height_state.invested_capital_in_loss_raw),
)?;
self.investor_cap_in_profit_raw.truncate_push(
height,
CentsSquaredSats::new(height_state.investor_cap_in_profit_raw),
)?;
self.investor_cap_in_loss_raw.truncate_push(
height,
CentsSquaredSats::new(height_state.investor_cap_in_loss_raw),
)?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.base.collect_vecs_mut();
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.invested_capital_in_profit_raw as &mut dyn AnyStoredVec);
vecs.push(&mut self.invested_capital_in_loss_raw 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
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
others: &[&Self],
exit: &Exit,
) -> Result<()> {
// Delegate Complete-tier aggregation
let base_refs: Vec<&UnrealizedBase> =
others.iter().map(|o| &o.base).collect();
self.base
.compute_from_stateful(starting_indexes, &base_refs, exit)?;
// Source-only: invested_capital
sum_others!(self, starting_indexes, others, exit; invested_capital_in_profit.cents.height);
sum_others!(self, starting_indexes, others, exit; invested_capital_in_loss.cents.height);
// Source-only: raw BytesVec aggregation
let start = self
.invested_capital_in_profit_raw
.len()
.min(self.invested_capital_in_loss_raw.len())
.min(self.investor_cap_in_profit_raw.len())
.min(self.investor_cap_in_loss_raw.len());
let end = others
.iter()
.map(|o| o.invested_capital_in_profit_raw.len())
.min()
.unwrap_or(0);
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
let invested_profit_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| {
o.invested_capital_in_profit_raw
.collect_range_at(start, end)
})
.collect();
let invested_loss_ranges: Vec<Vec<CentsSats>> = others
.iter()
.map(|o| o.invested_capital_in_loss_raw.collect_range_at(start, end))
.collect();
let investor_profit_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_in_profit_raw.collect_range_at(start, end))
.collect();
let investor_loss_ranges: Vec<Vec<CentsSquaredSats>> = others
.iter()
.map(|o| o.investor_cap_in_loss_raw.collect_range_at(start, end))
.collect();
for i in start..end {
let height = Height::from(i);
let local_i = i - start;
let mut sum_invested_profit = CentsSats::ZERO;
let mut sum_invested_loss = CentsSats::ZERO;
let mut sum_investor_profit = CentsSquaredSats::ZERO;
let mut sum_investor_loss = CentsSquaredSats::ZERO;
for idx in 0..others.len() {
sum_invested_profit += invested_profit_ranges[idx][local_i];
sum_invested_loss += invested_loss_ranges[idx][local_i];
sum_investor_profit += investor_profit_ranges[idx][local_i];
sum_investor_loss += investor_loss_ranges[idx][local_i];
}
self.invested_capital_in_profit_raw
.truncate_push(height, sum_invested_profit)?;
self.invested_capital_in_loss_raw
.truncate_push(height, sum_invested_loss)?;
self.investor_cap_in_profit_raw
.truncate_push(height, sum_investor_profit)?;
self.investor_cap_in_loss_raw
.truncate_push(height, sum_investor_loss)?;
}
Ok(())
}
/// Compute derived metrics from stored values + price.
pub(crate) fn compute_rest(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
// Complete-tier: net_unrealized_pnl
self.base.compute_rest(starting_indexes, exit)?;
// Extended-only: Pain index (investor_price_of_losers - spot)
self.pain_index.cents.height.compute_transform3(
starting_indexes.height,
&self.investor_cap_in_loss_raw,
&self.invested_capital_in_loss_raw,
&prices.price.cents.height,
|(h, investor_cap, invested_cap, spot, ..)| {
if invested_cap.inner() == 0 {
return (h, Cents::ZERO);
}
let investor_price_losers = investor_cap.inner() / invested_cap.inner();
let spot_u128 = spot.as_u128();
(h, Cents::new((investor_price_losers - spot_u128) as u64))
},
exit,
)?;
// Extended-only: Greed index (spot - investor_price_of_winners)
self.greed_index.cents.height.compute_transform3(
starting_indexes.height,
&self.investor_cap_in_profit_raw,
&self.invested_capital_in_profit_raw,
&prices.price.cents.height,
|(h, investor_cap, invested_cap, spot, ..)| {
if invested_cap.inner() == 0 {
return (h, Cents::ZERO);
}
let investor_price_winners = investor_cap.inner() / invested_cap.inner();
let spot_u128 = spot.as_u128();
(h, Cents::new((spot_u128 - investor_price_winners) as u64))
},
exit,
)?;
Ok(())
}
/// Compute net_sentiment.height for separate cohorts (greed - pain).
pub(crate) fn compute_net_sentiment_height(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.net_sentiment
.cents
.height
.compute_binary::<Cents, Cents, CentsSubtractToCentsSigned>(
starting_indexes.height,
&self.greed_index.cents.height,
&self.pain_index.cents.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,5 +1,5 @@
mod base;
mod complete;
mod full;
pub use base::*;
pub use complete::*;
pub use full::*;

View File

@@ -13,6 +13,12 @@ pub trait RealizedOps: Default + Clone + Send + Sync + 'static {
fn value_destroyed(&self) -> Cents {
Cents::ZERO
}
fn sent_in_profit(&self) -> Sats {
Sats::ZERO
}
fn sent_in_loss(&self) -> Sats {
Sats::ZERO
}
fn set_cap_raw(&mut self, cap_raw: CentsSats);
fn set_investor_cap_raw(&mut self, investor_cap_raw: CentsSquaredSats);
fn reset_single_iteration_values(&mut self);
@@ -121,13 +127,15 @@ impl RealizedOps for MinimalRealizedState {
}
}
/// Core realized state: cap, profit, loss + value_created/destroyed for SOPR.
/// Core realized state: cap, profit, loss + value_created/destroyed for SOPR + sent tracking.
/// Used by CoreCohortMetrics cohorts (epoch, class, max_age, min_age — ~59 separate cohorts).
#[derive(Debug, Default, Clone)]
pub struct CoreRealizedState {
minimal: MinimalRealizedState,
value_created_raw: u128,
value_destroyed_raw: u128,
sent_in_profit: Sats,
sent_in_loss: Sats,
}
impl RealizedOps for CoreRealizedState {
@@ -162,6 +170,16 @@ impl RealizedOps for CoreRealizedState {
Cents::new((self.value_destroyed_raw / Sats::ONE_BTC_U128) as u64)
}
#[inline]
fn sent_in_profit(&self) -> Sats {
self.sent_in_profit
}
#[inline]
fn sent_in_loss(&self) -> Sats {
self.sent_in_loss
}
#[inline]
fn set_cap_raw(&mut self, cap_raw: CentsSats) {
self.minimal.set_cap_raw(cap_raw);
@@ -175,6 +193,8 @@ impl RealizedOps for CoreRealizedState {
self.minimal.reset_single_iteration_values();
self.value_created_raw = 0;
self.value_destroyed_raw = 0;
self.sent_in_profit = Sats::ZERO;
self.sent_in_loss = Sats::ZERO;
}
#[inline]
@@ -205,6 +225,14 @@ impl RealizedOps for CoreRealizedState {
.send(sats, current_ps, prev_ps, ath_ps, prev_investor_cap);
self.value_created_raw += current_ps.as_u128();
self.value_destroyed_raw += prev_ps.as_u128();
match current_ps.cmp(&prev_ps) {
Ordering::Greater | Ordering::Equal => {
self.sent_in_profit += sats;
}
Ordering::Less => {
self.sent_in_loss += sats;
}
}
}
}
@@ -232,10 +260,6 @@ pub struct RealizedState {
loss_value_destroyed_raw: u128,
/// Raw realized peak regret: Σ((peak - sell_price) × sats)
peak_regret_raw: u128,
/// Sats sent in profit
sent_in_profit: Sats,
/// Sats sent in loss
sent_in_loss: Sats,
}
impl RealizedOps for RealizedState {
@@ -272,6 +296,16 @@ impl RealizedOps for RealizedState {
Cents::new((raw / Sats::ONE_BTC_U128) as u64)
}
#[inline]
fn sent_in_profit(&self) -> Sats {
self.core.sent_in_profit()
}
#[inline]
fn sent_in_loss(&self) -> Sats {
self.core.sent_in_loss()
}
#[inline]
fn set_cap_raw(&mut self, cap_raw: CentsSats) {
self.core.set_cap_raw(cap_raw);
@@ -290,8 +324,6 @@ impl RealizedOps for RealizedState {
self.loss_value_created_raw = 0;
self.loss_value_destroyed_raw = 0;
self.peak_regret_raw = 0;
self.sent_in_profit = Sats::ZERO;
self.sent_in_loss = Sats::ZERO;
}
#[inline]
@@ -323,7 +355,7 @@ impl RealizedOps for RealizedState {
ath_ps: CentsSats,
prev_investor_cap: CentsSquaredSats,
) {
// Delegate cap/profit/loss + value_created/destroyed to core
// Delegate cap/profit/loss + value_created/destroyed + sent tracking to core
self.core
.send(sats, current_ps, prev_ps, ath_ps, prev_investor_cap);
@@ -331,20 +363,13 @@ impl RealizedOps for RealizedState {
let current = current_ps.as_u128();
let prev = prev_ps.as_u128();
match current_ps.cmp(&prev_ps) {
Ordering::Greater => {
Ordering::Greater | Ordering::Equal => {
self.profit_value_created_raw += current;
self.profit_value_destroyed_raw += prev;
self.sent_in_profit += sats;
}
Ordering::Less => {
self.loss_value_created_raw += current;
self.loss_value_destroyed_raw += prev;
self.sent_in_loss += sats;
}
Ordering::Equal => {
self.profit_value_created_raw += current;
self.profit_value_destroyed_raw += prev;
self.sent_in_profit += sats;
}
}
@@ -421,16 +446,4 @@ impl RealizedState {
}
Cents::new((self.peak_regret_raw / Sats::ONE_BTC_U128) as u64)
}
/// Get sats sent in profit.
#[inline]
pub(crate) fn sent_in_profit(&self) -> Sats {
self.sent_in_profit
}
/// Get sats sent in loss.
#[inline]
pub(crate) fn sent_in_loss(&self) -> Sats {
self.sent_in_loss
}
}

View File

@@ -1,51 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Height, Indexes, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, indexes, prices};
use super::{ComputedFromHeightRatioExtended, ComputedFromHeightRatioStdDevBands};
#[derive(Deref, DerefMut, Traversable)]
pub struct ComputedFromHeightRatioFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: ComputedFromHeightRatioExtended<M>,
#[traversable(flatten)]
pub std_dev: ComputedFromHeightRatioStdDevBands<M>,
}
impl ComputedFromHeightRatioFull {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self {
base: ComputedFromHeightRatioExtended::forced_import(db, name, version, indexes)?,
std_dev: ComputedFromHeightRatioStdDevBands::forced_import(
db, name, version, indexes,
)?,
})
}
/// Compute ratio, percentiles, and all stddev bands from an externally-provided metric price (in cents).
pub(crate) fn compute_rest(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
metric_price: &impl ReadableVec<Height, Cents>,
) -> Result<()> {
self.base
.compute_rest(blocks, prices, starting_indexes, exit, metric_price)?;
self.std_dev
.compute(blocks, starting_indexes, exit, &self.base.base.ratio.height, metric_price)?;
Ok(())
}
}

View File

@@ -1,11 +1,9 @@
mod extended;
mod full;
mod percentiles;
mod price_extended;
mod std_dev_bands;
pub use extended::*;
pub use full::*;
pub use percentiles::*;
pub use price_extended::*;
pub use std_dev_bands::*;

File diff suppressed because it is too large Load Diff

View File

@@ -2064,17 +2064,11 @@ class MetricPattern35(Generic[T]):
# Reusable structural pattern classes
class AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern:
class CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.adjusted_sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, _m(acc, 'adjusted_sopr'))
self.adjusted_sopr_ema: _1m1wPattern = _1m1wPattern(client, _m(acc, 'adjusted_sopr_24h_ema'))
self.adjusted_value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'adjusted_value_created'))
self.adjusted_value_created_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'adjusted_value_created'))
self.adjusted_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'adjusted_value_destroyed'))
self.adjusted_value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'adjusted_value_destroyed'))
self.cap_raw: MetricPattern18[CentsSats] = MetricPattern18(client, _m(acc, 'cap_raw'))
self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow'))
self.gross_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_gross_pnl'))
@@ -2131,102 +2125,6 @@ class AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedS
self.value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'value_destroyed'))
self.value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'value_destroyed'))
class CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.cap_raw: MetricPattern18[CentsSats] = MetricPattern18(client, _m(acc, 'cap_raw'))
self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow'))
self.gross_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_gross_pnl'))
self.gross_pnl_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'gross_pnl_sum'))
self.investor_cap_raw: MetricPattern18[CentsSquaredSats] = MetricPattern18(client, _m(acc, 'investor_cap_raw'))
self.investor_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'investor_price'))
self.investor_price_ratio: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'investor_price_ratio'))
self.loss_value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'loss_value_created'))
self.loss_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'loss_value_destroyed'))
self.lower_price_band: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'lower_price_band'))
self.mvrv: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'mvrv'))
self.neg_realized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_realized_loss'))
self.net_pnl_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'net_pnl_change_1m'))
self.net_pnl_change_1m_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_pnl_change_1m_rel_to_market_cap'))
self.net_pnl_change_1m_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_pnl_change_1m_rel_to_realized_cap'))
self.net_realized_pnl: CumulativeHeightPattern[CentsSigned] = CumulativeHeightPattern(client, _m(acc, 'net_realized_pnl'))
self.net_realized_pnl_ema_1w: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'net_realized_pnl_ema_1w'))
self.net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap'))
self.peak_regret: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_peak_regret'))
self.peak_regret_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_peak_regret_rel_to_realized_cap'))
self.profit_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_flow'))
self.profit_value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'profit_value_created'))
self.profit_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'profit_value_destroyed'))
self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap'))
self.realized_cap_cents: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_cap_cents'))
self.realized_cap_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'realized_cap_change_1m'))
self.realized_loss: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_loss'))
self.realized_loss_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_loss_ema_1w'))
self.realized_loss_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap'))
self.realized_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'realized_price'))
self.realized_price_ratio: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'realized_price_ratio'))
self.realized_profit: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_profit'))
self.realized_profit_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_profit_ema_1w'))
self.realized_profit_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap'))
self.sell_side_risk_ratio: _1m1w1y24hPattern2 = _1m1w1y24hPattern2(client, _m(acc, 'sell_side_risk_ratio'))
self.sell_side_risk_ratio_24h_ema: _1m1wPattern2 = _1m1wPattern2(client, _m(acc, 'sell_side_risk_ratio_24h_ema'))
self.sent_in_loss: BaseCumulativePattern = BaseCumulativePattern(client, _m(acc, 'sent_in_loss'))
self.sent_in_loss_ema: _2wPattern = _2wPattern(client, _m(acc, 'sent_in_loss_ema_2w'))
self.sent_in_profit: BaseCumulativePattern = BaseCumulativePattern(client, _m(acc, 'sent_in_profit'))
self.sent_in_profit_ema: _2wPattern = _2wPattern(client, _m(acc, 'sent_in_profit_ema_2w'))
self.sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, _m(acc, 'sopr'))
self.sopr_24h_ema: _1m1wPattern = _1m1wPattern(client, _m(acc, 'sopr_24h_ema'))
self.upper_price_band: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'upper_price_band'))
self.value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'value_created'))
self.value_created_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'value_created'))
self.value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'value_destroyed'))
self.value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'value_destroyed'))
class CapitulationGrossLossMvrvNegNetProfitRealizedSentSoprValuePattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'capitulation_flow'))
self.gross_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_gross_pnl'))
self.gross_pnl_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'gross_pnl_sum'))
self.loss_value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'loss_value_created'))
self.loss_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'loss_value_destroyed'))
self.mvrv: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'mvrv'))
self.neg_realized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_realized_loss'))
self.net_pnl_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'net_pnl_change_1m'))
self.net_pnl_change_1m_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_pnl_change_1m_rel_to_market_cap'))
self.net_pnl_change_1m_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_pnl_change_1m_rel_to_realized_cap'))
self.net_realized_pnl: CumulativeHeightPattern[CentsSigned] = CumulativeHeightPattern(client, _m(acc, 'net_realized_pnl'))
self.net_realized_pnl_ema_1w: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'net_realized_pnl_ema_1w'))
self.net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap'))
self.profit_flow: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'profit_flow'))
self.profit_value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'profit_value_created'))
self.profit_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'profit_value_destroyed'))
self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap'))
self.realized_cap_cents: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_cap_cents'))
self.realized_cap_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'realized_cap_change_1m'))
self.realized_loss: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_loss'))
self.realized_loss_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_loss_ema_1w'))
self.realized_loss_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap'))
self.realized_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'realized_price'))
self.realized_price_ratio: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'realized_price_ratio'))
self.realized_profit: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_profit'))
self.realized_profit_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_profit_ema_1w'))
self.realized_profit_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap'))
self.sent_in_loss: BaseCumulativePattern = BaseCumulativePattern(client, _m(acc, 'sent_in_loss'))
self.sent_in_loss_ema: _2wPattern = _2wPattern(client, _m(acc, 'sent_in_loss_ema_2w'))
self.sent_in_profit: BaseCumulativePattern = BaseCumulativePattern(client, _m(acc, 'sent_in_profit'))
self.sent_in_profit_ema: _2wPattern = _2wPattern(client, _m(acc, 'sent_in_profit_ema_2w'))
self.sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, _m(acc, 'sopr'))
self.sopr_24h_ema: _1m1wPattern = _1m1wPattern(client, _m(acc, 'sopr_24h_ema'))
self.value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'value_created'))
self.value_created_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'value_created'))
self.value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'value_destroyed'))
self.value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'value_destroyed'))
class _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern:
"""Pattern struct for repeated tree structure."""
@@ -2261,6 +2159,40 @@ class _0sdM0M1M1sdM2M2sdM3sdP0P1P1sdP2P2sdP3sdSdSmaZscorePattern:
self.sma: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'sma_4y'))
self.zscore: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'zscore_4y'))
class GrossMvrvNegNetRealizedSentSoprValuePattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.gross_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_gross_pnl'))
self.mvrv: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'mvrv'))
self.neg_realized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_realized_loss'))
self.net_realized_pnl: CumulativeHeightPattern[CentsSigned] = CumulativeHeightPattern(client, _m(acc, 'net_realized_pnl'))
self.net_realized_pnl_ema_1w: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'net_realized_pnl_ema_1w'))
self.net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap'))
self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap'))
self.realized_cap_cents: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_cap_cents'))
self.realized_cap_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'realized_cap_change_1m'))
self.realized_loss: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_loss'))
self.realized_loss_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_loss_ema_1w'))
self.realized_loss_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap'))
self.realized_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'realized_price'))
self.realized_price_ratio: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'realized_price_ratio'))
self.realized_price_ratio_percentiles: RatioPattern = RatioPattern(client, _m(acc, 'realized_price_ratio'))
self.realized_profit: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_profit'))
self.realized_profit_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_profit_ema_1w'))
self.realized_profit_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap'))
self.sent_in_loss: BaseCumulativePattern = BaseCumulativePattern(client, _m(acc, 'sent_in_loss'))
self.sent_in_loss_ema: _2wPattern = _2wPattern(client, _m(acc, 'sent_in_loss_ema_2w'))
self.sent_in_profit: BaseCumulativePattern = BaseCumulativePattern(client, _m(acc, 'sent_in_profit'))
self.sent_in_profit_ema: _2wPattern = _2wPattern(client, _m(acc, 'sent_in_profit_ema_2w'))
self.sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, _m(acc, 'sopr'))
self.sopr_24h_ema: _1m1wPattern = _1m1wPattern(client, _m(acc, 'sopr_24h_ema'))
self.value_created: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'value_created'))
self.value_created_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'value_created'))
self.value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'value_destroyed'))
self.value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, _m(acc, 'value_destroyed'))
class InvestedNegNetNuplSupplyUnrealizedPattern3:
"""Pattern struct for repeated tree structure."""
@@ -2287,31 +2219,6 @@ class InvestedNegNetNuplSupplyUnrealizedPattern3:
self.unrealized_profit_rel_to_own_gross_pnl: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'unrealized_profit_rel_to_own_gross_pnl'))
self.unrealized_profit_rel_to_own_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap'))
class GrossMvrvNegNetRealizedSoprPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.gross_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_gross_pnl'))
self.mvrv: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'mvrv'))
self.neg_realized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_realized_loss'))
self.net_realized_pnl: CumulativeHeightPattern[CentsSigned] = CumulativeHeightPattern(client, _m(acc, 'net_realized_pnl'))
self.net_realized_pnl_ema_1w: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'net_realized_pnl_ema_1w'))
self.net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_realized_pnl_rel_to_realized_cap'))
self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap'))
self.realized_cap_cents: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_cap_cents'))
self.realized_cap_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, _m(acc, 'realized_cap_change_1m'))
self.realized_loss: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_loss'))
self.realized_loss_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_loss_ema_1w'))
self.realized_loss_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap'))
self.realized_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'realized_price'))
self.realized_price_ratio: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'realized_price_ratio'))
self.realized_profit: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_profit'))
self.realized_profit_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_profit_ema_1w'))
self.realized_profit_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap'))
self.sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, _m(acc, 'sopr'))
self.sopr_24h_ema: _1m1wPattern = _1m1wPattern(client, _m(acc, 'sopr_24h_ema'))
class Pct05Pct10Pct15Pct20Pct25Pct30Pct35Pct40Pct45Pct50Pct55Pct60Pct65Pct70Pct75Pct80Pct85Pct90Pct95Pattern:
"""Pattern struct for repeated tree structure."""
@@ -2505,6 +2412,22 @@ class AverageGainsLossesRsiStochPattern:
self.stoch_rsi_d: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'stoch_d_24h'))
self.stoch_rsi_k: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'stoch_k_24h'))
class NegNetNuplSupplyUnrealizedPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap'))
self.net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap'))
self.nupl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'nupl'))
self.supply_in_loss_rel_to_circulating_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply'))
self.supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_loss_rel_to_own_supply'))
self.supply_in_profit_rel_to_circulating_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply'))
self.supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_profit_rel_to_own_supply'))
self.supply_rel_to_circulating_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_rel_to_circulating_supply'))
self.unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'unrealized_loss_rel_to_market_cap'))
self.unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'unrealized_profit_rel_to_market_cap'))
class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern:
"""Pattern struct for repeated tree structure."""
@@ -2550,21 +2473,6 @@ class AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern:
self.pct90: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, _m(acc, 'p90'))
self.sum: _1m1w1y24hPattern[StoredU64] = _1m1w1y24hPattern(client, _m(acc, 'sum'))
class NetNuplSupplyUnrealizedPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap'))
self.nupl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'nupl'))
self.supply_in_loss_rel_to_circulating_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply'))
self.supply_in_loss_rel_to_own_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_loss_rel_to_own_supply'))
self.supply_in_profit_rel_to_circulating_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply'))
self.supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_in_profit_rel_to_own_supply'))
self.supply_rel_to_circulating_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'supply_rel_to_circulating_supply'))
self.unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'unrealized_loss_rel_to_market_cap'))
self.unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'unrealized_profit_rel_to_market_cap'))
class AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern(Generic[T]):
"""Pattern struct for repeated tree structure."""
@@ -2603,10 +2511,10 @@ class ActivityAddrOutputsRealizedRelativeSupplyUnrealizedPattern:
self.addr_count: MetricPattern1[StoredU64] = MetricPattern1(client, _m(acc, 'addr_count'))
self.addr_count_change_1m: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'addr_count_change_1m'))
self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count'))
self.realized: GrossMvrvNegNetRealizedSoprPattern = GrossMvrvNegNetRealizedSoprPattern(client, acc)
self.relative: NetNuplSupplyUnrealizedPattern = NetNuplSupplyUnrealizedPattern(client, acc)
self.realized: MvrvRealizedPattern = MvrvRealizedPattern(client, acc)
self.relative: SupplyPattern = SupplyPattern(client, _m(acc, 'supply_in'))
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, _m(acc, 'supply'))
self.unrealized: NegNetSupplyUnrealizedPattern = NegNetSupplyUnrealizedPattern(client, acc)
self.unrealized: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply_in'))
class AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern(Generic[T]):
"""Pattern struct for repeated tree structure."""
@@ -2643,23 +2551,36 @@ class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern:
self.activity: CoinblocksCoindaysSentPattern = CoinblocksCoindaysSentPattern(client, acc)
self.cost_basis: MaxMinPattern = MaxMinPattern(client, _m(acc, 'cost_basis'))
self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count'))
self.realized: CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern = CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern(client, acc)
self.realized: GrossMvrvNegNetRealizedSentSoprValuePattern = GrossMvrvNegNetRealizedSentSoprValuePattern(client, acc)
self.relative: InvestedNegNetNuplSupplyUnrealizedPattern = InvestedNegNetNuplSupplyUnrealizedPattern(client, acc)
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, _m(acc, 'supply'))
self.unrealized: GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern = GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern(client, acc)
class ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4:
class GrossNegNetSupplyUnrealizedPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.activity: CoinblocksCoindaysSentPattern = CoinblocksCoindaysSentPattern(client, acc)
self.cost_basis: MaxMinPattern = MaxMinPattern(client, _m(acc, 'cost_basis'))
self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count'))
self.realized: CapitulationGrossLossMvrvNegNetProfitRealizedSentSoprValuePattern = CapitulationGrossLossMvrvNegNetProfitRealizedSentSoprValuePattern(client, acc)
self.relative: NetNuplSupplyUnrealizedPattern = NetNuplSupplyUnrealizedPattern(client, acc)
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, _m(acc, 'supply'))
self.unrealized: NegNetSupplyUnrealizedPattern = NegNetSupplyUnrealizedPattern(client, acc)
self.gross_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'unrealized_gross_pnl'))
self.neg_unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss'))
self.net_unrealized_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'net_unrealized_pnl'))
self.supply_in_loss: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'supply_in_loss'))
self.supply_in_profit: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'supply_in_profit'))
self.unrealized_loss: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'unrealized_loss'))
self.unrealized_profit: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'unrealized_profit'))
class MvrvRealizedPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.mvrv: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'mvrv'))
self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap'))
self.realized_cap_cents: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_cap_cents'))
self.realized_loss: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_loss'))
self.realized_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'realized_price'))
self.realized_price_ratio: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'realized_price_ratio'))
self.realized_profit: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, _m(acc, 'realized_profit'))
class _1m1w1y24hBaseCumulativePattern:
"""Pattern struct for repeated tree structure."""
@@ -2673,6 +2594,18 @@ class _1m1w1y24hBaseCumulativePattern:
self.base: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, acc)
self.cumulative: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'cumulative'))
class ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.activity: SentPattern = SentPattern(client, _m(acc, 'sent'))
self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count'))
self.realized: GrossMvrvNegNetRealizedSentSoprValuePattern = GrossMvrvNegNetRealizedSentSoprValuePattern(client, acc)
self.relative: NegNetNuplSupplyUnrealizedPattern = NegNetNuplSupplyUnrealizedPattern(client, acc)
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, _m(acc, 'supply'))
self.unrealized: GrossNegNetSupplyUnrealizedPattern = GrossNegNetSupplyUnrealizedPattern(client, acc)
class ActivityOutputsRealizedRelativeSupplyUnrealizedPattern:
"""Pattern struct for repeated tree structure."""
@@ -2680,10 +2613,10 @@ class ActivityOutputsRealizedRelativeSupplyUnrealizedPattern:
"""Create pattern node with accumulated metric name."""
self.activity: SentPattern = SentPattern(client, _m(acc, 'sent'))
self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count'))
self.realized: GrossMvrvNegNetRealizedSoprPattern = GrossMvrvNegNetRealizedSoprPattern(client, acc)
self.relative: NetNuplSupplyUnrealizedPattern = NetNuplSupplyUnrealizedPattern(client, acc)
self.realized: MvrvRealizedPattern = MvrvRealizedPattern(client, acc)
self.relative: SupplyPattern = SupplyPattern(client, _m(acc, 'supply_in'))
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, _m(acc, 'supply'))
self.unrealized: NegNetSupplyUnrealizedPattern = NegNetSupplyUnrealizedPattern(client, acc)
self.unrealized: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply_in'))
class BalanceBothReactivatedReceivingSendingPattern:
"""Pattern struct for repeated tree structure."""
@@ -2697,18 +2630,6 @@ class BalanceBothReactivatedReceivingSendingPattern:
self.receiving: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern[StoredU32] = AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern(client, _m(acc, 'receiving'))
self.sending: AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern[StoredU32] = AverageHeightMaxMedianMinPct10Pct25Pct75Pct90Pattern(client, _m(acc, 'sending'))
class NegNetSupplyUnrealizedPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.neg_unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss'))
self.net_unrealized_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'net_unrealized_pnl'))
self.supply_in_loss: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'supply_in_loss'))
self.supply_in_profit: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, _m(acc, 'supply_in_profit'))
self.unrealized_loss: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'unrealized_loss'))
self.unrealized_profit: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'unrealized_profit'))
class EmaHistogramLineSignalPattern:
"""Pattern struct for repeated tree structure."""
@@ -2720,28 +2641,6 @@ class EmaHistogramLineSignalPattern:
self.line: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'line_24h'))
self.signal: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'signal_24h'))
class MvrvRealizedPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.mvrv: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'mvrv'))
self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_cap'))
self.realized_cap_cents: MetricPattern1[Cents] = MetricPattern1(client, _m(acc, 'realized_cap_cents'))
self.realized_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, 'realized_price'))
self.realized_price_ratio: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'realized_price_ratio'))
class OutputsRealizedRelativeSupplyUnrealizedPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated metric name."""
self.outputs: UtxoPattern = UtxoPattern(client, _m(acc, 'utxo_count'))
self.realized: MvrvRealizedPattern = MvrvRealizedPattern(client, acc)
self.relative: SupplyPattern = SupplyPattern(client, _m(acc, 'supply_in'))
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, _m(acc, 'supply'))
self.unrealized: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply_in'))
class _1m1w1y24hPattern2:
"""Pattern struct for repeated tree structure."""
@@ -4307,11 +4206,21 @@ class MetricsTree_Distribution_AddressesData:
self.funded: MetricPattern34[FundedAddressData] = MetricPattern34(client, 'fundedaddressdata')
self.empty: MetricPattern35[EmptyAddressData] = MetricPattern35(client, 'emptyaddressdata')
class MetricsTree_Distribution_UtxoCohorts_All_Adjusted:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self.adjusted_value_created: MetricPattern1[Cents] = MetricPattern1(client, 'adjusted_value_created')
self.adjusted_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, 'adjusted_value_destroyed')
self.adjusted_value_created_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'adjusted_value_created')
self.adjusted_value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'adjusted_value_destroyed')
self.adjusted_sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'adjusted_sopr')
self.adjusted_sopr_ema: _1m1wPattern = _1m1wPattern(client, 'adjusted_sopr_24h_ema')
class MetricsTree_Distribution_UtxoCohorts_All_Relative:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self.neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'neg_unrealized_loss_rel_to_market_cap')
self.invested_capital_in_profit_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'invested_capital_in_profit_rel_to_realized_cap')
self.invested_capital_in_loss_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'invested_capital_in_loss_rel_to_realized_cap')
self.supply_in_profit_rel_to_own_supply: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'supply_in_profit_rel_to_own_supply')
@@ -4319,6 +4228,7 @@ class MetricsTree_Distribution_UtxoCohorts_All_Relative:
self.unrealized_profit_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'unrealized_profit_rel_to_market_cap')
self.unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'unrealized_loss_rel_to_market_cap')
self.net_unrealized_pnl_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'net_unrealized_pnl_rel_to_market_cap')
self.neg_unrealized_loss_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'neg_unrealized_loss_rel_to_market_cap')
self.nupl: MetricPattern1[StoredF32] = MetricPattern1(client, 'nupl')
self.unrealized_profit_rel_to_own_gross_pnl: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'unrealized_profit_rel_to_own_gross_pnl')
self.unrealized_loss_rel_to_own_gross_pnl: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'unrealized_loss_rel_to_own_gross_pnl')
@@ -4332,10 +4242,13 @@ class MetricsTree_Distribution_UtxoCohorts_All:
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, 'supply')
self.outputs: UtxoPattern = UtxoPattern(client, 'utxo_count')
self.activity: CoinblocksCoindaysSentPattern = CoinblocksCoindaysSentPattern(client, '')
self.realized: AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern = AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern(client, '')
self.realized: CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern = CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern(client, '')
self.cost_basis: InvestedMaxMinPercentilesPattern = InvestedMaxMinPercentilesPattern(client, '')
self.unrealized: GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern = GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern(client, '')
self.adjusted: MetricsTree_Distribution_UtxoCohorts_All_Adjusted = MetricsTree_Distribution_UtxoCohorts_All_Adjusted(client)
self.relative: MetricsTree_Distribution_UtxoCohorts_All_Relative = MetricsTree_Distribution_UtxoCohorts_All_Relative(client)
self.dormancy: MetricPattern1[StoredF32] = MetricPattern1(client, 'dormancy')
self.velocity: MetricPattern1[StoredF32] = MetricPattern1(client, 'velocity')
class MetricsTree_Distribution_UtxoCohorts_Sth:
"""Metrics tree node."""
@@ -4344,70 +4257,18 @@ class MetricsTree_Distribution_UtxoCohorts_Sth:
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, 'sth_supply')
self.outputs: UtxoPattern = UtxoPattern(client, 'sth_utxo_count')
self.activity: CoinblocksCoindaysSentPattern = CoinblocksCoindaysSentPattern(client, 'sth')
self.realized: AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern = AdjustedCapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern(client, 'sth')
self.realized: CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern = CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern(client, 'sth')
self.cost_basis: InvestedMaxMinPercentilesPattern = InvestedMaxMinPercentilesPattern(client, 'sth')
self.unrealized: GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern = GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern(client, 'sth')
self.relative: InvestedNegNetNuplSupplyUnrealizedPattern3 = InvestedNegNetNuplSupplyUnrealizedPattern3(client, 'sth')
class MetricsTree_Distribution_UtxoCohorts_Lth_Realized:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self.investor_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'lth_investor_price')
self.investor_price_ratio: BpsRatioPattern = BpsRatioPattern(client, 'lth_investor_price_ratio')
self.lower_price_band: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'lth_lower_price_band')
self.upper_price_band: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'lth_upper_price_band')
self.cap_raw: MetricPattern18[CentsSats] = MetricPattern18(client, 'lth_cap_raw')
self.investor_cap_raw: MetricPattern18[CentsSquaredSats] = MetricPattern18(client, 'lth_investor_cap_raw')
self.sell_side_risk_ratio: _1m1w1y24hPattern2 = _1m1w1y24hPattern2(client, 'lth_sell_side_risk_ratio')
self.sell_side_risk_ratio_24h_ema: _1m1wPattern2 = _1m1wPattern2(client, 'lth_sell_side_risk_ratio_24h_ema')
self.peak_regret: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, 'lth_realized_peak_regret')
self.peak_regret_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'lth_realized_peak_regret_rel_to_realized_cap')
self.profit_value_created: MetricPattern1[Cents] = MetricPattern1(client, 'lth_profit_value_created')
self.profit_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, 'lth_profit_value_destroyed')
self.loss_value_created: MetricPattern1[Cents] = MetricPattern1(client, 'lth_loss_value_created')
self.loss_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, 'lth_loss_value_destroyed')
self.value_created: MetricPattern1[Cents] = MetricPattern1(client, 'lth_value_created')
self.value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, 'lth_value_destroyed')
self.capitulation_flow: MetricPattern1[Dollars] = MetricPattern1(client, 'lth_capitulation_flow')
self.profit_flow: MetricPattern1[Dollars] = MetricPattern1(client, 'lth_profit_flow')
self.value_created_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'lth_value_created')
self.value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'lth_value_destroyed')
self.gross_pnl_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'lth_gross_pnl_sum')
self.net_pnl_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, 'lth_net_pnl_change_1m')
self.net_pnl_change_1m_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'lth_net_pnl_change_1m_rel_to_realized_cap')
self.net_pnl_change_1m_rel_to_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'lth_net_pnl_change_1m_rel_to_market_cap')
self.sent_in_profit: BaseCumulativePattern = BaseCumulativePattern(client, 'lth_sent_in_profit')
self.sent_in_profit_ema: _2wPattern = _2wPattern(client, 'lth_sent_in_profit_ema_2w')
self.sent_in_loss: BaseCumulativePattern = BaseCumulativePattern(client, 'lth_sent_in_loss')
self.sent_in_loss_ema: _2wPattern = _2wPattern(client, 'lth_sent_in_loss_ema_2w')
self.realized_cap_cents: MetricPattern1[Cents] = MetricPattern1(client, 'lth_realized_cap_cents')
self.realized_profit: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, 'lth_realized_profit')
self.realized_loss: CumulativeHeightPattern[Cents] = CumulativeHeightPattern(client, 'lth_realized_loss')
self.realized_cap: MetricPattern1[Dollars] = MetricPattern1(client, 'lth_realized_cap')
self.realized_price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'lth_realized_price')
self.realized_price_ratio: BpsRatioPattern = BpsRatioPattern(client, 'lth_realized_price_ratio')
self.realized_cap_change_1m: MetricPattern1[CentsSigned] = MetricPattern1(client, 'lth_realized_cap_change_1m')
self.mvrv: MetricPattern1[StoredF32] = MetricPattern1(client, 'lth_mvrv')
self.neg_realized_loss: MetricPattern1[Dollars] = MetricPattern1(client, 'lth_neg_realized_loss')
self.net_realized_pnl: CumulativeHeightPattern[CentsSigned] = CumulativeHeightPattern(client, 'lth_net_realized_pnl')
self.net_realized_pnl_ema_1w: MetricPattern1[CentsSigned] = MetricPattern1(client, 'lth_net_realized_pnl_ema_1w')
self.gross_pnl: CentsUsdPattern = CentsUsdPattern(client, 'lth_realized_gross_pnl')
self.realized_profit_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, 'lth_realized_profit_ema_1w')
self.realized_loss_ema_1w: MetricPattern1[Cents] = MetricPattern1(client, 'lth_realized_loss_ema_1w')
self.sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'lth_sopr')
self.sopr_24h_ema: _1m1wPattern = _1m1wPattern(client, 'lth_sopr_24h_ema')
self.realized_profit_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'lth_realized_profit_rel_to_realized_cap')
self.realized_loss_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'lth_realized_loss_rel_to_realized_cap')
self.net_realized_pnl_rel_to_realized_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'lth_net_realized_pnl_rel_to_realized_cap')
self.realized_cap_rel_to_own_market_cap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'lth_realized_cap_rel_to_own_market_cap')
self.realized_profit_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'lth_realized_profit')
self.realized_loss_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'lth_realized_loss')
self.realized_profit_to_loss_ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'lth_realized_profit_to_loss_ratio')
self.realized_price_ratio_percentiles: RatioPattern = RatioPattern(client, 'lth_realized_price_ratio')
self.realized_price_ratio_std_dev: RatioPattern2 = RatioPattern2(client, 'lth_realized_price_ratio')
self.investor_price_ratio_percentiles: RatioPattern = RatioPattern(client, 'lth_investor_price_ratio')
self.investor_price_ratio_std_dev: RatioPattern2 = RatioPattern2(client, 'lth_investor_price_ratio')
self.dormancy: MetricPattern1[StoredF32] = MetricPattern1(client, 'sth_dormancy')
self.velocity: MetricPattern1[StoredF32] = MetricPattern1(client, 'sth_velocity')
self.adjusted_value_created: MetricPattern1[Cents] = MetricPattern1(client, 'sth_adjusted_value_created')
self.adjusted_value_destroyed: MetricPattern1[Cents] = MetricPattern1(client, 'sth_adjusted_value_destroyed')
self.adjusted_value_created_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'sth_adjusted_value_created')
self.adjusted_value_destroyed_sum: _1m1w1y24hPattern[Cents] = _1m1w1y24hPattern(client, 'sth_adjusted_value_destroyed')
self.adjusted_sopr: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'sth_adjusted_sopr')
self.adjusted_sopr_ema: _1m1wPattern = _1m1wPattern(client, 'sth_adjusted_sopr_24h_ema')
class MetricsTree_Distribution_UtxoCohorts_Lth:
"""Metrics tree node."""
@@ -4416,10 +4277,12 @@ class MetricsTree_Distribution_UtxoCohorts_Lth:
self.supply: ChangeHalvedTotalPattern = ChangeHalvedTotalPattern(client, 'lth_supply')
self.outputs: UtxoPattern = UtxoPattern(client, 'lth_utxo_count')
self.activity: CoinblocksCoindaysSentPattern = CoinblocksCoindaysSentPattern(client, 'lth')
self.realized: MetricsTree_Distribution_UtxoCohorts_Lth_Realized = MetricsTree_Distribution_UtxoCohorts_Lth_Realized(client)
self.realized: CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern = CapCapitulationGrossInvestorLossLowerMvrvNegNetPeakProfitRealizedSellSentSoprUpperValuePattern(client, 'lth')
self.cost_basis: InvestedMaxMinPercentilesPattern = InvestedMaxMinPercentilesPattern(client, 'lth')
self.unrealized: GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern = GreedGrossInvestedInvestorNegNetPainSupplyUnrealizedPattern(client, 'lth')
self.relative: InvestedNegNetNuplSupplyUnrealizedPattern3 = InvestedNegNetNuplSupplyUnrealizedPattern3(client, 'lth')
self.dormancy: MetricPattern1[StoredF32] = MetricPattern1(client, 'lth_dormancy')
self.velocity: MetricPattern1[StoredF32] = MetricPattern1(client, 'lth_velocity')
class MetricsTree_Distribution_UtxoCohorts_AgeRange:
"""Metrics tree node."""
@@ -4451,47 +4314,80 @@ class MetricsTree_Distribution_UtxoCohorts_MaxAge:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self._1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_1w_old')
self._1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_1m_old')
self._2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_2m_old')
self._3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_3m_old')
self._4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_4m_old')
self._5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_5m_old')
self._6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_6m_old')
self._1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_1y_old')
self._2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_2y_old')
self._3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_3y_old')
self._4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_4y_old')
self._5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_5y_old')
self._6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_6y_old')
self._7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_7y_old')
self._8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_8y_old')
self._10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_10y_old')
self._12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_12y_old')
self._15y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_under_15y_old')
self._1w: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_1w_old')
self._1m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_1m_old')
self._2m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_2m_old')
self._3m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_3m_old')
self._4m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_4m_old')
self._5m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_5m_old')
self._6m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_6m_old')
self._1y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_1y_old')
self._2y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_2y_old')
self._3y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_3y_old')
self._4y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_4y_old')
self._5y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_5y_old')
self._6y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_6y_old')
self._7y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_7y_old')
self._8y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_8y_old')
self._10y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_10y_old')
self._12y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_12y_old')
self._15y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_under_15y_old')
class MetricsTree_Distribution_UtxoCohorts_MinAge:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self._1d: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1d_old')
self._1w: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1w_old')
self._1m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1m_old')
self._2m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_2m_old')
self._3m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_3m_old')
self._4m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_4m_old')
self._5m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_5m_old')
self._6m: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_6m_old')
self._1y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_1y_old')
self._2y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_2y_old')
self._3y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_3y_old')
self._4y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_4y_old')
self._5y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_5y_old')
self._6y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_6y_old')
self._7y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_7y_old')
self._8y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_8y_old')
self._10y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_10y_old')
self._12y: ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4 = ActivityCostOutputsRealizedRelativeSupplyUnrealizedPattern4(client, 'utxos_over_12y_old')
self._1d: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_1d_old')
self._1w: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_1w_old')
self._1m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_1m_old')
self._2m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_2m_old')
self._3m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_3m_old')
self._4m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_4m_old')
self._5m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_5m_old')
self._6m: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_6m_old')
self._1y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_1y_old')
self._2y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_2y_old')
self._3y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_3y_old')
self._4y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_4y_old')
self._5y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_5y_old')
self._6y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_6y_old')
self._7y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_7y_old')
self._8y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_8y_old')
self._10y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_10y_old')
self._12y: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'utxos_over_12y_old')
class MetricsTree_Distribution_UtxoCohorts_Epoch:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self._0: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'epoch_0')
self._1: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'epoch_1')
self._2: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'epoch_2')
self._3: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'epoch_3')
self._4: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'epoch_4')
class MetricsTree_Distribution_UtxoCohorts_Class:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self._2009: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2009')
self._2010: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2010')
self._2011: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2011')
self._2012: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2012')
self._2013: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2013')
self._2014: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2014')
self._2015: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2015')
self._2016: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2016')
self._2017: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2017')
self._2018: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2018')
self._2019: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2019')
self._2020: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2020')
self._2021: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2021')
self._2022: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2022')
self._2023: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2023')
self._2024: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2024')
self._2025: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2025')
self._2026: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2 = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern2(client, 'class_2026')
class MetricsTree_Distribution_UtxoCohorts_GeAmount:
"""Metrics tree node."""
@@ -4549,54 +4445,21 @@ class MetricsTree_Distribution_UtxoCohorts_LtAmount:
self._10k_btc: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'utxos_under_10k_btc')
self._100k_btc: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'utxos_under_100k_btc')
class MetricsTree_Distribution_UtxoCohorts_Epoch:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self._0: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'epoch_0')
self._1: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'epoch_1')
self._2: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'epoch_2')
self._3: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'epoch_3')
self._4: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'epoch_4')
class MetricsTree_Distribution_UtxoCohorts_Class:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self._2009: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2009')
self._2010: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2010')
self._2011: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2011')
self._2012: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2012')
self._2013: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2013')
self._2014: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2014')
self._2015: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2015')
self._2016: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2016')
self._2017: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2017')
self._2018: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2018')
self._2019: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2019')
self._2020: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2020')
self._2021: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2021')
self._2022: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2022')
self._2023: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2023')
self._2024: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2024')
self._2025: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2025')
self._2026: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'class_2026')
class MetricsTree_Distribution_UtxoCohorts_Type:
"""Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''):
self.p2pk65: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2pk65')
self.p2pk33: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2pk33')
self.p2pkh: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2pkh')
self.p2ms: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2ms')
self.p2sh: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2sh')
self.p2wpkh: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2wpkh')
self.p2wsh: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2wsh')
self.p2tr: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2tr')
self.p2a: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2a')
self.unknown: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'unknown_outputs')
self.empty: OutputsRealizedRelativeSupplyUnrealizedPattern = OutputsRealizedRelativeSupplyUnrealizedPattern(client, 'empty_outputs')
self.p2pk65: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2pk65')
self.p2pk33: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2pk33')
self.p2pkh: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2pkh')
self.p2ms: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2ms')
self.p2sh: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2sh')
self.p2wpkh: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2wpkh')
self.p2wsh: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2wsh')
self.p2tr: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2tr')
self.p2a: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'p2a')
self.unknown: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'unknown_outputs')
self.empty: ActivityOutputsRealizedRelativeSupplyUnrealizedPattern = ActivityOutputsRealizedRelativeSupplyUnrealizedPattern(client, 'empty_outputs')
class MetricsTree_Distribution_UtxoCohorts:
"""Metrics tree node."""
@@ -4608,11 +4471,11 @@ class MetricsTree_Distribution_UtxoCohorts:
self.age_range: MetricsTree_Distribution_UtxoCohorts_AgeRange = MetricsTree_Distribution_UtxoCohorts_AgeRange(client)
self.max_age: MetricsTree_Distribution_UtxoCohorts_MaxAge = MetricsTree_Distribution_UtxoCohorts_MaxAge(client)
self.min_age: MetricsTree_Distribution_UtxoCohorts_MinAge = MetricsTree_Distribution_UtxoCohorts_MinAge(client)
self.epoch: MetricsTree_Distribution_UtxoCohorts_Epoch = MetricsTree_Distribution_UtxoCohorts_Epoch(client)
self.class: MetricsTree_Distribution_UtxoCohorts_Class = MetricsTree_Distribution_UtxoCohorts_Class(client)
self.ge_amount: MetricsTree_Distribution_UtxoCohorts_GeAmount = MetricsTree_Distribution_UtxoCohorts_GeAmount(client)
self.amount_range: MetricsTree_Distribution_UtxoCohorts_AmountRange = MetricsTree_Distribution_UtxoCohorts_AmountRange(client)
self.lt_amount: MetricsTree_Distribution_UtxoCohorts_LtAmount = MetricsTree_Distribution_UtxoCohorts_LtAmount(client)
self.epoch: MetricsTree_Distribution_UtxoCohorts_Epoch = MetricsTree_Distribution_UtxoCohorts_Epoch(client)
self.class: MetricsTree_Distribution_UtxoCohorts_Class = MetricsTree_Distribution_UtxoCohorts_Class(client)
self.type_: MetricsTree_Distribution_UtxoCohorts_Type = MetricsTree_Distribution_UtxoCohorts_Type(client)
class MetricsTree_Distribution_AddressCohorts_GeAmount: