global: snapshot

This commit is contained in:
nym21
2026-03-19 19:28:59 +01:00
parent 45de61b438
commit 2ce6a7cee2
11 changed files with 123 additions and 209 deletions

View File

@@ -107,15 +107,6 @@ impl ActivityCore {
.compute_rest_part1(prices, starting_indexes, exit)?;
self.coindays_destroyed
.compute_rest(starting_indexes.height, exit)?;
Ok(())
}
pub(crate) fn compute_sent_profitability(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.transfer_volume_in_profit
.compute_rest(starting_indexes.height, prices, exit)?;
self.transfer_volume_in_loss

View File

@@ -89,14 +89,8 @@ impl ActivityFull {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.inner.compute_rest_part1(prices, starting_indexes, exit)
}
self.inner.compute_rest_part1(prices, starting_indexes, exit)?;
pub(crate) fn compute_rest_part2(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
for ((dormancy, cdd_sum), tv_sum) in self
.dormancy
.as_mut_array()

View File

@@ -11,7 +11,7 @@ use crate::{
blocks,
distribution::metrics::{
ActivityFull, AdjustedSopr, CohortMetricsBase, CostBasis, ImportConfig, OutputsBase,
RealizedFull, RelativeForAll, SupplyCore, UnrealizedFull,
RealizedFull, RelativeForAll, SupplyCore, UnrealizedFull, UnrealizedLike,
},
prices,
};
@@ -144,11 +144,6 @@ impl AllCohortMetrics {
exit,
)?;
self.activity.compute_rest_part2(
starting_indexes,
exit,
)?;
Ok(())
}
}

View File

@@ -110,8 +110,6 @@ impl CoreCohortMetrics {
self.activity
.compute_rest_part1(prices, starting_indexes, exit)?;
self.activity
.compute_sent_profitability(prices, starting_indexes, exit)?;
self.realized
.compute_rest_part1(starting_indexes, exit)?;

View File

@@ -11,7 +11,7 @@ use crate::{
blocks,
distribution::metrics::{
ActivityFull, CohortMetricsBase, CostBasis, ImportConfig, OutputsBase, RealizedFull,
RelativeWithExtended, SupplyCore, UnrealizedFull,
RelativeWithExtended, SupplyCore, UnrealizedFull, UnrealizedLike,
},
prices,
};
@@ -124,11 +124,6 @@ impl ExtendedCohortMetrics {
exit,
)?;
self.activity.compute_rest_part2(
starting_indexes,
exit,
)?;
Ok(())
}
}

View File

@@ -32,7 +32,7 @@ impl CohortMetricsBase for ExtendedAdjustedCohortMetrics {
type RealizedVecs = RealizedFull;
type UnrealizedVecs = UnrealizedFull;
impl_cohort_accessors!();
impl_cohort_accessors_inner!();
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
self.inner.validate_computed_versions(base_version)

View File

@@ -51,6 +51,52 @@ macro_rules! impl_cohort_accessors {
fn unrealized_mut(&mut self) -> &mut Self::UnrealizedVecs {
&mut self.unrealized
}
fn supply_and_unrealized_mut(&mut self) -> (&$crate::distribution::metrics::SupplyCore, &mut Self::UnrealizedVecs) {
(&*self.supply, &mut self.unrealized)
}
};
}
/// Variant of `impl_cohort_accessors` for wrapper types that deref to an `inner` field.
/// Uses `self.inner.*` directly to enable split borrows that Rust cannot infer through `Deref`.
macro_rules! impl_cohort_accessors_inner {
() => {
fn filter(&self) -> &brk_cohort::Filter {
&self.inner.filter
}
fn supply(&self) -> &$crate::distribution::metrics::SupplyCore {
&self.inner.supply
}
fn supply_mut(&mut self) -> &mut $crate::distribution::metrics::SupplyCore {
&mut self.inner.supply
}
fn outputs(&self) -> &$crate::distribution::metrics::OutputsBase {
&self.inner.outputs
}
fn outputs_mut(&mut self) -> &mut $crate::distribution::metrics::OutputsBase {
&mut self.inner.outputs
}
fn activity(&self) -> &Self::ActivityVecs {
&self.inner.activity
}
fn activity_mut(&mut self) -> &mut Self::ActivityVecs {
&mut self.inner.activity
}
fn realized(&self) -> &Self::RealizedVecs {
&self.inner.realized
}
fn realized_mut(&mut self) -> &mut Self::RealizedVecs {
&mut self.inner.realized
}
fn unrealized(&self) -> &Self::UnrealizedVecs {
&self.inner.unrealized
}
fn unrealized_mut(&mut self) -> &mut Self::UnrealizedVecs {
&mut self.inner.unrealized
}
fn supply_and_unrealized_mut(&mut self) -> (&$crate::distribution::metrics::SupplyCore, &mut Self::UnrealizedVecs) {
(&*self.inner.supply, &mut self.inner.unrealized)
}
};
}
@@ -148,6 +194,7 @@ pub trait CohortMetricsBase:
fn realized_mut(&mut self) -> &mut Self::RealizedVecs;
fn unrealized(&self) -> &Self::UnrealizedVecs;
fn unrealized_mut(&mut self) -> &mut Self::UnrealizedVecs;
fn supply_and_unrealized_mut(&mut self) -> (&SupplyCore, &mut Self::UnrealizedVecs);
/// Convenience: access activity as `&ActivityCore` (via `ActivityLike::as_core`).
fn activity_core(&self) -> &ActivityCore {
@@ -224,17 +271,18 @@ pub trait CohortMetricsBase:
.compute(prices, starting_indexes.height, exit)?;
self.activity_mut()
.compute_rest_part1(prices, starting_indexes, exit)?;
self.activity_core_mut()
.compute_sent_profitability(prices, starting_indexes, exit)?;
self.realized_mut()
.compute_rest_part1(starting_indexes, exit)?;
self.unrealized_mut()
.compute_rest(prices, starting_indexes, exit)?;
self.unrealized_mut()
.compute_net_sentiment_height(starting_indexes, exit)?;
let (supply, unrealized) = self.supply_and_unrealized_mut();
unrealized.compute_rest(
prices,
starting_indexes,
&supply.in_profit.sats.height,
&supply.in_loss.sats.height,
exit,
)?;
Ok(())
}

View File

@@ -1,6 +1,6 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{CentsSats, CentsSquaredSats, Height, Indexes, Version};
use brk_types::{CentsSquaredSats, Height, Indexes, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
@@ -15,10 +15,6 @@ pub struct UnrealizedBase<M: StorageMode = Rw> {
#[traversable(flatten)]
pub core: UnrealizedCore<M>,
#[traversable(hidden)]
pub invested_capital_in_profit_raw: M::Stored<BytesVec<Height, CentsSats>>,
#[traversable(hidden)]
pub invested_capital_in_loss_raw: M::Stored<BytesVec<Height, CentsSats>>,
#[traversable(hidden)]
pub investor_cap_in_profit_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
#[traversable(hidden)]
@@ -31,16 +27,11 @@ impl UnrealizedBase {
let core = UnrealizedCore::forced_import(cfg)?;
let invested_capital_in_profit_raw =
cfg.import("invested_capital_in_profit_raw", v0)?;
let invested_capital_in_loss_raw = cfg.import("invested_capital_in_loss_raw", v0)?;
let investor_cap_in_profit_raw = cfg.import("investor_cap_in_profit_raw", v0)?;
let investor_cap_in_loss_raw = cfg.import("investor_cap_in_loss_raw", v0)?;
Ok(Self {
core,
invested_capital_in_profit_raw,
invested_capital_in_loss_raw,
investor_cap_in_profit_raw,
investor_cap_in_loss_raw,
})
@@ -49,8 +40,6 @@ impl UnrealizedBase {
pub(crate) fn min_stateful_len(&self) -> usize {
self.core
.min_stateful_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())
}
@@ -59,10 +48,6 @@ impl UnrealizedBase {
pub(crate) fn push_state(&mut self, state: &UnrealizedState) {
self.core.push_state(state);
self.invested_capital_in_profit_raw
.push(CentsSats::new(state.invested_capital_in_profit_raw));
self.invested_capital_in_loss_raw
.push(CentsSats::new(state.invested_capital_in_loss_raw));
self.investor_cap_in_profit_raw
.push(CentsSquaredSats::new(state.investor_cap_in_profit_raw));
self.investor_cap_in_loss_raw
@@ -71,8 +56,6 @@ impl UnrealizedBase {
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.core.collect_vecs_mut();
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
@@ -90,28 +73,15 @@ impl UnrealizedBase {
.compute_from_stateful(starting_indexes, &core_refs, exit)?;
let start = self
.invested_capital_in_profit_raw
.investor_cap_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())
.map(|o| o.investor_cap_in_profit_raw.len())
.min()
.unwrap_or(0);
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))
@@ -121,10 +91,6 @@ impl UnrealizedBase {
.map(|o| o.investor_cap_in_loss_raw.collect_range_at(start, end))
.collect();
self.invested_capital_in_profit_raw
.truncate_if_needed_at(start)?;
self.invested_capital_in_loss_raw
.truncate_if_needed_at(start)?;
self.investor_cap_in_profit_raw
.truncate_if_needed_at(start)?;
self.investor_cap_in_loss_raw
@@ -133,22 +99,14 @@ impl UnrealizedBase {
for i in start..end {
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
.push(sum_invested_profit);
self.invested_capital_in_loss_raw
.push(sum_invested_loss);
self.investor_cap_in_profit_raw
.push(sum_investor_profit);
self.investor_cap_in_loss_raw

View File

@@ -1,8 +1,8 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, CentsSats, CentsSigned, Indexes, Version};
use brk_types::{Cents, CentsSigned, Height, Indexes, Sats, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, Exit, Rw, StorageMode, WritableVec};
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::state::UnrealizedState;
use crate::internal::{CentsSubtractToCentsSigned, FiatPerBlock};
@@ -26,11 +26,6 @@ pub struct UnrealizedFull<M: StorageMode = Rw> {
pub gross_pnl: FiatPerBlock<Cents, M>,
#[traversable(wrap = "invested_capital", rename = "in_profit")]
pub invested_capital_in_profit: FiatPerBlock<Cents, M>,
#[traversable(wrap = "invested_capital", rename = "in_loss")]
pub invested_capital_in_loss: FiatPerBlock<Cents, M>,
pub sentiment: UnrealizedSentiment<M>,
}
@@ -40,8 +35,6 @@ impl UnrealizedFull {
let inner = UnrealizedBase::forced_import(cfg)?;
let gross_pnl = cfg.import("unrealized_gross_pnl", v0)?;
let invested_capital_in_profit = cfg.import("invested_capital_in_profit", v0)?;
let invested_capital_in_loss = cfg.import("invested_capital_in_loss", v0)?;
let sentiment = UnrealizedSentiment {
pain_index: cfg.import("pain_index", v0)?,
@@ -52,8 +45,6 @@ impl UnrealizedFull {
Ok(Self {
inner,
gross_pnl,
invested_capital_in_profit,
invested_capital_in_loss,
sentiment,
})
}
@@ -61,21 +52,11 @@ impl UnrealizedFull {
#[inline(always)]
pub(crate) fn push_state_all(&mut self, state: &UnrealizedState) {
self.inner.push_state(state);
self.invested_capital_in_profit
.cents
.height
.push(state.invested_capital_in_profit);
self.invested_capital_in_loss
.cents
.height
.push(state.invested_capital_in_loss);
}
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
let mut vecs = self.inner.collect_vecs_mut();
vecs.push(&mut self.gross_pnl.cents.height as &mut dyn AnyStoredVec);
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.sentiment.pain_index.cents.height as &mut dyn AnyStoredVec);
vecs.push(&mut self.sentiment.greed_index.cents.height as &mut dyn AnyStoredVec);
vecs.push(&mut self.sentiment.net.cents.height as &mut dyn AnyStoredVec);
@@ -86,6 +67,8 @@ impl UnrealizedFull {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
exit: &Exit,
) -> Result<()> {
self.inner.compute_rest(starting_indexes, exit)?;
@@ -97,76 +80,8 @@ impl UnrealizedFull {
exit,
)?;
self.invested_capital_in_profit
.cents
.height
.compute_transform(
starting_indexes.height,
&self.inner.invested_capital_in_profit_raw,
|(h, raw, ..)| (h, CentsSats::to_cents(raw)),
exit,
)?;
self.compute_rest_extended(prices, starting_indexes, supply_in_profit_sats, supply_in_loss_sats, exit)?;
self.invested_capital_in_loss
.cents
.height
.compute_transform(
starting_indexes.height,
&self.inner.invested_capital_in_loss_raw,
|(h, raw, ..)| (h, CentsSats::to_cents(raw)),
exit,
)?;
self.compute_rest_extended(prices, starting_indexes, exit)?;
Ok(())
}
fn compute_rest_extended(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.sentiment.pain_index.cents.height.compute_transform3(
starting_indexes.height,
&self.inner.investor_cap_in_loss_raw,
&self.inner.invested_capital_in_loss_raw,
&prices.spot.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,
)?;
self.sentiment.greed_index.cents.height.compute_transform3(
starting_indexes.height,
&self.inner.investor_cap_in_profit_raw,
&self.inner.invested_capital_in_profit_raw,
&prices.spot.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(())
}
pub(crate) fn compute_net_sentiment_height(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.sentiment
.net
.cents
@@ -177,6 +92,53 @@ impl UnrealizedFull {
&self.sentiment.pain_index.cents.height,
exit,
)?;
Ok(())
}
fn compute_rest_extended(
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
exit: &Exit,
) -> Result<()> {
self.sentiment.greed_index.cents.height.compute_transform3(
starting_indexes.height,
&self.inner.investor_cap_in_profit_raw,
supply_in_profit_sats,
&prices.spot.cents.height,
|(h, investor_cap, supply_sats, spot, ..)| {
let invested_cap = supply_sats.as_u128() * spot.as_u128();
if invested_cap == 0 {
return (h, Cents::ZERO);
}
let investor_price = investor_cap.inner() / invested_cap;
let spot_u128 = spot.as_u128();
(h, Cents::new((spot_u128 - investor_price) as u64))
},
exit,
)?;
self.sentiment.pain_index.cents.height.compute_transform3(
starting_indexes.height,
&self.inner.investor_cap_in_loss_raw,
supply_in_loss_sats,
&prices.spot.cents.height,
|(h, investor_cap, supply_sats, spot, ..)| {
let invested_cap = supply_sats.as_u128() * spot.as_u128();
if invested_cap == 0 {
return (h, Cents::ZERO);
}
let investor_price = investor_cap.inner() / invested_cap;
let spot_u128 = spot.as_u128();
(h, Cents::new((investor_price - spot_u128) as u64))
},
exit,
)?;
Ok(())
}
}

View File

@@ -11,8 +11,8 @@ pub use full::UnrealizedFull;
pub use minimal::UnrealizedMinimal;
use brk_error::Result;
use brk_types::Indexes;
use vecdb::Exit;
use brk_types::{Height, Indexes, Sats};
use vecdb::{Exit, ReadableVec};
use crate::{distribution::state::UnrealizedState, prices};
@@ -25,11 +25,8 @@ pub trait UnrealizedLike: Send + Sync {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()>;
fn compute_net_sentiment_height(
&mut self,
starting_indexes: &Indexes,
supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
exit: &Exit,
) -> Result<()>;
}
@@ -52,17 +49,12 @@ impl UnrealizedLike for UnrealizedBase {
&mut self,
_prices: &prices::Vecs,
starting_indexes: &Indexes,
_supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
_supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
exit: &Exit,
) -> Result<()> {
self.compute_rest(starting_indexes, exit)
}
fn compute_net_sentiment_height(
&mut self,
_starting_indexes: &Indexes,
_exit: &Exit,
) -> Result<()> {
Ok(())
}
}
impl UnrealizedLike for UnrealizedFull {
@@ -83,15 +75,10 @@ impl UnrealizedLike for UnrealizedFull {
&mut self,
prices: &prices::Vecs,
starting_indexes: &Indexes,
supply_in_profit_sats: &(impl ReadableVec<Height, Sats> + Sync),
supply_in_loss_sats: &(impl ReadableVec<Height, Sats> + Sync),
exit: &Exit,
) -> Result<()> {
self.compute_rest_all(prices, starting_indexes, exit)
}
fn compute_net_sentiment_height(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.compute_net_sentiment_height(starting_indexes, exit)
self.compute_rest_all(prices, starting_indexes, supply_in_profit_sats, supply_in_loss_sats, exit)
}
}

View File

@@ -10,16 +10,10 @@ pub struct UnrealizedState {
pub supply_in_loss: Sats,
pub unrealized_profit: Cents,
pub unrealized_loss: Cents,
pub invested_capital_in_profit: Cents,
pub invested_capital_in_loss: Cents,
/// Raw Σ(price² × sats) for UTXOs in profit. Used for aggregation.
pub investor_cap_in_profit_raw: u128,
/// Raw Σ(price² × sats) for UTXOs in loss. Used for aggregation.
pub investor_cap_in_loss_raw: u128,
/// Raw Σ(price × sats) for UTXOs in profit. Used for aggregation.
pub invested_capital_in_profit_raw: u128,
/// Raw Σ(price × sats) for UTXOs in loss. Used for aggregation.
pub invested_capital_in_loss_raw: u128,
}
impl UnrealizedState {
@@ -28,12 +22,8 @@ impl UnrealizedState {
supply_in_loss: Sats::ZERO,
unrealized_profit: Cents::ZERO,
unrealized_loss: Cents::ZERO,
invested_capital_in_profit: Cents::ZERO,
invested_capital_in_loss: Cents::ZERO,
investor_cap_in_profit_raw: 0,
investor_cap_in_loss_raw: 0,
invested_capital_in_profit_raw: 0,
invested_capital_in_loss_raw: 0,
};
}
@@ -118,12 +108,8 @@ impl Accumulate for WithoutCapital {
impl Accumulate for WithCapital {
fn to_output(&self) -> UnrealizedState {
UnrealizedState {
invested_capital_in_profit: div_btc(self.invested_capital_in_profit),
invested_capital_in_loss: div_btc(self.invested_capital_in_loss),
investor_cap_in_profit_raw: self.investor_cap_in_profit,
investor_cap_in_loss_raw: self.investor_cap_in_loss,
invested_capital_in_profit_raw: self.invested_capital_in_profit,
invested_capital_in_loss_raw: self.invested_capital_in_loss,
..Accumulate::to_output(&self.core)
}
}