global: snapshot

This commit is contained in:
nym21
2026-03-10 14:25:11 +01:00
parent 9aed86cbf2
commit ed0c9ade1a
26 changed files with 599 additions and 674 deletions

View File

@@ -55,6 +55,9 @@ impl DynCohortVecs for UTXOCohortVecs<CoreCohortMetrics> {
self.metrics
.unrealized
.truncate_push(height, &unrealized_state)?;
self.metrics
.supply
.truncate_push_profitability(height, &unrealized_state)?;
}
Ok(())
}

View File

@@ -54,6 +54,9 @@ impl DynCohortVecs for UTXOCohortVecs<TypeCohortMetrics> {
self.metrics
.unrealized
.truncate_push(height, &unrealized_state)?;
self.metrics
.supply
.truncate_push_profitability(height, &unrealized_state)?;
}
Ok(())
}

View File

@@ -29,8 +29,6 @@ pub struct ActivityFull<M: StorageMode = Rw> {
pub dormancy: ComputedPerBlock<StoredF32, M>,
pub velocity: ComputedPerBlock<StoredF32, M>,
pub coindays_destroyed_supply_adjusted: ComputedPerBlock<StoredF32, M>,
pub coinyears_destroyed_supply_adjusted: ComputedPerBlock<StoredF32, M>,
}
impl ActivityFull {
@@ -54,8 +52,6 @@ impl ActivityFull {
coinyears_destroyed,
dormancy: cfg.import("dormancy", v1)?,
velocity: cfg.import("velocity", v1)?,
coindays_destroyed_supply_adjusted: cfg.import("coindays_destroyed_supply_adjusted", v1)?,
coinyears_destroyed_supply_adjusted: cfg.import("coinyears_destroyed_supply_adjusted", v1)?,
})
}
@@ -75,8 +71,6 @@ impl ActivityFull {
let mut vecs = self.inner.collect_vecs_mut();
vecs.push(&mut self.dormancy.height);
vecs.push(&mut self.velocity.height);
vecs.push(&mut self.coindays_destroyed_supply_adjusted.height);
vecs.push(&mut self.coinyears_destroyed_supply_adjusted.height);
vecs
}
@@ -161,38 +155,6 @@ impl ActivityFull {
exit,
)?;
// Supply-Adjusted CDD = sum_24h(CDD) / circulating_supply
self.coindays_destroyed_supply_adjusted.height.compute_transform2(
starting_indexes.height,
&self.inner.coindays_destroyed.sum._24h.height,
supply_total_sats,
|(i, cdd_24h, supply_sats, ..)| {
let supply = f64::from(Bitcoin::from(supply_sats));
if supply == 0.0 {
(i, StoredF32::from(0.0f32))
} else {
(i, StoredF32::from((f64::from(cdd_24h) / supply) as f32))
}
},
exit,
)?;
// Supply-Adjusted CYD = CYD / circulating_supply (CYD = 1y rolling sum of CDD)
self.coinyears_destroyed_supply_adjusted.height.compute_transform2(
starting_indexes.height,
&self.coinyears_destroyed.height,
supply_total_sats,
|(i, cdd_1y, supply_sats, ..)| {
let supply = f64::from(Bitcoin::from(supply_sats));
if supply == 0.0 {
(i, StoredF32::from(0.0f32))
} else {
(i, StoredF32::from((f64::from(cdd_1y) / supply) as f32))
}
},
exit,
)?;
Ok(())
}
}

View File

@@ -139,8 +139,8 @@ impl AllCohortMetrics {
self.relative.compute(
starting_indexes.height,
&self.supply.core,
&self.unrealized,
&self.supply.total.sats.height,
height_to_market_cap,
exit,
)?;

View File

@@ -81,9 +81,7 @@ impl BasicCohortMetrics {
self.relative.compute(
starting_indexes.height,
&self.unrealized.supply_in_profit.sats.height,
&self.unrealized.supply_in_loss.sats.height,
&self.supply.total.sats.height,
&self.supply.core,
all_supply_sats,
exit,
)?;

View File

@@ -118,7 +118,7 @@ impl CoreCohortMetrics {
self.realized
.compute_rest_part1(blocks, starting_indexes, exit)?;
self.unrealized.compute_rest(blocks, prices, starting_indexes, exit)?;
self.unrealized.compute_rest(blocks, starting_indexes, exit)?;
Ok(())
}
@@ -141,9 +141,7 @@ impl CoreCohortMetrics {
self.relative.compute(
starting_indexes.height,
&self.unrealized.supply_in_profit.sats.height,
&self.unrealized.supply_in_loss.sats.height,
&self.supply.total.sats.height,
&self.supply.core,
all_supply_sats,
exit,
)?;

View File

@@ -115,8 +115,8 @@ impl ExtendedCohortMetrics {
self.relative.compute(
starting_indexes.height,
&self.supply.core,
&self.unrealized,
&self.supply.total.sats.height,
height_to_market_cap,
all_supply_sats,
&self.supply.total.usd.height,

View File

@@ -7,17 +7,17 @@ use vecdb::{AnyStoredVec, Exit, Rw, StorageMode};
use crate::{blocks, prices};
use crate::distribution::metrics::{
ImportConfig, OutputsBase, RealizedMinimal, SupplyBase, UnrealizedBasic,
ImportConfig, OutputsBase, RealizedMinimal, SupplyCore, UnrealizedBasic,
};
/// TypeCohortMetrics: supply(base), outputs(base), realized(minimal), unrealized(basic).
/// TypeCohortMetrics: supply(core), outputs(base), realized(minimal), unrealized(basic).
///
/// Used for type_ cohorts (p2pkh, p2sh, etc.).
#[derive(Traversable)]
pub struct TypeCohortMetrics<M: StorageMode = Rw> {
#[traversable(skip)]
pub filter: Filter,
pub supply: Box<SupplyBase<M>>,
pub supply: Box<SupplyCore<M>>,
pub outputs: Box<OutputsBase<M>>,
pub realized: Box<RealizedMinimal<M>>,
pub unrealized: Box<UnrealizedBasic<M>>,
@@ -27,7 +27,7 @@ impl TypeCohortMetrics {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
filter: cfg.filter.clone(),
supply: Box::new(SupplyBase::forced_import(cfg)?),
supply: Box::new(SupplyCore::forced_import(cfg)?),
outputs: Box::new(OutputsBase::forced_import(cfg)?),
realized: Box::new(RealizedMinimal::forced_import(cfg)?),
unrealized: Box::new(UnrealizedBasic::forced_import(cfg)?),
@@ -62,7 +62,7 @@ impl TypeCohortMetrics {
self.realized
.compute_rest_part1(blocks, starting_indexes, exit)?;
self.unrealized
.compute_rest(blocks, prices, starting_indexes.height, exit)?;
.compute_rest(blocks, starting_indexes.height, exit)?;
Ok(())
}

View File

@@ -58,7 +58,7 @@ pub use realized::{
pub use relative::{
RelativeForAll, RelativeToAll, RelativeWithExtended,
};
pub use supply::{SupplyBase, SupplyFull};
pub use supply::{SupplyBase, SupplyCore, SupplyFull};
pub use unrealized::{UnrealizedBase, UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike};
use brk_cohort::Filter;
@@ -148,6 +148,8 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState, CostBa
let unrealized_state = state.compute_unrealized_state(height_price);
self.unrealized_mut()
.truncate_push(height, &unrealized_state)?;
self.supply_mut()
.truncate_push_profitability(height, &unrealized_state)?;
Ok(())
}

View File

@@ -1,10 +1,10 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats};
use brk_types::{Dollars, Height};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull};
use super::{RelativeFull, RelativeExtendedOwnPnl};
@@ -30,15 +30,15 @@ impl RelativeForAll {
pub(crate) fn compute(
&mut self,
max_from: Height,
supply: &SupplyCore,
unrealized: &UnrealizedFull,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base.compute(
max_from,
&unrealized.inner.core,
supply_total_sats,
supply,
&unrealized.inner.core.basic,
market_cap,
exit,
)?;

View File

@@ -4,16 +4,16 @@ use brk_types::{BasisPoints16, Dollars, Height, Sats, Version};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{
distribution::metrics::{ImportConfig, UnrealizedCore},
distribution::metrics::{ImportConfig, SupplyCore, UnrealizedBasic},
internal::{PercentPerBlock, RatioDollarsBp16, RatioSatsBp16},
};
/// Full relative metrics (sth/lth/all tier).
#[derive(Traversable)]
pub struct RelativeFull<M: StorageMode = Rw> {
#[traversable(wrap = "unrealized/profit/supply", rename = "rel_to_own_supply")]
#[traversable(wrap = "supply/in_profit", rename = "rel_to_own_supply")]
pub supply_in_profit_rel_to_own_supply: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "unrealized/loss/supply", rename = "rel_to_own_supply")]
#[traversable(wrap = "supply/in_loss", rename = "rel_to_own_supply")]
pub supply_in_loss_rel_to_own_supply: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "unrealized/profit", rename = "rel_to_market_cap")]
@@ -41,23 +41,23 @@ impl RelativeFull {
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedCore,
supply_total_sats: &impl ReadableVec<Height, Sats>,
supply: &SupplyCore,
unrealized: &UnrealizedBasic,
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,
&supply.in_profit.sats.height,
&supply.total.sats.height,
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,
&supply.in_loss.sats.height,
&supply.total.sats.height,
exit,
)?;

View File

@@ -5,16 +5,16 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::{PercentPerBlock, RatioSatsBp16};
use crate::distribution::metrics::ImportConfig;
use crate::distribution::metrics::{ImportConfig, SupplyCore};
/// Relative-to-all metrics (not present for the "all" cohort itself).
#[derive(Traversable)]
pub struct RelativeToAll<M: StorageMode = Rw> {
#[traversable(wrap = "supply", rename = "rel_to_circulating_supply")]
pub supply_rel_to_circulating_supply: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "unrealized/profit/supply", rename = "rel_to_circulating_supply")]
#[traversable(wrap = "supply/in_profit", rename = "rel_to_circulating_supply")]
pub supply_in_profit_rel_to_circulating_supply: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "unrealized/loss/supply", rename = "rel_to_circulating_supply")]
#[traversable(wrap = "supply/in_loss", rename = "rel_to_circulating_supply")]
pub supply_in_loss_rel_to_circulating_supply: PercentPerBlock<BasisPoints16, M>,
}
@@ -33,30 +33,28 @@ impl RelativeToAll {
pub(crate) fn compute(
&mut self,
max_from: Height,
supply_in_profit_sats: &impl ReadableVec<Height, Sats>,
supply_in_loss_sats: &impl ReadableVec<Height, Sats>,
supply_total_sats: &impl ReadableVec<Height, Sats>,
supply: &SupplyCore,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.supply_rel_to_circulating_supply
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
supply_total_sats,
&supply.total.sats.height,
all_supply_sats,
exit,
)?;
self.supply_in_profit_rel_to_circulating_supply
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
supply_in_profit_sats,
&supply.in_profit.sats.height,
all_supply_sats,
exit,
)?;
self.supply_in_loss_rel_to_circulating_supply
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
supply_in_loss_sats,
&supply.in_loss.sats.height,
all_supply_sats,
exit,
)?;

View File

@@ -4,7 +4,7 @@ use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, UnrealizedFull};
use crate::distribution::metrics::{ImportConfig, SupplyCore, UnrealizedFull};
use super::{RelativeFull, RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeToAll};
@@ -38,8 +38,8 @@ impl RelativeWithExtended {
pub(crate) fn compute(
&mut self,
max_from: Height,
supply: &SupplyCore,
unrealized: &UnrealizedFull,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
own_market_cap: &impl ReadableVec<Height, Dollars>,
@@ -47,16 +47,14 @@ impl RelativeWithExtended {
) -> Result<()> {
self.base.compute(
max_from,
&unrealized.inner.core,
supply_total_sats,
supply,
&unrealized.inner.core.basic,
market_cap,
exit,
)?;
self.rel_to_all.compute(
max_from,
&unrealized.supply_in_profit.sats.height,
&unrealized.supply_in_loss.sats.height,
supply_total_sats,
supply,
all_supply_sats,
exit,
)?;

View File

@@ -8,29 +8,29 @@ use crate::{blocks, internal::RollingDelta1m};
use crate::distribution::metrics::ImportConfig;
use super::SupplyBase;
use super::SupplyCore;
/// Full supply metrics: total + delta (4 stored vecs).
/// Full supply metrics: total + in_profit/in_loss + delta (6 stored vecs).
#[derive(Deref, DerefMut, Traversable)]
pub struct SupplyFull<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: SupplyBase<M>,
pub core: SupplyCore<M>,
pub delta: RollingDelta1m<Sats, SatsSigned, M>,
}
impl SupplyFull {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let base = SupplyBase::forced_import(cfg)?;
let core = SupplyCore::forced_import(cfg)?;
let delta = cfg.import("supply_delta", Version::ONE)?;
Ok(Self { base, delta })
Ok(Self { core, delta })
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
self.base.collect_vecs_mut()
self.core.collect_vecs_mut()
}
pub(crate) fn validate_computed_versions(&mut self, _base_version: Version) -> Result<()> {
@@ -43,8 +43,9 @@ impl SupplyFull {
others: &[&Self],
exit: &Exit,
) -> Result<()> {
let base_refs: Vec<&SupplyBase> = others.iter().map(|o| &o.base).collect();
self.base.compute_from_stateful(starting_indexes, &base_refs, exit)
let core_refs: Vec<&SupplyCore> = others.iter().map(|o| &o.core).collect();
self.core
.compute_from_stateful(starting_indexes, &core_refs, exit)
}
pub(crate) fn compute_rest_part1(
@@ -56,7 +57,7 @@ impl SupplyFull {
self.delta.compute(
starting_indexes.height,
&blocks.lookback.height_1m_ago,
&self.base.total.sats.height,
&self.core.total.sats.height,
exit,
)
}

View File

@@ -4,7 +4,7 @@ use brk_types::{CentsSats, CentsSquaredSats, Height, Indexes, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{blocks, distribution::{metrics::ImportConfig, state::UnrealizedState}, prices};
use crate::{blocks, distribution::{metrics::ImportConfig, state::UnrealizedState}};
use super::UnrealizedCore;
@@ -166,11 +166,10 @@ impl UnrealizedBase {
pub(crate) fn compute_rest(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.core.compute_rest(blocks, prices, starting_indexes, exit)?;
self.core.compute_rest(blocks, starting_indexes, exit)?;
Ok(())
}
}

View File

@@ -1,26 +1,17 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Height, Indexes, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::{
blocks,
distribution::{metrics::ImportConfig, state::UnrealizedState},
internal::FiatPerBlockWithSum24h,
prices,
};
use super::UnrealizedMinimal;
/// Basic unrealized metrics: supply in profit/loss + unrealized profit/loss (fiat + 24h sums).
#[derive(Deref, DerefMut, Traversable)]
/// Basic unrealized metrics: unrealized profit/loss (fiat + 24h sums).
#[derive(Traversable)]
pub struct UnrealizedBasic<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub minimal: UnrealizedMinimal<M>,
pub profit: FiatPerBlockWithSum24h<Cents, M>,
pub loss: FiatPerBlockWithSum24h<Cents, M>,
}
@@ -28,24 +19,23 @@ pub struct UnrealizedBasic<M: StorageMode = Rw> {
impl UnrealizedBasic {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v1 = Version::ONE;
let minimal = UnrealizedMinimal::forced_import(cfg)?;
Ok(Self {
minimal,
profit: cfg.import("unrealized_profit", v1)?,
loss: cfg.import("unrealized_loss", v1)?,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.minimal
.min_stateful_height_len()
.min(self.profit.raw.cents.height.len())
self.profit
.raw
.cents
.height
.len()
.min(self.loss.raw.cents.height.len())
}
pub(crate) fn truncate_push(&mut self, height: Height, state: &UnrealizedState) -> Result<()> {
self.minimal.truncate_push(height, state)?;
self.profit
.raw
.cents
@@ -60,10 +50,10 @@ impl UnrealizedBasic {
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.minimal.collect_vecs_mut();
vecs.push(&mut self.profit.raw.cents.height as &mut dyn AnyStoredVec);
vecs.push(&mut self.loss.raw.cents.height);
vecs
vec![
&mut self.profit.raw.cents.height as &mut dyn AnyStoredVec,
&mut self.loss.raw.cents.height,
]
}
pub(crate) fn compute_from_sources(
@@ -72,9 +62,6 @@ impl UnrealizedBasic {
others: &[&Self],
exit: &Exit,
) -> Result<()> {
let minimal_refs: Vec<&UnrealizedMinimal> = others.iter().map(|o| &o.minimal).collect();
self.minimal
.compute_from_sources(starting_indexes, &minimal_refs, exit)?;
sum_others!(self, starting_indexes, others, exit; profit.raw.cents.height);
sum_others!(self, starting_indexes, others, exit; loss.raw.cents.height);
Ok(())
@@ -83,12 +70,9 @@ impl UnrealizedBasic {
pub(crate) fn compute_rest(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.minimal.compute_rest(prices, max_from, exit)?;
self.profit.sum.compute_rolling_sum(
max_from,
&blocks.lookback.height_24h_ago,

View File

@@ -11,7 +11,6 @@ use crate::{
state::UnrealizedState,
},
internal::{CentsSubtractToCentsSigned, FiatPerBlock, LazyPerBlock, NegCentsUnsignedToDollars},
prices,
};
use brk_types::Dollars;
@@ -83,12 +82,11 @@ impl UnrealizedCore {
pub(crate) fn compute_rest(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.basic
.compute_rest(blocks, prices, starting_indexes.height, exit)?;
.compute_rest(blocks, starting_indexes.height, exit)?;
self.net_pnl
.cents

View File

@@ -93,7 +93,7 @@ impl UnrealizedFull {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.inner.compute_rest(blocks, prices, starting_indexes, exit)?;
self.inner.compute_rest(blocks, starting_indexes, exit)?;
self.gross_pnl.cents.height.compute_add(
starting_indexes.height,

View File

@@ -1,80 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::prices;
use crate::internal::AmountPerBlock;
use crate::distribution::{metrics::ImportConfig, state::UnrealizedState};
/// Minimal unrealized metrics: supply in profit/loss only.
#[derive(Traversable)]
pub struct UnrealizedMinimal<M: StorageMode = Rw> {
#[traversable(wrap = "profit", rename = "supply")]
pub supply_in_profit: AmountPerBlock<M>,
#[traversable(wrap = "loss", rename = "supply")]
pub supply_in_loss: AmountPerBlock<M>,
}
impl UnrealizedMinimal {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
Ok(Self {
supply_in_profit: cfg.import("supply_in_profit", v0)?,
supply_in_loss: cfg.import("supply_in_loss", v0)?,
})
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.supply_in_profit
.sats
.height
.len()
.min(self.supply_in_loss.sats.height.len())
}
pub(crate) fn truncate_push(&mut self, height: Height, state: &UnrealizedState) -> Result<()> {
self.supply_in_profit
.sats
.height
.truncate_push(height, state.supply_in_profit)?;
self.supply_in_loss
.sats
.height
.truncate_push(height, state.supply_in_loss)?;
Ok(())
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.supply_in_profit.sats.height as &mut dyn AnyStoredVec,
&mut self.supply_in_profit.cents.height,
&mut self.supply_in_loss.sats.height,
&mut self.supply_in_loss.cents.height,
]
}
pub(crate) fn compute_from_sources(
&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);
Ok(())
}
pub(crate) fn compute_rest(
&mut self,
prices: &prices::Vecs,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.supply_in_profit.compute(prices, max_from, exit)?;
self.supply_in_loss.compute(prices, max_from, exit)?;
Ok(())
}
}

View File

@@ -2,13 +2,11 @@ mod base;
mod basic;
mod core;
mod full;
mod minimal;
pub use self::core::UnrealizedCore;
pub use base::UnrealizedBase;
pub use basic::UnrealizedBasic;
pub use full::UnrealizedFull;
pub use minimal::UnrealizedMinimal;
use brk_error::Result;
use brk_types::{Height, Indexes};
@@ -51,11 +49,11 @@ impl UnrealizedLike for UnrealizedBase {
fn compute_rest(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
_prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_rest(blocks, prices, starting_indexes, exit)
self.compute_rest(blocks, starting_indexes, exit)
}
fn compute_net_sentiment_height(
&mut self,

View File

@@ -1,5 +1,5 @@
use brk_error::Result;
use brk_types::{Dollars, Indexes};
use brk_types::{Bitcoin, Dollars, Indexes, StoredF32};
use vecdb::Exit;
use super::{gini, Vecs};
@@ -71,6 +71,81 @@ impl Vecs {
exit,
)?;
// Thermocap Multiple: market_cap / thermo_cap
// thermo_cap = cumulative subsidy in USD
self.thermocap_multiple
.bps
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
starting_indexes.height,
market_cap,
&mining.rewards.subsidy.cumulative.usd.height,
exit,
)?;
let all_activity = &distribution.utxo_cohorts.all.metrics.activity;
let supply_total_sats = &distribution
.utxo_cohorts
.all
.metrics
.supply
.total
.sats
.height;
// Supply-Adjusted CDD = sum_24h(CDD) / circulating_supply_btc
self.coindays_destroyed_supply_adjusted
.height
.compute_transform2(
starting_indexes.height,
&all_activity.coindays_destroyed.sum._24h.height,
supply_total_sats,
|(i, cdd_24h, supply_sats, ..)| {
let supply = f64::from(Bitcoin::from(supply_sats));
if supply == 0.0 {
(i, StoredF32::from(0.0f32))
} else {
(i, StoredF32::from((f64::from(cdd_24h) / supply) as f32))
}
},
exit,
)?;
// Supply-Adjusted CYD = CYD / circulating_supply_btc (CYD = 1y rolling sum of CDD)
self.coinyears_destroyed_supply_adjusted
.height
.compute_transform2(
starting_indexes.height,
&all_activity.coinyears_destroyed.height,
supply_total_sats,
|(i, cyd, supply_sats, ..)| {
let supply = f64::from(Bitcoin::from(supply_sats));
if supply == 0.0 {
(i, StoredF32::from(0.0f32))
} else {
(i, StoredF32::from((f64::from(cyd) / supply) as f32))
}
},
exit,
)?;
// Supply-Adjusted Dormancy = dormancy / circulating_supply_btc
self.dormancy_supply_adjusted
.height
.compute_transform2(
starting_indexes.height,
&all_activity.dormancy.height,
supply_total_sats,
|(i, dormancy, supply_sats, ..)| {
let supply = f64::from(Bitcoin::from(supply_sats));
if supply == 0.0 {
(i, StoredF32::from(0.0f32))
} else {
(i, StoredF32::from((f64::from(dormancy) / supply) as f32))
}
},
exit,
)?;
let _lock = exit.lock();
self.db.compact()?;
Ok(())

View File

@@ -6,7 +6,7 @@ use brk_types::Version;
use super::Vecs;
use crate::{
indexes,
internal::{finalize_db, open_db, PercentPerBlock, RatioPerBlock},
internal::{finalize_db, open_db, ComputedPerBlock, PercentPerBlock, RatioPerBlock},
};
const VERSION: Version = Version::new(1);
@@ -24,6 +24,14 @@ impl Vecs {
let nvt = RatioPerBlock::forced_import_raw(&db, "nvt", v, indexes)?;
let gini = PercentPerBlock::forced_import(&db, "gini", v, indexes)?;
let rhodl_ratio = RatioPerBlock::forced_import_raw(&db, "rhodl_ratio", v, indexes)?;
let thermocap_multiple =
RatioPerBlock::forced_import_raw(&db, "thermocap_multiple", v, indexes)?;
let coindays_destroyed_supply_adjusted =
ComputedPerBlock::forced_import(&db, "coindays_destroyed_supply_adjusted", v, indexes)?;
let coinyears_destroyed_supply_adjusted =
ComputedPerBlock::forced_import(&db, "coinyears_destroyed_supply_adjusted", v, indexes)?;
let dormancy_supply_adjusted =
ComputedPerBlock::forced_import(&db, "dormancy_supply_adjusted", v, indexes)?;
let this = Self {
db,
@@ -31,6 +39,10 @@ impl Vecs {
nvt,
gini,
rhodl_ratio,
thermocap_multiple,
coindays_destroyed_supply_adjusted,
coinyears_destroyed_supply_adjusted,
dormancy_supply_adjusted,
};
finalize_db(&this.db, &this)?;
Ok(this)

View File

@@ -1,8 +1,8 @@
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, BasisPoints32};
use brk_types::{BasisPoints16, BasisPoints32, StoredF32};
use vecdb::{Database, Rw, StorageMode};
use crate::internal::{PercentPerBlock, RatioPerBlock};
use crate::internal::{ComputedPerBlock, PercentPerBlock, RatioPerBlock};
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
@@ -12,4 +12,8 @@ pub struct Vecs<M: StorageMode = Rw> {
pub nvt: RatioPerBlock<BasisPoints32, M>,
pub gini: PercentPerBlock<BasisPoints16, M>,
pub rhodl_ratio: RatioPerBlock<BasisPoints32, M>,
pub thermocap_multiple: RatioPerBlock<BasisPoints32, M>,
pub coindays_destroyed_supply_adjusted: ComputedPerBlock<StoredF32, M>,
pub coinyears_destroyed_supply_adjusted: ComputedPerBlock<StoredF32, M>,
pub dormancy_supply_adjusted: ComputedPerBlock<StoredF32, M>,
}