mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-09 18:18:14 -07:00
336 lines
11 KiB
Rust
336 lines
11 KiB
Rust
/// Aggregate a field by summing the same field across `others`.
|
|
macro_rules! sum_others {
|
|
($self_:ident, $si:ident, $others:ident, $exit:ident; $($field:tt).+) => {
|
|
$self_.$($field).+.compute_sum_of_others(
|
|
$si.height,
|
|
&$others.iter().map(|v| &v.$($field).+).collect::<Vec<_>>(),
|
|
$exit,
|
|
)?
|
|
};
|
|
}
|
|
|
|
mod activity;
|
|
|
|
/// Accessor methods for `CohortMetricsBase` implementations.
|
|
///
|
|
/// All cohort metric types share the same field names (`filter`, `supply`, `outputs`,
|
|
/// `activity`, `realized`, `unrealized`). For wrapper types like
|
|
/// `ExtendedAdjustedCohortMetrics`, Rust's auto-deref resolves these through `Deref`.
|
|
macro_rules! impl_cohort_accessors {
|
|
() => {
|
|
fn filter(&self) -> &brk_cohort::Filter {
|
|
&self.filter
|
|
}
|
|
fn supply(&self) -> &$crate::distribution::metrics::SupplyCore {
|
|
&self.supply
|
|
}
|
|
fn supply_mut(&mut self) -> &mut $crate::distribution::metrics::SupplyCore {
|
|
&mut self.supply
|
|
}
|
|
fn outputs(&self) -> &$crate::distribution::metrics::OutputsBase {
|
|
&self.outputs
|
|
}
|
|
fn outputs_mut(&mut self) -> &mut $crate::distribution::metrics::OutputsBase {
|
|
&mut self.outputs
|
|
}
|
|
fn activity(&self) -> &Self::ActivityVecs {
|
|
&self.activity
|
|
}
|
|
fn activity_mut(&mut self) -> &mut Self::ActivityVecs {
|
|
&mut self.activity
|
|
}
|
|
fn realized(&self) -> &Self::RealizedVecs {
|
|
&self.realized
|
|
}
|
|
fn realized_mut(&mut self) -> &mut Self::RealizedVecs {
|
|
&mut self.realized
|
|
}
|
|
fn unrealized(&self) -> &Self::UnrealizedVecs {
|
|
&self.unrealized
|
|
}
|
|
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)
|
|
}
|
|
};
|
|
}
|
|
|
|
mod cohort;
|
|
mod config;
|
|
mod cost_basis;
|
|
mod outputs;
|
|
mod profitability;
|
|
mod realized;
|
|
mod relative;
|
|
mod supply;
|
|
mod unrealized;
|
|
|
|
pub use activity::{ActivityCore, ActivityFull, ActivityLike, ActivityMinimal};
|
|
pub use cohort::{
|
|
AllCohortMetrics, BasicCohortMetrics, CoreCohortMetrics, ExtendedAdjustedCohortMetrics,
|
|
ExtendedCohortMetrics, MinimalCohortMetrics, TypeCohortMetrics,
|
|
};
|
|
pub use config::ImportConfig;
|
|
pub use cost_basis::CostBasis;
|
|
pub use outputs::OutputsBase;
|
|
pub use profitability::ProfitabilityMetrics;
|
|
pub use realized::{
|
|
AdjustedSopr, RealizedCore, RealizedFull, RealizedFullAccum, RealizedLike, RealizedMinimal,
|
|
};
|
|
pub use relative::{RelativeForAll, RelativeToAll, RelativeWithExtended};
|
|
pub use supply::{SupplyBase, SupplyCore};
|
|
pub use unrealized::{
|
|
UnrealizedBasic, UnrealizedCore, UnrealizedFull, UnrealizedLike, UnrealizedMinimal,
|
|
};
|
|
|
|
use brk_cohort::Filter;
|
|
use brk_error::Result;
|
|
use brk_types::{Cents, Indexes, Version};
|
|
use vecdb::{AnyStoredVec, Exit, StorageMode};
|
|
|
|
use crate::{
|
|
distribution::state::{
|
|
CohortState, CoreRealizedState, CostBasisData, CostBasisOps, CostBasisRaw,
|
|
MinimalRealizedState, RealizedOps, RealizedState, WithCapital, WithoutCapital,
|
|
},
|
|
prices,
|
|
};
|
|
|
|
pub trait CohortMetricsState {
|
|
type Realized: RealizedOps;
|
|
type CostBasis: CostBasisOps;
|
|
}
|
|
|
|
impl<M: StorageMode> CohortMetricsState for TypeCohortMetrics<M> {
|
|
type Realized = MinimalRealizedState;
|
|
type CostBasis = CostBasisData<WithoutCapital>;
|
|
}
|
|
impl<M: StorageMode> CohortMetricsState for MinimalCohortMetrics<M> {
|
|
type Realized = MinimalRealizedState;
|
|
type CostBasis = CostBasisRaw;
|
|
}
|
|
impl<M: StorageMode> CohortMetricsState for CoreCohortMetrics<M> {
|
|
type Realized = CoreRealizedState;
|
|
type CostBasis = CostBasisData<WithoutCapital>;
|
|
}
|
|
impl<M: StorageMode> CohortMetricsState for BasicCohortMetrics<M> {
|
|
type Realized = RealizedState;
|
|
type CostBasis = CostBasisData<WithCapital>;
|
|
}
|
|
impl<M: StorageMode> CohortMetricsState for ExtendedCohortMetrics<M> {
|
|
type Realized = RealizedState;
|
|
type CostBasis = CostBasisData<WithCapital>;
|
|
}
|
|
impl<M: StorageMode> CohortMetricsState for ExtendedAdjustedCohortMetrics<M> {
|
|
type Realized = RealizedState;
|
|
type CostBasis = CostBasisData<WithCapital>;
|
|
}
|
|
impl<M: StorageMode> CohortMetricsState for AllCohortMetrics<M> {
|
|
type Realized = RealizedState;
|
|
type CostBasis = CostBasisData<WithCapital>;
|
|
}
|
|
|
|
pub trait CohortMetricsBase:
|
|
CohortMetricsState<Realized = RealizedState, CostBasis = CostBasisData<WithCapital>> + Send + Sync
|
|
{
|
|
type ActivityVecs: ActivityLike;
|
|
type RealizedVecs: RealizedLike;
|
|
type UnrealizedVecs: UnrealizedLike;
|
|
|
|
fn filter(&self) -> &Filter;
|
|
fn supply(&self) -> &SupplyCore;
|
|
fn supply_mut(&mut self) -> &mut SupplyCore;
|
|
fn outputs(&self) -> &OutputsBase;
|
|
fn outputs_mut(&mut self) -> &mut OutputsBase;
|
|
fn activity(&self) -> &Self::ActivityVecs;
|
|
fn activity_mut(&mut self) -> &mut Self::ActivityVecs;
|
|
fn realized(&self) -> &Self::RealizedVecs;
|
|
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 {
|
|
self.activity().as_core()
|
|
}
|
|
fn activity_core_mut(&mut self) -> &mut ActivityCore {
|
|
self.activity_mut().as_core_mut()
|
|
}
|
|
|
|
/// Convenience: access realized as `&RealizedCore` (via `RealizedLike::as_core`).
|
|
fn realized_core(&self) -> &RealizedCore {
|
|
self.realized().as_core()
|
|
}
|
|
fn realized_core_mut(&mut self) -> &mut RealizedCore {
|
|
self.realized_mut().as_core_mut()
|
|
}
|
|
|
|
/// Convenience: access unrealized as `&UnrealizedCore` (via `UnrealizedLike::as_core`).
|
|
fn unrealized_core(&self) -> &UnrealizedCore {
|
|
self.unrealized().as_core()
|
|
}
|
|
fn unrealized_core_mut(&mut self) -> &mut UnrealizedCore {
|
|
self.unrealized_mut().as_core_mut()
|
|
}
|
|
|
|
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
|
|
self.supply_mut().validate_computed_versions(base_version)?;
|
|
self.activity_mut()
|
|
.validate_computed_versions(base_version)?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Apply pending state, compute and push unrealized state.
|
|
fn compute_and_push_unrealized(
|
|
&mut self,
|
|
height_price: Cents,
|
|
state: &mut CohortState<RealizedState, CostBasisData<WithCapital>>,
|
|
) {
|
|
state.apply_pending();
|
|
let unrealized_state = state.compute_unrealized_state(height_price);
|
|
self.unrealized_mut().push_state(&unrealized_state);
|
|
self.supply_mut().push_profitability(&unrealized_state);
|
|
}
|
|
|
|
fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec>;
|
|
|
|
fn min_stateful_len(&self) -> usize {
|
|
self.supply()
|
|
.min_len()
|
|
.min(self.outputs().min_len())
|
|
.min(self.activity().min_len())
|
|
.min(self.realized().min_stateful_len())
|
|
.min(self.unrealized().min_stateful_len())
|
|
}
|
|
|
|
fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) {
|
|
self.supply_mut().push_state(state);
|
|
self.outputs_mut().push_state(state);
|
|
self.activity_mut().push_state(state);
|
|
self.realized_mut().push_state(state);
|
|
}
|
|
|
|
/// First phase of computed metrics (indexes from height).
|
|
fn compute_rest_part1(
|
|
&mut self,
|
|
prices: &prices::Vecs,
|
|
starting_indexes: &Indexes,
|
|
exit: &Exit,
|
|
) -> Result<()> {
|
|
self.supply_mut()
|
|
.compute(prices, starting_indexes.height, exit)?;
|
|
self.outputs_mut()
|
|
.compute_rest(starting_indexes.height, exit)?;
|
|
self.activity_mut()
|
|
.compute_rest_part1(prices, starting_indexes, exit)?;
|
|
|
|
self.realized_mut()
|
|
.compute_rest_part1(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(())
|
|
}
|
|
|
|
/// Compute aggregate base metrics from source cohorts.
|
|
fn compute_base_from_others<T: CohortMetricsBase>(
|
|
&mut self,
|
|
starting_indexes: &Indexes,
|
|
others: &[&T],
|
|
exit: &Exit,
|
|
) -> Result<()> {
|
|
self.supply_mut().compute_from_stateful(
|
|
starting_indexes,
|
|
&others.iter().map(|v| v.supply()).collect::<Vec<_>>(),
|
|
exit,
|
|
)?;
|
|
self.outputs_mut().compute_from_stateful(
|
|
starting_indexes,
|
|
&others.iter().map(|v| v.outputs()).collect::<Vec<_>>(),
|
|
exit,
|
|
)?;
|
|
self.activity_mut().compute_from_stateful(
|
|
starting_indexes,
|
|
&others.iter().map(|v| v.activity_core()).collect::<Vec<_>>(),
|
|
exit,
|
|
)?;
|
|
self.realized_mut().compute_from_stateful(
|
|
starting_indexes,
|
|
&others.iter().map(|v| v.realized_core()).collect::<Vec<_>>(),
|
|
exit,
|
|
)?;
|
|
self.unrealized_core_mut().compute_from_stateful(
|
|
starting_indexes,
|
|
&others
|
|
.iter()
|
|
.map(|v| v.unrealized_core())
|
|
.collect::<Vec<_>>(),
|
|
exit,
|
|
)?;
|
|
Ok(())
|
|
}
|
|
}
|