global: snapshot

This commit is contained in:
nym21
2026-03-07 22:28:39 +01:00
parent a0efe491e5
commit 90f2d64019
23 changed files with 808 additions and 365 deletions

View File

@@ -6,7 +6,7 @@ use vecdb::{Database, Exit, Rw, StorageMode};
use crate::{
indexes,
internal::{ComputedFromHeightFull, WindowStarts},
internal::{ComputedFromHeightSum, WindowStarts},
};
use super::TotalAddrCountVecs;
@@ -14,9 +14,9 @@ use super::TotalAddrCountVecs;
/// New address count per block (global + per-type)
#[derive(Traversable)]
pub struct NewAddrCountVecs<M: StorageMode = Rw> {
pub all: ComputedFromHeightFull<StoredU64, M>,
pub all: ComputedFromHeightSum<StoredU64, M>,
#[traversable(flatten)]
pub by_addresstype: ByAddressType<ComputedFromHeightFull<StoredU64, M>>,
pub by_addresstype: ByAddressType<ComputedFromHeightSum<StoredU64, M>>,
}
impl NewAddrCountVecs {
@@ -25,11 +25,11 @@ impl NewAddrCountVecs {
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let all = ComputedFromHeightFull::forced_import(db, "new_addr_count", version, indexes)?;
let all = ComputedFromHeightSum::forced_import(db, "new_addr_count", version, indexes)?;
let by_addresstype: ByAddressType<ComputedFromHeightFull<StoredU64>> =
let by_addresstype: ByAddressType<ComputedFromHeightSum<StoredU64>> =
ByAddressType::new_with_name(|name| {
ComputedFromHeightFull::forced_import(
ComputedFromHeightSum::forced_import(
db,
&format!("{name}_new_addr_count"),
version,

View File

@@ -96,7 +96,7 @@ impl AddressCohorts {
exit: &Exit,
) -> Result<()> {
self.par_iter_mut().try_for_each(|v| {
v.addr_count_change_1m.height.compute_rolling_change(
v.addr_count_delta.compute(
starting_indexes.height,
&blocks.count.height_1m_ago,
&v.addr_count.height,

View File

@@ -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::{Cents, Height, Indexes, StoredF64, StoredU64, Version};
use brk_types::{Cents, Height, Indexes, StoredI64, StoredU64, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
@@ -11,7 +11,7 @@ use crate::{
blocks,
distribution::state::{AddressCohortState, MinimalRealizedState},
indexes,
internal::ComputedFromHeight,
internal::{ComputedFromHeight, RollingDelta1m},
prices,
};
@@ -29,7 +29,7 @@ pub struct AddressCohortVecs<M: StorageMode = Rw> {
pub metrics: MinimalCohortMetrics<M>,
pub addr_count: ComputedFromHeight<StoredU64, M>,
pub addr_count_change_1m: ComputedFromHeight<StoredF64, M>,
pub addr_count_delta: RollingDelta1m<StoredU64, StoredI64, M>,
}
impl AddressCohortVecs {
@@ -64,10 +64,10 @@ impl AddressCohortVecs {
version,
indexes,
)?,
addr_count_change_1m: ComputedFromHeight::forced_import(
addr_count_delta: RollingDelta1m::forced_import(
db,
&cfg.name("addr_count_change_1m"),
version,
&cfg.name("addr_count_delta"),
version + Version::ONE,
indexes,
)?,
})

View File

@@ -1,13 +1,16 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Cents, Dollars, Height, Indexes, StoredF32, Version};
use brk_types::{
Bitcoin, Cents, Dollars, Height, Indexes, Sats, SatsSigned, StoredF32, StoredI64, StoredU64,
Version,
};
use vecdb::AnyStoredVec;
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, prices};
use crate::internal::ComputedFromHeight;
use crate::internal::{ComputedFromHeight, RollingDeltaExcept1m};
use crate::distribution::metrics::{
ActivityFull, CohortMetricsBase, CostBasisWithExtended, ImportConfig, OutputsMetrics,
@@ -31,6 +34,9 @@ pub struct AllCohortMetrics<M: StorageMode = Rw> {
pub relative: Box<RelativeForAll<M>>,
pub dormancy: ComputedFromHeight<StoredF32, M>,
pub velocity: ComputedFromHeight<StoredF32, M>,
pub supply_delta_extended: RollingDeltaExcept1m<Sats, SatsSigned, M>,
pub utxo_count_delta_extended: RollingDeltaExcept1m<StoredU64, StoredI64, M>,
}
impl CohortMetricsBase for AllCohortMetrics {
@@ -82,6 +88,8 @@ impl AllCohortMetrics {
relative: Box::new(relative),
dormancy: cfg.import("dormancy", Version::ONE)?,
velocity: cfg.import("velocity", Version::ONE)?,
supply_delta_extended: cfg.import("supply_delta", Version::ONE)?,
utxo_count_delta_extended: cfg.import("utxo_count_delta", Version::ONE)?,
})
}
@@ -123,6 +131,20 @@ impl AllCohortMetrics {
exit,
)?;
let window_starts = blocks.count.window_starts();
self.supply_delta_extended.compute(
starting_indexes.height,
&window_starts,
&self.supply.total.sats.height,
exit,
)?;
self.utxo_count_delta_extended.compute(
starting_indexes.height,
&window_starts,
&self.outputs.utxo_count.height,
exit,
)?;
self.dormancy.height.compute_transform2(
starting_indexes.height,
&self.activity.coindays_destroyed.height,

View File

@@ -1,13 +1,15 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Dollars, Height, Indexes, Sats, StoredF32, Version};
use brk_types::{
Bitcoin, Dollars, Height, Indexes, Sats, SatsSigned, StoredF32, StoredI64, StoredU64, Version,
};
use vecdb::AnyStoredVec;
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{blocks, prices};
use crate::internal::ComputedFromHeight;
use crate::internal::{ComputedFromHeight, RollingDeltaExcept1m};
use crate::distribution::metrics::{
ActivityFull, CohortMetricsBase, CostBasisWithExtended, ImportConfig, OutputsMetrics,
@@ -29,6 +31,9 @@ pub struct ExtendedCohortMetrics<M: StorageMode = Rw> {
pub relative: Box<RelativeWithExtended<M>>,
pub dormancy: ComputedFromHeight<StoredF32, M>,
pub velocity: ComputedFromHeight<StoredF32, M>,
pub supply_delta_extended: RollingDeltaExcept1m<Sats, SatsSigned, M>,
pub utxo_count_delta_extended: RollingDeltaExcept1m<StoredU64, StoredI64, M>,
}
impl CohortMetricsBase for ExtendedCohortMetrics {
@@ -72,6 +77,8 @@ impl ExtendedCohortMetrics {
relative: Box::new(relative),
dormancy: cfg.import("dormancy", Version::ONE)?,
velocity: cfg.import("velocity", Version::ONE)?,
supply_delta_extended: cfg.import("supply_delta", Version::ONE)?,
utxo_count_delta_extended: cfg.import("utxo_count_delta", Version::ONE)?,
})
}
@@ -103,6 +110,20 @@ impl ExtendedCohortMetrics {
exit,
)?;
let window_starts = blocks.count.window_starts();
self.supply_delta_extended.compute(
starting_indexes.height,
&window_starts,
&self.supply.total.sats.height,
exit,
)?;
self.utxo_count_delta_extended.compute(
starting_indexes.height,
&window_starts,
&self.outputs.utxo_count.height,
exit,
)?;
self.dormancy.height.compute_transform2(
starting_indexes.height,
&self.activity.coindays_destroyed.height,

View File

@@ -11,9 +11,9 @@ use crate::{
internal::{
CentsType, ComputedFromHeight, ComputedFromHeightCumulative,
ComputedFromHeightCumulativeSum, ComputedFromHeightRatio, FiatFromHeight, NumericValue,
PercentFromHeight, PercentRollingWindows, Price,
PercentFromHeight, PercentRollingWindows, Price, RollingDelta1m, RollingDeltaExcept1m,
RollingWindow24h, RollingWindows, RollingWindowsFrom1w,
ValueFromHeight, ValueFromHeightChange, ValueFromHeightCumulative,
ValueFromHeight, ValueFromHeightCumulative,
},
};
@@ -39,7 +39,6 @@ macro_rules! impl_config_import {
impl_config_import!(
ValueFromHeight,
ValueFromHeightCumulative,
ValueFromHeightChange,
ComputedFromHeightRatio,
PercentFromHeight<BasisPoints16>,
PercentFromHeight<BasisPoints32>,
@@ -84,6 +83,19 @@ impl<C: CentsType> ConfigImport for FiatFromHeight<C> {
Self::forced_import(cfg.db, &cfg.name(suffix), cfg.version + offset, cfg.indexes)
}
}
impl<S: NumericValue + JsonSchema, C: NumericValue + JsonSchema> ConfigImport for RollingDelta1m<S, C>
{
fn config_import(cfg: &ImportConfig, suffix: &str, offset: Version) -> Result<Self> {
Self::forced_import(cfg.db, &cfg.name(suffix), cfg.version + offset, cfg.indexes)
}
}
impl<S: NumericValue + JsonSchema, C: NumericValue + JsonSchema> ConfigImport
for RollingDeltaExcept1m<S, C>
{
fn config_import(cfg: &ImportConfig, suffix: &str, offset: Version) -> Result<Self> {
Self::forced_import(cfg.db, &cfg.name(suffix), cfg.version + offset, cfg.indexes)
}
}
impl<T: BytesVecValue> ConfigImport for BytesVec<Height, T> {
fn config_import(cfg: &ImportConfig, suffix: &str, offset: Version) -> Result<Self> {
Ok(Self::forced_import(

View File

@@ -1,9 +1,9 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, StoredF64, StoredU64, Version};
use brk_types::{Height, Indexes, StoredI64, StoredU64, Version};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::{blocks, internal::ComputedFromHeight};
use crate::{blocks, internal::{ComputedFromHeight, RollingDelta1m}};
use super::ImportConfig;
@@ -11,7 +11,7 @@ use super::ImportConfig;
#[derive(Traversable)]
pub struct OutputsMetrics<M: StorageMode = Rw> {
pub utxo_count: ComputedFromHeight<StoredU64, M>,
pub utxo_count_change_1m: ComputedFromHeight<StoredF64, M>,
pub utxo_count_delta: RollingDelta1m<StoredU64, StoredI64, M>,
}
impl OutputsMetrics {
@@ -19,7 +19,7 @@ impl OutputsMetrics {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
utxo_count: cfg.import("utxo_count", Version::ZERO)?,
utxo_count_change_1m: cfg.import("utxo_count_change_1m", Version::ZERO)?,
utxo_count_delta: cfg.import("utxo_count_delta", Version::ONE)?,
})
}
@@ -65,7 +65,7 @@ impl OutputsMetrics {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.utxo_count_change_1m.height.compute_rolling_change(
self.utxo_count_delta.compute(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.utxo_count.height,

View File

@@ -11,7 +11,7 @@ use crate::{
distribution::state::RealizedOps,
internal::{
ComputedFromHeight, ComputedFromHeightCumulative, LazyFromHeight,
NegCentsUnsignedToDollars, RatioCents64, RollingWindow24h,
NegCentsUnsignedToDollars, RatioCents64, RollingDelta1m, RollingWindow24h,
},
prices,
};
@@ -27,7 +27,7 @@ pub struct RealizedCore<M: StorageMode = Rw> {
#[traversable(flatten)]
pub minimal: RealizedMinimal<M>,
pub realized_cap_change_1m: ComputedFromHeight<CentsSigned, M>,
pub realized_cap_delta: RollingDelta1m<Cents, CentsSigned, M>,
pub neg_realized_loss: LazyFromHeight<Dollars, Cents>,
pub net_realized_pnl: ComputedFromHeightCumulative<CentsSigned, M>,
@@ -63,7 +63,7 @@ impl RealizedCore {
Ok(Self {
minimal,
realized_cap_change_1m: cfg.import("realized_cap_change_1m", v0)?,
realized_cap_delta: cfg.import("realized_cap_delta", v1)?,
neg_realized_loss,
net_realized_pnl,
value_created,
@@ -154,7 +154,7 @@ impl RealizedCore {
self.minimal
.compute_rest_part2(prices, starting_indexes, height_to_supply, exit)?;
self.realized_cap_change_1m.height.compute_rolling_change(
self.realized_cap_delta.compute(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.minimal.realized_cap_cents.height,

View File

@@ -19,7 +19,7 @@ use crate::{
ComputedFromHeightRatioStdDevBands, LazyFromHeight, PercentFromHeight,
PercentRollingWindows, Price, RatioCents64, RatioCentsBp32,
RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32, RatioDollarsBp32,
RollingWindows, RollingWindowsFrom1w,
RollingDelta1m, RollingDeltaExcept1m, RollingWindows, RollingWindowsFrom1w,
},
prices,
};
@@ -56,10 +56,13 @@ pub struct RealizedFull<M: StorageMode = Rw> {
pub gross_pnl_sum: RollingWindows<Cents, M>,
pub net_pnl_change_1m: ComputedFromHeight<CentsSigned, M>,
pub net_pnl_delta: RollingDelta1m<CentsSigned, CentsSigned, M>,
pub net_pnl_delta_extended: RollingDeltaExcept1m<CentsSigned, 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 realized_cap_delta_extended: RollingDeltaExcept1m<Cents, CentsSigned, M>,
pub investor_price: Price<ComputedFromHeight<Cents, M>>,
pub investor_price_ratio: ComputedFromHeightRatio<M>,
@@ -176,11 +179,13 @@ impl RealizedFull {
capitulation_flow,
profit_flow,
gross_pnl_sum,
net_pnl_change_1m: cfg.import("net_pnl_change_1m", Version::new(3))?,
net_pnl_delta: cfg.import("net_pnl_delta", Version::new(5))?,
net_pnl_delta_extended: cfg.import("net_pnl_delta", Version::new(5))?,
net_pnl_change_1m_rel_to_realized_cap: cfg
.import("net_pnl_change_1m_rel_to_realized_cap", Version::new(4))?,
net_pnl_change_1m_rel_to_market_cap: cfg
.import("net_pnl_change_1m_rel_to_market_cap", Version::new(4))?,
realized_cap_delta_extended: cfg.import("realized_cap_delta", Version::new(5))?,
investor_price,
investor_price_ratio,
lower_price_band,
@@ -425,28 +430,42 @@ impl RealizedFull {
exit,
)?;
// Net PnL change 1m
self.net_pnl_change_1m.height.compute_rolling_change(
// Net PnL delta (1m base + 24h/1w/1y extended)
self.net_pnl_delta.compute(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.base.core.net_realized_pnl.cumulative.height,
exit,
)?;
self.net_pnl_delta_extended.compute(
starting_indexes.height,
&window_starts,
&self.base.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.net_pnl_delta.change_1m.height,
&self.base.core.minimal.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,
&self.net_pnl_delta.change_1m.height,
height_to_market_cap,
exit,
)?;
// Realized cap delta extended (24h/1w/1y — 1m is in RealizedCore)
self.realized_cap_delta_extended.compute(
starting_indexes.height,
&window_starts,
&self.base.core.minimal.realized_cap_cents.height,
exit,
)?;
// Peak regret
self.peak_regret_rel_to_realized_cap
.compute_binary::<Cents, Cents, RatioCentsBp32>(

View File

@@ -1,13 +1,13 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, Sats, Version};
use brk_types::{Height, Indexes, Sats, SatsSigned, Version};
use crate::{blocks, prices};
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::internal::{
HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin, LazyValueFromHeight, ValueFromHeight,
ValueFromHeightChange,
HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin, LazyValueFromHeight,
RollingDelta1m, ValueFromHeight,
};
use super::ImportConfig;
@@ -17,8 +17,7 @@ use super::ImportConfig;
pub struct SupplyMetrics<M: StorageMode = Rw> {
pub total: ValueFromHeight<M>,
pub halved: LazyValueFromHeight,
/// 1-month change in supply (net position change) - sats, btc, usd
pub change_1m: ValueFromHeightChange<M>,
pub delta: RollingDelta1m<Sats, SatsSigned, M>,
}
impl SupplyMetrics {
@@ -33,12 +32,12 @@ impl SupplyMetrics {
HalveDollars,
>(&cfg.name("supply_halved"), &supply, cfg.version);
let change_1m = cfg.import("supply_change_1m", Version::ZERO)?;
let delta = cfg.import("supply_delta", Version::ONE)?;
Ok(Self {
total: supply,
halved: supply_halved,
change_1m,
delta,
})
}
@@ -101,11 +100,10 @@ impl SupplyMetrics {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.change_1m.compute_rolling(
self.delta.compute(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.total.sats.height,
&self.total.cents.height,
exit,
)
}