mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
)?;
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user