global: snap

This commit is contained in:
nym21
2026-04-18 17:23:12 +02:00
parent 2a93f51e81
commit fd2b93367d
31 changed files with 1004 additions and 988 deletions
@@ -3,7 +3,7 @@ use std::path::Path;
use brk_cohort::{AddrGroups, AmountRange, Filter, Filtered, OverAmount, UnderAmount};
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, StoredU64, Version};
use brk_types::{Height, Indexes, Sats, StoredU64, Version};
use derive_more::{Deref, DerefMut};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Database, Exit, ReadableVec, Rw, StorageMode};
@@ -109,12 +109,19 @@ impl AddrCohorts {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
all_supply_sats: &impl ReadableVec<Height, Sats>,
all_utxo_count: &impl ReadableVec<Height, StoredU64>,
exit: &Exit,
) -> Result<()> {
self.0
.par_iter_mut()
.try_for_each(|v| v.compute_rest_part2(prices, starting_indexes, all_utxo_count, exit))
self.0.par_iter_mut().try_for_each(|v| {
v.compute_rest_part2(
prices,
starting_indexes,
all_supply_sats,
all_utxo_count,
exit,
)
})
}
/// Returns a parallel iterator over all vecs for parallel writing.
@@ -3,7 +3,7 @@ use std::path::Path;
use brk_cohort::{CohortContext, Filter, Filtered};
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPointsSigned32, Cents, Height, Indexes, StoredI64, StoredU64, Version};
use brk_types::{BasisPointsSigned32, Cents, Height, Indexes, Sats, StoredI64, StoredU64, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
@@ -230,10 +230,16 @@ impl CohortVecs for AddrCohortVecs {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
all_supply_sats: &impl ReadableVec<Height, Sats>,
all_utxo_count: &impl ReadableVec<Height, StoredU64>,
exit: &Exit,
) -> Result<()> {
self.metrics
.compute_rest_part2(prices, starting_indexes, all_utxo_count, exit)
self.metrics.compute_rest_part2(
prices,
starting_indexes,
all_supply_sats,
all_utxo_count,
exit,
)
}
}
@@ -1,5 +1,5 @@
use brk_error::Result;
use brk_types::{Cents, Height, Indexes, StoredU64, Version};
use brk_types::{Cents, Height, Indexes, Sats, StoredU64, Version};
use vecdb::{Exit, ReadableVec};
use crate::prices;
@@ -62,6 +62,7 @@ pub trait CohortVecs: DynCohortVecs {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
all_supply_sats: &impl ReadableVec<Height, Sats>,
all_utxo_count: &impl ReadableVec<Height, StoredU64>,
exit: &Exit,
) -> Result<()>;
@@ -660,7 +660,7 @@ impl UTXOCohorts<Rw> {
Box::new(|| {
over_amount.par_iter_mut().try_for_each(|v| {
v.metrics
.compute_rest_part2(prices, starting_indexes, au, exit)
.compute_rest_part2(prices, starting_indexes, ss, au, exit)
})
}),
Box::new(|| {
@@ -678,19 +678,19 @@ impl UTXOCohorts<Rw> {
Box::new(|| {
amount_range.par_iter_mut().try_for_each(|v| {
v.metrics
.compute_rest_part2(prices, starting_indexes, au, exit)
.compute_rest_part2(prices, starting_indexes, ss, au, exit)
})
}),
Box::new(|| {
under_amount.par_iter_mut().try_for_each(|v| {
v.metrics
.compute_rest_part2(prices, starting_indexes, au, exit)
.compute_rest_part2(prices, starting_indexes, ss, au, exit)
})
}),
Box::new(|| {
type_.par_iter_mut().try_for_each(|v| {
v.metrics
.compute_rest_part2(prices, starting_indexes, au, exit)
.compute_rest_part2(prices, starting_indexes, ss, au, exit)
})
}),
];
@@ -2,8 +2,7 @@ use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height, Indexes, Version};
use vecdb::AnyStoredVec;
use vecdb::{Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode};
use vecdb::{AnyStoredVec, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode};
use crate::{
blocks,
@@ -152,6 +151,10 @@ impl AllCohortMetrics {
self.unrealized
.compute_sentiment(starting_indexes, &prices.spot.cents.height, exit)?;
let own_supply_sats = self.supply.total.sats.height.read_only_clone();
self.supply
.compute_dominance(starting_indexes.height, &own_supply_sats, exit)?;
self.relative.compute(
starting_indexes.height,
&self.supply,
@@ -6,14 +6,13 @@ use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
use crate::{
distribution::metrics::{
ActivityCore, CohortMetricsBase, ImportConfig, OutputsBase, RealizedCore, RelativeToAll,
SupplyCore, UnrealizedCore,
ActivityCore, CohortMetricsBase, ImportConfig, OutputsBase, RealizedCore, SupplyCore,
UnrealizedCore,
},
prices,
};
/// Basic cohort metrics: no extensions, with relative (rel_to_all).
/// Used by: age_range cohorts.
/// Basic cohort metrics: no extensions, used by age_range cohorts.
#[derive(Traversable)]
pub struct BasicCohortMetrics<M: StorageMode = Rw> {
#[traversable(skip)]
@@ -23,8 +22,6 @@ pub struct BasicCohortMetrics<M: StorageMode = Rw> {
pub activity: Box<ActivityCore<M>>,
pub realized: Box<RealizedCore<M>>,
pub unrealized: Box<UnrealizedCore<M>>,
#[traversable(flatten)]
pub relative: Box<RelativeToAll<M>>,
}
impl CohortMetricsBase for BasicCohortMetrics {
@@ -51,8 +48,6 @@ impl BasicCohortMetrics {
let unrealized = UnrealizedCore::forced_import(cfg)?;
let realized = RealizedCore::forced_import(cfg)?;
let relative = RelativeToAll::forced_import(cfg)?;
Ok(Self {
filter: cfg.filter.clone(),
supply: Box::new(supply),
@@ -60,7 +55,6 @@ impl BasicCohortMetrics {
activity: Box::new(ActivityCore::forced_import(cfg)?),
realized: Box::new(realized),
unrealized: Box::new(unrealized),
relative: Box::new(relative),
})
}
@@ -87,8 +81,8 @@ impl BasicCohortMetrics {
exit,
)?;
self.relative
.compute(starting_indexes.height, &self.supply, all_supply_sats, exit)?;
self.supply
.compute_dominance(starting_indexes.height, all_supply_sats, exit)?;
self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
@@ -6,8 +6,8 @@ use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
use crate::{
distribution::metrics::{
ActivityCore, CohortMetricsBase, ImportConfig, OutputsBase, RealizedCore, RelativeToAll,
SupplyCore, UnrealizedCore,
ActivityCore, CohortMetricsBase, ImportConfig, OutputsBase, RealizedCore, SupplyCore,
UnrealizedCore,
},
prices,
};
@@ -21,8 +21,6 @@ pub struct CoreCohortMetrics<M: StorageMode = Rw> {
pub activity: Box<ActivityCore<M>>,
pub realized: Box<RealizedCore<M>>,
pub unrealized: Box<UnrealizedCore<M>>,
#[traversable(flatten)]
pub relative: Box<RelativeToAll<M>>,
}
impl CoreCohortMetrics {
@@ -34,7 +32,6 @@ impl CoreCohortMetrics {
activity: Box::new(ActivityCore::forced_import(cfg)?),
realized: Box::new(RealizedCore::forced_import(cfg)?),
unrealized: Box::new(UnrealizedCore::forced_import(cfg)?),
relative: Box::new(RelativeToAll::forced_import(cfg)?),
})
}
@@ -145,8 +142,8 @@ impl CoreCohortMetrics {
exit,
)?;
self.relative
.compute(starting_indexes.height, &self.supply, all_supply_sats, exit)?;
self.supply
.compute_dominance(starting_indexes.height, all_supply_sats, exit)?;
self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
@@ -128,13 +128,15 @@ impl ExtendedCohortMetrics {
self.unrealized
.compute_sentiment(starting_indexes, &prices.spot.cents.height, exit)?;
self.supply
.compute_dominance(starting_indexes.height, all_supply_sats, exit)?;
self.relative.compute(
starting_indexes.height,
&self.supply,
&self.unrealized,
&self.realized,
height_to_market_cap,
all_supply_sats,
&self.supply.total.usd.height,
exit,
)?;
@@ -1,7 +1,7 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, StoredU64};
use brk_types::{Height, Indexes, Sats, StoredU64};
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
use crate::{
@@ -112,6 +112,7 @@ impl MinimalCohortMetrics {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
all_supply_sats: &impl ReadableVec<Height, Sats>,
all_utxo_count: &impl ReadableVec<Height, StoredU64>,
exit: &Exit,
) -> Result<()> {
@@ -129,6 +130,9 @@ impl MinimalCohortMetrics {
exit,
)?;
self.supply
.compute_dominance(starting_indexes.height, all_supply_sats, exit)?;
self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
@@ -1,7 +1,7 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, StoredU64};
use brk_types::{Height, Indexes, Sats, StoredU64};
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
use crate::{
@@ -74,6 +74,7 @@ impl TypeCohortMetrics {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
all_supply_sats: &impl ReadableVec<Height, Sats>,
all_utxo_count: &impl ReadableVec<Height, StoredU64>,
exit: &Exit,
) -> Result<()> {
@@ -91,6 +92,9 @@ impl TypeCohortMetrics {
exit,
)?;
self.supply
.compute_dominance(starting_indexes.height, all_supply_sats, exit)?;
self.outputs
.compute_part2(starting_indexes.height, all_utxo_count, exit)?;
@@ -132,7 +132,7 @@ pub use profitability::ProfitabilityMetrics;
pub use realized::{
AdjustedSopr, RealizedCore, RealizedFull, RealizedFullAccum, RealizedLike, RealizedMinimal,
};
pub use relative::{RelativeForAll, RelativeToAll, RelativeWithExtended};
pub use relative::{RelativeForAll, RelativeWithExtended};
pub use supply::{AvgAmountMetrics, SupplyBase, SupplyCore};
pub use unrealized::{
UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike, UnrealizedMinimal,
@@ -11,10 +11,10 @@ use crate::{
/// Full relative metrics (sth/lth/all tier).
#[derive(Traversable)]
pub struct RelativeFull<M: StorageMode = Rw> {
#[traversable(wrap = "supply/in_profit", rename = "to_own")]
pub supply_in_profit_to_own: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "supply/in_loss", rename = "to_own")]
pub supply_in_loss_to_own: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "supply/in_profit", rename = "share")]
pub supply_in_profit_share: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "supply/in_loss", rename = "share")]
pub supply_in_loss_share: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "unrealized/profit", rename = "to_mcap")]
pub unrealized_profit_to_mcap: PercentPerBlock<BasisPoints16, M>,
@@ -28,8 +28,8 @@ impl RelativeFull {
let v2 = Version::new(2);
Ok(Self {
supply_in_profit_to_own: cfg.import("supply_in_profit_to_own", v1)?,
supply_in_loss_to_own: cfg.import("supply_in_loss_to_own", v1)?,
supply_in_profit_share: cfg.import("supply_in_profit_share", v1)?,
supply_in_loss_share: cfg.import("supply_in_loss_share", v1)?,
unrealized_profit_to_mcap: cfg.import("unrealized_profit_to_mcap", v2)?,
unrealized_loss_to_mcap: cfg.import("unrealized_loss_to_mcap", v2)?,
})
@@ -43,14 +43,14 @@ impl RelativeFull {
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.supply_in_profit_to_own
self.supply_in_profit_share
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&supply.in_profit.sats.height,
&supply.total.sats.height,
exit,
)?;
self.supply_in_loss_to_own
self.supply_in_loss_share
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&supply.in_loss.sats.height,
@@ -11,18 +11,18 @@ use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
/// Present for cohorts with `UnrealizedFull` (all, sth, lth).
#[derive(Traversable)]
pub struct RelativeInvestedCapital<M: StorageMode = Rw> {
#[traversable(wrap = "invested_capital/in_profit", rename = "to_own")]
pub in_profit_to_own: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "invested_capital/in_loss", rename = "to_own")]
pub in_loss_to_own: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "invested_capital/in_profit", rename = "share")]
pub in_profit_share: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "invested_capital/in_loss", rename = "share")]
pub in_loss_share: PercentPerBlock<BasisPoints16, M>,
}
impl RelativeInvestedCapital {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v0 = Version::ZERO;
Ok(Self {
in_profit_to_own: cfg.import("invested_capital_in_profit_to_own", v0)?,
in_loss_to_own: cfg.import("invested_capital_in_loss_to_own", v0)?,
in_profit_share: cfg.import("invested_capital_in_profit_share", v0)?,
in_loss_share: cfg.import("invested_capital_in_loss_share", v0)?,
})
}
@@ -34,14 +34,14 @@ impl RelativeInvestedCapital {
exit: &Exit,
) -> Result<()> {
let realized_cap = &realized.core.minimal.cap.cents.height;
self.in_profit_to_own
self.in_profit_share
.compute_binary::<Cents, Cents, RatioCentsBp16>(
max_from,
&unrealized.invested_capital.in_profit.cents.height,
realized_cap,
exit,
)?;
self.in_loss_to_own
self.in_loss_share
.compute_binary::<Cents, Cents, RatioCentsBp16>(
max_from,
&unrealized.invested_capital.in_loss.cents.height,
@@ -3,7 +3,6 @@ mod extended_own_pnl;
mod for_all;
mod full;
mod invested_capital;
mod to_all;
mod with_extended;
pub use extended_own_market_cap::RelativeExtendedOwnMarketCap;
@@ -11,5 +10,4 @@ pub use extended_own_pnl::RelativeExtendedOwnPnl;
pub use for_all::RelativeForAll;
pub use full::RelativeFull;
pub use invested_capital::RelativeInvestedCapital;
pub use to_all::RelativeToAll;
pub use with_extended::RelativeWithExtended;
@@ -1,62 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, Height, Sats, Version};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::{PercentPerBlock, RatioSatsBp16};
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 = "to_circulating")]
pub supply_to_circulating: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "supply/in_profit", rename = "to_circulating")]
pub supply_in_profit_to_circulating: PercentPerBlock<BasisPoints16, M>,
#[traversable(wrap = "supply/in_loss", rename = "to_circulating")]
pub supply_in_loss_to_circulating: PercentPerBlock<BasisPoints16, M>,
}
impl RelativeToAll {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
supply_to_circulating: cfg.import("supply_to_circulating", Version::ONE)?,
supply_in_profit_to_circulating: cfg
.import("supply_in_profit_to_circulating", Version::ONE)?,
supply_in_loss_to_circulating: cfg
.import("supply_in_loss_to_circulating", Version::ONE)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
supply: &SupplyCore,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.supply_to_circulating
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&supply.total.sats.height,
all_supply_sats,
exit,
)?;
self.supply_in_profit_to_circulating
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&supply.in_profit.sats.height,
all_supply_sats,
exit,
)?;
self.supply_in_loss_to_circulating
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&supply.in_loss.sats.height,
all_supply_sats,
exit,
)?;
Ok(())
}
}
@@ -1,6 +1,6 @@
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};
@@ -8,10 +8,9 @@ use crate::distribution::metrics::{ImportConfig, RealizedFull, SupplyCore, Unrea
use super::{
RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl, RelativeFull, RelativeInvestedCapital,
RelativeToAll,
};
/// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl).
/// Full extended relative metrics (base + own_market_cap + own_pnl + invested_capital).
/// Used by: sth, lth cohorts.
#[derive(Deref, DerefMut, Traversable)]
pub struct RelativeWithExtended<M: StorageMode = Rw> {
@@ -20,8 +19,6 @@ pub struct RelativeWithExtended<M: StorageMode = Rw> {
#[traversable(flatten)]
pub base: RelativeFull<M>,
#[traversable(flatten)]
pub rel_to_all: RelativeToAll<M>,
#[traversable(flatten)]
pub extended_own_market_cap: RelativeExtendedOwnMarketCap<M>,
#[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
@@ -33,7 +30,6 @@ impl RelativeWithExtended {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
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)?,
invested_capital: RelativeInvestedCapital::forced_import(cfg)?,
@@ -48,14 +44,11 @@ impl RelativeWithExtended {
unrealized: &UnrealizedFull,
realized: &RealizedFull,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
own_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base
.compute(max_from, supply, &unrealized.inner.basic, market_cap, exit)?;
self.rel_to_all
.compute(max_from, supply, all_supply_sats, exit)?;
self.extended_own_market_cap
.compute(max_from, &unrealized.inner, own_market_cap, exit)?;
self.extended_own_pnl.compute(
@@ -1,22 +1,26 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPointsSigned32, Height, Indexes, Sats, SatsSigned, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use brk_types::{BasisPoints16, BasisPointsSigned32, Height, Indexes, Sats, SatsSigned, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
use crate::{
distribution::state::{CohortState, CostBasisOps, RealizedOps},
prices,
};
use crate::internal::{AmountPerBlock, LazyRollingDeltasFromHeight};
use crate::internal::{
AmountPerBlock, LazyRollingDeltasFromHeight, PercentPerBlock, RatioSatsBp16,
};
use crate::distribution::metrics::ImportConfig;
/// Base supply metrics: total supply only (2 stored vecs).
/// Base supply metrics: total supply + dominance (share of circulating).
#[derive(Traversable)]
pub struct SupplyBase<M: StorageMode = Rw> {
pub total: AmountPerBlock<M>,
pub delta: LazyRollingDeltasFromHeight<Sats, SatsSigned, BasisPointsSigned32>,
#[traversable(rename = "dominance")]
pub dominance: PercentPerBlock<BasisPoints16, M>,
}
impl SupplyBase {
@@ -31,9 +35,12 @@ impl SupplyBase {
cfg.indexes,
);
let dominance = cfg.import("supply_dominance", Version::ZERO)?;
Ok(Self {
total: supply,
delta,
dominance,
})
}
@@ -50,6 +57,7 @@ impl SupplyBase {
vec![
&mut self.total.sats.height as &mut dyn AnyStoredVec,
&mut self.total.cents.height,
&mut self.dominance.bps.height,
]
}
@@ -62,6 +70,21 @@ impl SupplyBase {
self.total.compute(prices, max_from, exit)
}
pub(crate) fn compute_dominance(
&mut self,
max_from: Height,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.dominance
.compute_binary::<Sats, Sats, RatioSatsBp16>(
max_from,
&self.total.sats.height,
all_supply_sats,
exit,
)
}
pub(crate) fn compute_from_stateful(
&mut self,
starting_indexes: &Indexes,
+16 -2
View File
@@ -560,6 +560,15 @@ impl Vecs {
exit,
)?;
let all_supply_sats = self
.utxo_cohorts
.all
.metrics
.supply
.total
.sats
.height
.read_only_clone();
let all_utxo_count = self
.utxo_cohorts
.all
@@ -568,8 +577,13 @@ impl Vecs {
.unspent_count
.height
.read_only_clone();
self.addr_cohorts
.compute_rest_part2(prices, starting_indexes, &all_utxo_count, exit)?;
self.addr_cohorts.compute_rest_part2(
prices,
starting_indexes,
&all_supply_sats,
&all_utxo_count,
exit,
)?;
let exit = exit.clone();
self.db.run_bg(move |db| {