computer: simplified a bunch of things

This commit is contained in:
nym21
2026-02-26 19:37:22 +01:00
parent 9e4fe62de2
commit cccaf6b206
252 changed files with 3788 additions and 7279 deletions

View File

@@ -1,75 +1,113 @@
//! Growth rate: new_addr_count / addr_count (global + per-type)
use brk_cohort::{ByAddressType, zip2_by_addresstype};
use brk_cohort::ByAddressType;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, StoredF32, StoredU64, Version};
use vecdb::ReadableCloneableVec;
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode};
use crate::{
indexes,
internal::{LazyBinaryComputedFromHeightDistribution, RatioU64F32},
internal::{ComputedFromHeightDistribution, WindowStarts},
};
use super::{AddrCountsVecs, NewAddrCountVecs};
/// Growth rate by type - lazy ratio with distribution stats
pub type GrowthRateByType =
ByAddressType<LazyBinaryComputedFromHeightDistribution<StoredF32, StoredU64, StoredU64>>;
/// Growth rate: new_addr_count / addr_count (global + per-type)
#[derive(Clone, Traversable)]
pub struct GrowthRateVecs {
pub all: LazyBinaryComputedFromHeightDistribution<StoredF32, StoredU64, StoredU64>,
#[derive(Traversable)]
pub struct GrowthRateVecs<M: StorageMode = Rw> {
pub all: ComputedFromHeightDistribution<StoredF32, M>,
#[traversable(flatten)]
pub by_addresstype: GrowthRateByType,
pub by_addresstype: ByAddressType<ComputedFromHeightDistribution<StoredF32, M>>,
}
impl GrowthRateVecs {
pub(crate) fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
new_addr_count: &NewAddrCountVecs,
addr_count: &AddrCountsVecs,
) -> Result<Self> {
let all = make_growth_rate(
let all = ComputedFromHeightDistribution::forced_import(
db,
"growth_rate",
version,
indexes,
&new_addr_count.all.height,
&addr_count.all.count.height,
);
)?;
let by_addresstype: GrowthRateByType = zip2_by_addresstype(
&new_addr_count.by_addresstype,
&addr_count.by_addresstype,
|name, new, addr| {
Ok(make_growth_rate(
let by_addresstype: ByAddressType<ComputedFromHeightDistribution<StoredF32>> =
ByAddressType::new_with_name(|name| {
ComputedFromHeightDistribution::forced_import(
db,
&format!("{name}_growth_rate"),
version,
indexes,
&new.height,
&addr.count.height,
))
},
)?;
)
})?;
Ok(Self { all, by_addresstype })
}
pub(crate) fn compute(
&mut self,
max_from: Height,
windows: &WindowStarts<'_>,
new_addr_count: &NewAddrCountVecs,
addr_count: &AddrCountsVecs,
exit: &Exit,
) -> Result<()> {
self.all.compute(max_from, windows, exit, |target| {
compute_ratio(
target,
max_from,
&new_addr_count.all.height,
&addr_count.all.count.height,
exit,
)
})?;
for ((_, growth), ((_, new), (_, addr))) in self
.by_addresstype
.iter_mut()
.zip(
new_addr_count
.by_addresstype
.iter()
.zip(addr_count.by_addresstype.iter()),
)
{
growth.compute(max_from, windows, exit, |target| {
compute_ratio(
target,
max_from,
&new.height,
&addr.count.height,
exit,
)
})?;
}
Ok(())
}
}
fn make_growth_rate<V1, V2>(
name: &str,
version: Version,
indexes: &indexes::Vecs,
new: &V1,
addr: &V2,
) -> LazyBinaryComputedFromHeightDistribution<StoredF32, StoredU64, StoredU64>
where
V1: ReadableCloneableVec<Height, StoredU64>,
V2: ReadableCloneableVec<Height, StoredU64>,
{
LazyBinaryComputedFromHeightDistribution::<StoredF32, StoredU64, StoredU64>::forced_import::<
RatioU64F32,
>(name, version, new.read_only_boxed_clone(), addr.read_only_boxed_clone(), indexes)
fn compute_ratio(
target: &mut EagerVec<PcoVec<Height, StoredF32>>,
max_from: Height,
numerator: &impl ReadableVec<Height, StoredU64>,
denominator: &impl ReadableVec<Height, StoredU64>,
exit: &Exit,
) -> Result<()> {
target.compute_transform2(
max_from,
numerator,
denominator,
|(h, num, den, ..)| {
let n = *num as f64;
let d = *den as f64;
let ratio = if d == 0.0 { 0.0 } else { n / d };
(h, StoredF32::from(ratio))
},
exit,
)?;
Ok(())
}

View File

@@ -11,8 +11,8 @@ use brk_types::{
use rayon::prelude::*;
use rustc_hash::FxHashMap;
use vecdb::{
AnyStoredVec, AnyVec, BytesVec, Database, ReadableVec, WritableVec, ImportOptions, ImportableVec,
Reader, Rw, Stamp, StorageMode,
AnyStoredVec, AnyVec, BytesVec, Database, ImportOptions, ImportableVec, ReadableVec, Reader,
Rw, Stamp, StorageMode, WritableVec,
};
use super::super::AddressTypeToTypeIndexMap;

View File

@@ -1,25 +1,23 @@
//! New address count: delta of total_addr_count (global + per-type)
//! New address count: delta of total_addr_count (global + per-type)
use brk_cohort::{ByAddressType, zip_by_addresstype};
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{StoredU64, Version};
use brk_types::{Height, StoredU64, Version};
use vecdb::{Database, Exit, Ident, Rw, StorageMode};
use crate::{ComputeIndexes, indexes, internal::LazyComputedFromHeightFull};
use crate::{indexes, internal::{LazyComputedFromHeightFull, WindowStarts}};
use super::TotalAddrCountVecs;
/// New addresses by type - identity transform with stored day1 stats
/// The delta is computed at the compute step, not lazily
pub type NewAddrCountByType<M = Rw> = ByAddressType<LazyComputedFromHeightFull<StoredU64, StoredU64, M>>;
/// New address count per block (global + per-type)
#[derive(Traversable)]
pub struct NewAddrCountVecs<M: StorageMode = Rw> {
pub all: LazyComputedFromHeightFull<StoredU64, StoredU64, M>,
#[traversable(flatten)]
pub by_addresstype: NewAddrCountByType<M>,
pub by_addresstype: ByAddressType<LazyComputedFromHeightFull<StoredU64, StoredU64, M>>,
}
impl NewAddrCountVecs {
@@ -37,7 +35,7 @@ impl NewAddrCountVecs {
indexes,
)?;
let by_addresstype: NewAddrCountByType =
let by_addresstype: ByAddressType<LazyComputedFromHeightFull<StoredU64, StoredU64>> =
zip_by_addresstype(&total_addr_count.by_addresstype, |name, total| {
LazyComputedFromHeightFull::forced_import::<Ident>(
db,
@@ -54,14 +52,15 @@ impl NewAddrCountVecs {
})
}
pub(crate) fn compute_cumulative(
pub(crate) fn compute(
&mut self,
starting_indexes: &ComputeIndexes,
max_from: Height,
windows: &WindowStarts<'_>,
exit: &Exit,
) -> Result<()> {
self.all.compute_cumulative(starting_indexes, exit)?;
self.all.compute(max_from, windows, exit)?;
for vecs in self.by_addresstype.values_mut() {
vecs.compute_cumulative(starting_indexes, exit)?;
vecs.compute(max_from, windows, exit)?;
}
Ok(())
}

View File

@@ -1,57 +1,85 @@
//! Total address count: addr_count + empty_addr_count (global + per-type)
use brk_cohort::{ByAddressType, zip2_by_addresstype};
use brk_cohort::ByAddressType;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{StoredU64, Version};
use vecdb::ReadableCloneableVec;
use brk_types::{Height, StoredU64, Version};
use vecdb::{Database, Exit, Rw, StorageMode};
use crate::{indexes, internal::{LazyBinaryComputedFromHeightLast, U64Plus}};
use crate::{indexes, internal::ComputedFromHeightLast};
use super::AddrCountsVecs;
/// Total addresses by type - lazy sum with all derived indexes
pub type TotalAddrCountByType =
ByAddressType<LazyBinaryComputedFromHeightLast<StoredU64, StoredU64, StoredU64>>;
/// Total address count (global + per-type) with all derived indexes
#[derive(Clone, Traversable)]
pub struct TotalAddrCountVecs {
pub all: LazyBinaryComputedFromHeightLast<StoredU64, StoredU64, StoredU64>,
#[derive(Traversable)]
pub struct TotalAddrCountVecs<M: StorageMode = Rw> {
pub all: ComputedFromHeightLast<StoredU64, M>,
#[traversable(flatten)]
pub by_addresstype: TotalAddrCountByType,
pub by_addresstype: ByAddressType<ComputedFromHeightLast<StoredU64, M>>,
}
impl TotalAddrCountVecs {
pub(crate) fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
addr_count: &AddrCountsVecs,
empty_addr_count: &AddrCountsVecs,
) -> Result<Self> {
let all = LazyBinaryComputedFromHeightLast::forced_import::<U64Plus>(
let all = ComputedFromHeightLast::forced_import(
db,
"total_addr_count",
version,
addr_count.all.count.height.read_only_boxed_clone(),
empty_addr_count.all.count.height.read_only_boxed_clone(),
indexes,
);
)?;
let by_addresstype: TotalAddrCountByType = zip2_by_addresstype(
&addr_count.by_addresstype,
&empty_addr_count.by_addresstype,
|name, addr, empty| {
Ok(LazyBinaryComputedFromHeightLast::forced_import::<U64Plus>(
let by_addresstype: ByAddressType<ComputedFromHeightLast<StoredU64>> = ByAddressType::new_with_name(
|name| {
ComputedFromHeightLast::forced_import(
db,
&format!("{name}_total_addr_count"),
version,
addr.count.height.read_only_boxed_clone(),
empty.count.height.read_only_boxed_clone(),
indexes,
))
)
},
)?;
Ok(Self { all, by_addresstype })
}
/// Eagerly compute total = addr_count + empty_addr_count.
pub(crate) fn compute(
&mut self,
max_from: Height,
addr_count: &AddrCountsVecs,
empty_addr_count: &AddrCountsVecs,
exit: &Exit,
) -> Result<()> {
self.all.height.compute_transform2(
max_from,
&addr_count.all.count.height,
&empty_addr_count.all.count.height,
|(h, a, b, ..)| (h, StoredU64::from(*a + *b)),
exit,
)?;
for ((_, total), ((_, addr), (_, empty))) in self
.by_addresstype
.iter_mut()
.zip(
addr_count
.by_addresstype
.iter()
.zip(empty_addr_count.by_addresstype.iter()),
)
{
total.height.compute_transform2(
max_from,
&addr.count.height,
&empty.count.height,
|(h, a, b, ..)| (h, StoredU64::from(*a + *b)),
exit,
)?;
}
Ok(())
}
}

View File

@@ -1,24 +1,24 @@
use brk_cohort::ByAddressType;
use brk_error::Result;
use brk_types::{AnyAddressDataIndexEnum, FundedAddressData, OutputType, TypeIndex};
use brk_types::{
AnyAddressDataIndexEnum, EmptyAddressData, FundedAddressData, OutputType, TxIndex, TypeIndex,
};
use smallvec::SmallVec;
use crate::distribution::{
address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs},
compute::VecsReaders,
};
use super::super::cohort::{
EmptyAddressDataWithSource, FundedAddressDataWithSource, TxIndexVec, WithAddressDataSource,
update_tx_counts,
};
use super::super::cohort::{WithAddressDataSource, update_tx_counts};
use super::lookup::AddressLookup;
/// Cache for address data within a flush interval.
pub struct AddressCache {
/// Addresses with non-zero balance
funded: AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
funded: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
/// Addresses that became empty (zero balance)
empty: AddressTypeToTypeIndexMap<EmptyAddressDataWithSource>,
empty: AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
}
impl Default for AddressCache {
@@ -49,7 +49,7 @@ impl AddressCache {
/// Merge address data into funded cache.
#[inline]
pub(crate) fn merge_funded(&mut self, data: AddressTypeToTypeIndexMap<FundedAddressDataWithSource>) {
pub(crate) fn merge_funded(&mut self, data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>) {
self.funded.merge_mut(data);
}
@@ -63,7 +63,7 @@ impl AddressCache {
}
/// Update transaction counts for addresses.
pub(crate) fn update_tx_counts(&mut self, txindex_vecs: AddressTypeToTypeIndexMap<TxIndexVec>) {
pub(crate) fn update_tx_counts(&mut self, txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>) {
update_tx_counts(&mut self.funded, &mut self.empty, txindex_vecs);
}
@@ -71,8 +71,8 @@ impl AddressCache {
pub(crate) fn take(
&mut self,
) -> (
AddressTypeToTypeIndexMap<EmptyAddressDataWithSource>,
AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
) {
(
std::mem::take(&mut self.empty),
@@ -93,7 +93,7 @@ pub(crate) fn load_uncached_address_data(
vr: &VecsReaders,
any_address_indexes: &AnyAddressIndexesVecs,
addresses_data: &AddressesDataVecs,
) -> Result<Option<FundedAddressDataWithSource>> {
) -> Result<Option<WithAddressDataSource<FundedAddressData>>> {
// Check if this is a new address (typeindex >= first for this height)
let first = *first_addressindexes.get(address_type).unwrap();
if first <= typeindex {

View File

@@ -1,10 +1,8 @@
use brk_types::{FundedAddressData, OutputType, TypeIndex};
use brk_types::{EmptyAddressData, FundedAddressData, OutputType, TypeIndex};
use crate::distribution::address::AddressTypeToTypeIndexMap;
use super::super::cohort::{
EmptyAddressDataWithSource, FundedAddressDataWithSource, WithAddressDataSource,
};
use super::super::cohort::WithAddressDataSource;
/// Tracking status of an address - determines cohort update strategy.
#[derive(Clone, Copy)]
@@ -19,8 +17,8 @@ pub enum TrackingStatus {
/// Context for looking up and storing address data during block processing.
pub struct AddressLookup<'a> {
pub funded: &'a mut AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
pub empty: &'a mut AddressTypeToTypeIndexMap<EmptyAddressDataWithSource>,
pub funded: &'a mut AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
pub empty: &'a mut AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
}
impl<'a> AddressLookup<'a> {
@@ -28,7 +26,7 @@ impl<'a> AddressLookup<'a> {
&mut self,
output_type: OutputType,
type_index: TypeIndex,
) -> (&mut FundedAddressDataWithSource, TrackingStatus) {
) -> (&mut WithAddressDataSource<FundedAddressData>, TrackingStatus) {
use std::collections::hash_map::Entry;
let map = self.funded.get_mut(output_type).unwrap();
@@ -83,7 +81,7 @@ impl<'a> AddressLookup<'a> {
&mut self,
output_type: OutputType,
type_index: TypeIndex,
) -> &mut FundedAddressDataWithSource {
) -> &mut WithAddressDataSource<FundedAddressData> {
self.funded
.get_mut(output_type)
.unwrap()

View File

@@ -7,7 +7,7 @@ use vecdb::AnyVec;
use crate::distribution::{AddressTypeToTypeIndexMap, AddressesDataVecs};
use super::with_source::{EmptyAddressDataWithSource, FundedAddressDataWithSource};
use super::with_source::WithAddressDataSource;
/// Process funded address data updates.
///
@@ -17,7 +17,7 @@ use super::with_source::{EmptyAddressDataWithSource, FundedAddressDataWithSource
/// - Transition empty -> funded: delete from empty, push to funded
pub(crate) fn process_funded_addresses(
addresses_data: &mut AddressesDataVecs,
funded_updates: AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
funded_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
) -> Result<AddressTypeToTypeIndexMap<AnyAddressIndex>> {
let total: usize = funded_updates.iter().map(|(_, m)| m.len()).sum();
@@ -28,13 +28,13 @@ pub(crate) fn process_funded_addresses(
for (address_type, items) in funded_updates.into_iter() {
for (typeindex, source) in items {
match source {
FundedAddressDataWithSource::New(data) => {
WithAddressDataSource::New(data) => {
pushes.push((address_type, typeindex, data));
}
FundedAddressDataWithSource::FromFunded(index, data) => {
WithAddressDataSource::FromFunded(index, data) => {
updates.push((index, data));
}
FundedAddressDataWithSource::FromEmpty(empty_index, data) => {
WithAddressDataSource::FromEmpty(empty_index, data) => {
deletes.push(empty_index);
pushes.push((address_type, typeindex, data));
}
@@ -88,7 +88,7 @@ pub(crate) fn process_funded_addresses(
/// - Transition funded -> empty: delete from funded, push to empty
pub(crate) fn process_empty_addresses(
addresses_data: &mut AddressesDataVecs,
empty_updates: AddressTypeToTypeIndexMap<EmptyAddressDataWithSource>,
empty_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
) -> Result<AddressTypeToTypeIndexMap<AnyAddressIndex>> {
let total: usize = empty_updates.iter().map(|(_, m)| m.len()).sum();
@@ -99,13 +99,13 @@ pub(crate) fn process_empty_addresses(
for (address_type, items) in empty_updates.into_iter() {
for (typeindex, source) in items {
match source {
EmptyAddressDataWithSource::New(data) => {
WithAddressDataSource::New(data) => {
pushes.push((address_type, typeindex, data));
}
EmptyAddressDataWithSource::FromEmpty(index, data) => {
WithAddressDataSource::FromEmpty(index, data) => {
updates.push((index, data));
}
EmptyAddressDataWithSource::FromFunded(funded_index, data) => {
WithAddressDataSource::FromFunded(funded_index, data) => {
deletes.push(funded_index);
pushes.push((address_type, typeindex, data));
}

View File

@@ -1,6 +1,9 @@
use brk_types::{EmptyAddressData, FundedAddressData, TxIndex};
use smallvec::SmallVec;
use crate::distribution::address::AddressTypeToTypeIndexMap;
use super::with_source::{EmptyAddressDataWithSource, FundedAddressDataWithSource, TxIndexVec};
use super::with_source::WithAddressDataSource;
/// Update tx_count for addresses based on unique transactions they participated in.
///
@@ -11,9 +14,9 @@ use super::with_source::{EmptyAddressDataWithSource, FundedAddressDataWithSource
/// Addresses are looked up in funded_cache first, then empty_cache.
/// NOTE: This should be called AFTER merging parallel-fetched address data into funded_cache.
pub(crate) fn update_tx_counts(
funded_cache: &mut AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
empty_cache: &mut AddressTypeToTypeIndexMap<EmptyAddressDataWithSource>,
mut txindex_vecs: AddressTypeToTypeIndexMap<TxIndexVec>,
funded_cache: &mut AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
empty_cache: &mut AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
mut txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
) {
// First, deduplicate txindex_vecs for addresses that appear multiple times in a block
for (_, map) in txindex_vecs.iter_mut() {

View File

@@ -1,16 +1,4 @@
use brk_types::{
EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex, TxIndex,
};
use smallvec::SmallVec;
/// Funded address data with source tracking for flush operations.
pub type FundedAddressDataWithSource = WithAddressDataSource<FundedAddressData>;
/// Empty address data with source tracking for flush operations.
pub type EmptyAddressDataWithSource = WithAddressDataSource<EmptyAddressData>;
/// SmallVec for transaction indexes - most addresses have few transactions per block.
pub type TxIndexVec = SmallVec<[TxIndex; 4]>;
use brk_types::{EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex};
/// Address data wrapped with its source location for flush operations.
///

View File

@@ -1,8 +1,9 @@
use brk_cohort::ByAddressType;
use brk_error::Result;
use brk_types::{Height, OutputType, Sats, TxIndex, TypeIndex};
use brk_types::{FundedAddressData, Height, OutputType, Sats, TxIndex, TypeIndex};
use rayon::prelude::*;
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
use crate::distribution::{
address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs},
@@ -14,7 +15,7 @@ use crate::distribution::address::HeightToAddressTypeToVec;
use super::super::{
cache::{AddressCache, load_uncached_address_data},
cohort::{FundedAddressDataWithSource, TxIndexVec},
cohort::WithAddressDataSource,
};
/// Result of processing inputs for a block.
@@ -24,9 +25,9 @@ pub struct InputsResult {
/// Per-height, per-address-type sent data: (typeindex, value) for each address.
pub sent_data: HeightToAddressTypeToVec<(TypeIndex, Sats)>,
/// Address data looked up during processing, keyed by (address_type, typeindex).
pub address_data: AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
pub address_data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
/// Transaction indexes per address for tx_count tracking.
pub txindex_vecs: AddressTypeToTypeIndexMap<TxIndexVec>,
pub txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
}
/// Process inputs (spent UTXOs) for a block.
@@ -101,9 +102,9 @@ pub(crate) fn process_inputs(
);
let mut sent_data = HeightToAddressTypeToVec::with_capacity(estimated_unique_heights);
let mut address_data =
AddressTypeToTypeIndexMap::<FundedAddressDataWithSource>::with_capacity(estimated_per_type);
AddressTypeToTypeIndexMap::<WithAddressDataSource<FundedAddressData>>::with_capacity(estimated_per_type);
let mut txindex_vecs =
AddressTypeToTypeIndexMap::<TxIndexVec>::with_capacity(estimated_per_type);
AddressTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
for (prev_height, value, output_type, addr_info) in items {
height_to_sent

View File

@@ -1,6 +1,7 @@
use brk_cohort::ByAddressType;
use brk_error::Result;
use brk_types::{Sats, TxIndex, TypeIndex};
use brk_types::{FundedAddressData, Sats, TxIndex, TypeIndex};
use smallvec::SmallVec;
use crate::distribution::{
address::{
@@ -12,7 +13,7 @@ use crate::distribution::{
use super::super::{
cache::{AddressCache, load_uncached_address_data},
cohort::{FundedAddressDataWithSource, TxIndexVec},
cohort::WithAddressDataSource,
};
/// Result of processing outputs for a block.
@@ -22,9 +23,9 @@ pub struct OutputsResult {
/// Per-address-type received data: (typeindex, value) for each address.
pub received_data: AddressTypeToVec<(TypeIndex, Sats)>,
/// Address data looked up during processing, keyed by (address_type, typeindex).
pub address_data: AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
pub address_data: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
/// Transaction indexes per address for tx_count tracking.
pub txindex_vecs: AddressTypeToTypeIndexMap<TxIndexVec>,
pub txindex_vecs: AddressTypeToTypeIndexMap<SmallVec<[TxIndex; 4]>>,
}
/// Process outputs (new UTXOs) for a block.
@@ -51,9 +52,9 @@ pub(crate) fn process_outputs(
let mut transacted = Transacted::default();
let mut received_data = AddressTypeToVec::with_capacity(estimated_per_type);
let mut address_data =
AddressTypeToTypeIndexMap::<FundedAddressDataWithSource>::with_capacity(estimated_per_type);
AddressTypeToTypeIndexMap::<WithAddressDataSource<FundedAddressData>>::with_capacity(estimated_per_type);
let mut txindex_vecs =
AddressTypeToTypeIndexMap::<TxIndexVec>::with_capacity(estimated_per_type);
AddressTypeToTypeIndexMap::<SmallVec<[TxIndex; 4]>>::with_capacity(estimated_per_type);
// Single pass: read from pre-collected vecs and accumulate
for (local_idx, txoutdata) in txoutdata_vec.iter().enumerate() {

View File

@@ -5,14 +5,14 @@ use brk_cohort::{
};
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Version};
use brk_types::{Dollars, Height, Sats, Version};
use derive_more::{Deref, DerefMut};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Database, Exit, ReadableVec, Rw, StorageMode};
use crate::{ComputeIndexes, blocks, distribution::DynCohortVecs, indexes, prices};
use crate::distribution::metrics::{CohortMetricsBase, SupplyMetrics};
use crate::distribution::metrics::CohortMetricsBase;
use super::{super::traits::CohortVecs, vecs::AddressCohortVecs};
@@ -24,16 +24,11 @@ pub struct AddressCohorts<M: StorageMode = Rw>(AddressGroups<AddressCohortVecs<M
impl AddressCohorts {
/// Import all Address cohorts from database.
///
/// `all_supply` is the supply metrics from the UTXO "all" cohort, used as global
/// sources for `*_rel_to_market_cap` ratios.
pub(crate) fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
states_path: &Path,
all_supply: &SupplyMetrics,
) -> Result<Self> {
let v = version + VERSION;
@@ -43,7 +38,7 @@ impl AddressCohorts {
has_state: bool|
-> Result<AddressCohortVecs> {
let sp = if has_state { Some(states_path) } else { None };
AddressCohortVecs::forced_import(db, filter, name, v, indexes, prices, sp, all_supply)
AddressCohortVecs::forced_import(db, filter, name, v, indexes, sp)
};
let full = |f: Filter, name: &'static str| create(f, name, true);
@@ -135,16 +130,18 @@ impl AddressCohorts {
}
/// Second phase of post-processing: compute relative metrics.
pub(crate) fn compute_rest_part2<HM>(
pub(crate) fn compute_rest_part2<HM, AS>(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &HM,
all_supply_sats: &AS,
exit: &Exit,
) -> Result<()>
where
HM: ReadableVec<Height, Dollars> + Sync,
AS: ReadableVec<Height, Sats> + Sync,
{
self.0.par_iter_mut().try_for_each(|v| {
v.compute_rest_part2(
@@ -152,6 +149,7 @@ impl AddressCohorts {
prices,
starting_indexes,
height_to_market_cap,
all_supply_sats,
exit,
)
})

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, Dollars, Height, StoredF64, StoredU64, Version};
use brk_types::{Cents, Dollars, Height, Sats, StoredF64, StoredU64, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, WritableVec, ReadableVec, Rw, StorageMode};
@@ -15,7 +15,7 @@ use crate::{
prices,
};
use crate::distribution::metrics::{BasicCohortMetrics, CohortMetricsBase, ImportConfig, SupplyMetrics};
use crate::distribution::metrics::{BasicCohortMetrics, CohortMetricsBase, ImportConfig};
use super::super::traits::{CohortVecs, DynCohortVecs};
@@ -41,19 +41,13 @@ pub struct AddressCohortVecs<M: StorageMode = Rw> {
impl AddressCohortVecs {
/// Import address cohort from database.
///
/// `all_supply` is the supply metrics from the "all" cohort, used as global
/// sources for `*_rel_to_market_cap` ratios.
#[allow(clippy::too_many_arguments)]
pub(crate) fn forced_import(
db: &Database,
filter: Filter,
name: &str,
version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
states_path: Option<&Path>,
all_supply: &SupplyMetrics,
) -> Result<Self> {
let full_name = CohortContext::Address.full_name(&filter, name);
@@ -64,7 +58,6 @@ impl AddressCohortVecs {
context: CohortContext::Address,
version,
indexes,
prices,
};
Ok(Self {
@@ -73,7 +66,7 @@ impl AddressCohortVecs {
state: states_path
.map(|path| Box::new(AddressCohortState::new(path, &full_name))),
metrics: BasicCohortMetrics::forced_import(&cfg, all_supply)?,
metrics: BasicCohortMetrics::forced_import(&cfg)?,
addr_count: ComputedFromHeightLast::forced_import(
db,
@@ -287,6 +280,7 @@ impl CohortVecs for AddressCohortVecs {
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.metrics.compute_rest_part2(
@@ -294,6 +288,7 @@ impl CohortVecs for AddressCohortVecs {
prices,
starting_indexes,
height_to_market_cap,
all_supply_sats,
exit,
)?;
Ok(())

View File

@@ -1,5 +1,5 @@
use brk_error::Result;
use brk_types::{Cents, Dollars, Height, Version};
use brk_types::{Cents, Dollars, Height, Sats, Version};
use vecdb::{Exit, ReadableVec};
use crate::{ComputeIndexes, blocks, prices};
@@ -75,6 +75,7 @@ pub trait CohortVecs: DynCohortVecs {
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()>;
}

View File

@@ -11,7 +11,7 @@ use brk_types::{
StoredF32, Timestamp, Version,
};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Database, Exit, ReadableVec, Rw, StorageMode, VecIndex, WritableVec};
use vecdb::{AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode, VecIndex, WritableVec};
use crate::{
ComputeIndexes, blocks,
@@ -24,7 +24,7 @@ use crate::{
use crate::distribution::metrics::{
AdjustedCohortMetrics, AllCohortMetrics, BasicCohortMetrics, CohortMetricsBase,
ExtendedAdjustedCohortMetrics, ExtendedCohortMetrics, ImportConfig, PeakRegretCohortMetrics,
RealizedBase, SupplyMetrics,
SupplyMetrics,
};
use super::vecs::UTXOCohortVecs;
@@ -68,7 +68,6 @@ impl UTXOCohorts<Rw> {
db: &Database,
version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
states_path: &Path,
) -> Result<Self> {
let v = version + VERSION;
@@ -82,7 +81,6 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v + Version::ONE,
indexes,
prices,
};
let all_supply = SupplyMetrics::forced_import(&all_cfg)?;
@@ -90,7 +88,6 @@ impl UTXOCohorts<Rw> {
// age_range: ExtendedCohortMetrics with full state
let age_range = {
let s = &all_supply;
ByAgeRange::try_new(&|f: Filter, name: &'static str| -> Result<_> {
let full_name = CohortContext::Utxo.full_name(&f, name);
let cfg = ImportConfig {
@@ -100,12 +97,11 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v,
indexes,
prices,
};
let state = Some(Box::new(UTXOCohortState::new(states_path, &full_name)));
Ok(UTXOCohortVecs::new(
state,
ExtendedCohortMetrics::forced_import(&cfg, s)?,
ExtendedCohortMetrics::forced_import(&cfg)?,
))
})?
};
@@ -121,12 +117,11 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v,
indexes,
prices,
};
let state = Some(Box::new(UTXOCohortState::new(states_path, &full_name)));
Ok(UTXOCohortVecs::new(
state,
BasicCohortMetrics::forced_import(&cfg, &all_supply)?,
BasicCohortMetrics::forced_import(&cfg)?,
))
};
@@ -135,18 +130,13 @@ impl UTXOCohorts<Rw> {
let year = ByYear::try_new(&basic_separate)?;
let type_ = BySpendableType::try_new(&basic_separate)?;
// Phase 3: Get up_to_1h realized for adjusted computation.
let up_to_1h_realized: &RealizedBase = &age_range.up_to_1h.metrics.realized;
// Phase 4: Import "all" cohort with pre-imported supply.
// Phase 3: Import "all" cohort with pre-imported supply.
let all = UTXOCohortVecs::new(
None,
AllCohortMetrics::forced_import_with_supply(&all_cfg, all_supply, up_to_1h_realized)?,
AllCohortMetrics::forced_import_with_supply(&all_cfg, all_supply)?,
);
let all_supply_ref = &all.metrics.supply;
// Phase 5: Import aggregate cohorts.
// Phase 4: Import aggregate cohorts.
// sth: ExtendedAdjustedCohortMetrics
let sth = {
@@ -159,14 +149,11 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v,
indexes,
prices,
};
UTXOCohortVecs::new(
None,
ExtendedAdjustedCohortMetrics::forced_import(
&cfg,
all_supply_ref,
up_to_1h_realized,
)?,
)
};
@@ -182,17 +169,15 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v,
indexes,
prices,
};
UTXOCohortVecs::new(
None,
ExtendedCohortMetrics::forced_import(&cfg, all_supply_ref)?,
ExtendedCohortMetrics::forced_import(&cfg)?,
)
};
// max_age: AdjustedCohortMetrics (adjusted + peak_regret)
let max_age = {
let s = all_supply_ref;
ByMaxAge::try_new(&|f: Filter, name: &'static str| -> Result<_> {
let full_name = CohortContext::Utxo.full_name(&f, name);
let cfg = ImportConfig {
@@ -202,18 +187,16 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v,
indexes,
prices,
};
Ok(UTXOCohortVecs::new(
None,
AdjustedCohortMetrics::forced_import(&cfg, s, up_to_1h_realized)?,
AdjustedCohortMetrics::forced_import(&cfg)?,
))
})?
};
// min_age: PeakRegretCohortMetrics
let min_age = {
let s = all_supply_ref;
ByMinAge::try_new(&|f: Filter, name: &'static str| -> Result<_> {
let full_name = CohortContext::Utxo.full_name(&f, name);
let cfg = ImportConfig {
@@ -223,11 +206,10 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v,
indexes,
prices,
};
Ok(UTXOCohortVecs::new(
None,
PeakRegretCohortMetrics::forced_import(&cfg, s)?,
PeakRegretCohortMetrics::forced_import(&cfg)?,
))
})?
};
@@ -243,11 +225,10 @@ impl UTXOCohorts<Rw> {
context: CohortContext::Utxo,
version: v,
indexes,
prices,
};
Ok(UTXOCohortVecs::new(
None,
BasicCohortMetrics::forced_import(&cfg, all_supply_ref)?,
BasicCohortMetrics::forced_import(&cfg)?,
))
};
@@ -647,18 +628,32 @@ impl UTXOCohorts<Rw> {
where
HM: ReadableVec<Height, Dollars> + Sync,
{
// Get up_to_1h value sources for adjusted computation (cloned to avoid borrow conflicts).
let up_to_1h_value_created = self.age_range.up_to_1h.metrics.realized.value_created.height.read_only_clone();
let up_to_1h_value_destroyed = self.age_range.up_to_1h.metrics.realized.value_destroyed.height.read_only_clone();
// "all" cohort computed first (no all_supply_sats needed).
self.all.metrics.compute_rest_part2(
blocks,
prices,
starting_indexes,
height_to_market_cap,
&up_to_1h_value_created,
&up_to_1h_value_destroyed,
exit,
)?;
// Clone all_supply_sats for non-all cohorts.
let all_supply_sats = self.all.metrics.supply.total.sats.height.read_only_clone();
self.sth.metrics.compute_rest_part2(
blocks,
prices,
starting_indexes,
height_to_market_cap,
&up_to_1h_value_created,
&up_to_1h_value_destroyed,
&all_supply_sats,
exit,
)?;
self.lth.metrics.compute_rest_part2(
@@ -666,6 +661,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)?;
self.age_range.par_iter_mut().try_for_each(|v| {
@@ -674,6 +670,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;
@@ -683,6 +680,9 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&up_to_1h_value_created,
&up_to_1h_value_destroyed,
&all_supply_sats,
exit,
)
})?;
@@ -692,6 +692,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;
@@ -701,6 +702,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;
@@ -710,6 +712,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;
@@ -719,6 +722,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;
@@ -728,6 +732,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;
@@ -737,6 +742,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;
@@ -746,6 +752,7 @@ impl UTXOCohorts<Rw> {
prices,
starting_indexes,
height_to_market_cap,
&all_supply_sats,
exit,
)
})?;

View File

@@ -75,6 +75,7 @@ where
prices,
starting_indexes,
height_to_market_cap,
&utxo_cohorts.all.metrics.supply.total.sats.height,
exit,
)?;

View File

@@ -65,10 +65,10 @@ pub(crate) fn process_blocks(
let height_to_first_txoutindex = &indexer.vecs.outputs.first_txoutindex;
let height_to_first_txinindex = &indexer.vecs.inputs.first_txinindex;
// From transactions and inputs/outputs (via .height or .height.sum_cum.sum patterns):
// From transactions and inputs/outputs (via .height or .height.sum_cumulative.sum patterns):
let height_to_tx_count = &transactions.count.tx_count.height;
let height_to_output_count = &outputs.count.total_count.sum_cum.sum.0;
let height_to_input_count = &inputs.count.height.sum_cum.sum.0;
let height_to_output_count = &outputs.count.total_count.sum_cumulative.sum.0;
let height_to_input_count = &inputs.count.height.sum_cumulative.sum.0;
// From blocks:
let height_to_timestamp = &blocks.time.timestamp_monotonic;
let height_to_date = &blocks.time.date;

View File

@@ -1,17 +1,14 @@
use std::time::Instant;
use brk_error::Result;
use brk_types::Height;
use brk_types::{EmptyAddressData, FundedAddressData, Height};
use rayon::prelude::*;
use tracing::info;
use vecdb::{AnyStoredVec, WritableVec, Stamp};
use crate::distribution::{
Vecs,
block::{
EmptyAddressDataWithSource, FundedAddressDataWithSource, process_empty_addresses,
process_funded_addresses,
},
block::{WithAddressDataSource, process_empty_addresses, process_funded_addresses},
state::BlockState,
};
@@ -28,8 +25,8 @@ use super::super::address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAdd
pub(crate) fn process_address_updates(
addresses_data: &mut AddressesDataVecs,
address_indexes: &mut AnyAddressIndexesVecs,
empty_updates: AddressTypeToTypeIndexMap<EmptyAddressDataWithSource>,
funded_updates: AddressTypeToTypeIndexMap<FundedAddressDataWithSource>,
empty_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<EmptyAddressData>>,
funded_updates: AddressTypeToTypeIndexMap<WithAddressDataSource<FundedAddressData>>,
) -> Result<()> {
info!("Processing address updates...");

View File

@@ -6,7 +6,7 @@ use vecdb::{AnyStoredVec, AnyVec, EagerVec, Exit, ImportableVec, PcoVec, Rw, Sto
use crate::{
ComputeIndexes, blocks,
internal::{ComputedFromHeightCumSum, LazyComputedValueFromHeightCum, ValueEmaFromHeight},
internal::{ComputedFromHeightCumulativeSum, LazyComputedValueFromHeightCumulative, ValueEmaFromHeight},
};
use super::ImportConfig;
@@ -15,7 +15,7 @@ use super::ImportConfig;
#[derive(Traversable)]
pub struct ActivityMetrics<M: StorageMode = Rw> {
/// Total satoshis sent at each height + derived indexes
pub sent: LazyComputedValueFromHeightCum<M>,
pub sent: LazyComputedValueFromHeightCumulative<M>,
/// 14-day EMA of sent supply (sats, btc, usd)
pub sent_14d_ema: ValueEmaFromHeight<M>,
@@ -27,22 +27,21 @@ pub struct ActivityMetrics<M: StorageMode = Rw> {
pub satdays_destroyed: M::Stored<EagerVec<PcoVec<Height, Sats>>>,
/// Coin-blocks destroyed (in BTC rather than sats)
pub coinblocks_destroyed: ComputedFromHeightCumSum<StoredF64, M>,
pub coinblocks_destroyed: ComputedFromHeightCumulativeSum<StoredF64, M>,
/// Coin-days destroyed (in BTC rather than sats)
pub coindays_destroyed: ComputedFromHeightCumSum<StoredF64, M>,
pub coindays_destroyed: ComputedFromHeightCumulativeSum<StoredF64, M>,
}
impl ActivityMetrics {
/// Import activity metrics from database.
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
sent: LazyComputedValueFromHeightCum::forced_import(
sent: LazyComputedValueFromHeightCumulative::forced_import(
cfg.db,
&cfg.name("sent"),
cfg.version,
cfg.indexes,
cfg.prices,
)?,
sent_14d_ema: ValueEmaFromHeight::forced_import(
@@ -64,14 +63,14 @@ impl ActivityMetrics {
cfg.version,
)?,
coinblocks_destroyed: ComputedFromHeightCumSum::forced_import(
coinblocks_destroyed: ComputedFromHeightCumulativeSum::forced_import(
cfg.db,
&cfg.name("coinblocks_destroyed"),
cfg.version,
cfg.indexes,
)?,
coindays_destroyed: ComputedFromHeightCumSum::forced_import(
coindays_destroyed: ComputedFromHeightCumulativeSum::forced_import(
cfg.db,
&cfg.name("coindays_destroyed"),
cfg.version,
@@ -165,8 +164,6 @@ impl ActivityMetrics {
) -> Result<()> {
let window_starts = blocks.count.window_starts();
self.sent.compute_cumulative(starting_indexes.height, exit)?;
// 14-day rolling average of sent (sats and dollars)
self.sent_14d_ema.compute_rolling_average(
starting_indexes.height,

View File

@@ -1,7 +1,7 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height, Version};
use brk_types::{Cents, Dollars, Height, Sats, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
@@ -25,7 +25,7 @@ pub struct AdjustedCohortMetrics<M: StorageMode = Rw> {
pub realized: Box<RealizedWithAdjusted<M>>,
pub cost_basis: Box<CostBasisBase<M>>,
pub unrealized: Box<UnrealizedWithPeakRegret<M>>,
pub relative: Box<RelativeWithPeakRegret>,
pub relative: Box<RelativeWithPeakRegret<M>>,
}
impl CohortMetricsBase for AdjustedCohortMetrics {
@@ -73,21 +73,12 @@ impl CohortMetricsBase for AdjustedCohortMetrics {
impl AdjustedCohortMetrics {
pub(crate) fn forced_import(
cfg: &ImportConfig,
all_supply: &SupplyMetrics,
up_to_1h: &RealizedBase,
) -> Result<Self> {
let supply = SupplyMetrics::forced_import(cfg)?;
let unrealized = UnrealizedWithPeakRegret::forced_import(cfg)?;
let realized = RealizedWithAdjusted::forced_import(cfg, up_to_1h)?;
let realized = RealizedWithAdjusted::forced_import(cfg)?;
let relative = RelativeWithPeakRegret::forced_import(
cfg,
&unrealized.base,
&supply,
all_supply,
&realized.base,
&unrealized.peak_regret_ext.peak_regret,
);
let relative = RelativeWithPeakRegret::forced_import(cfg)?;
Ok(Self {
filter: cfg.filter.clone(),
@@ -101,12 +92,16 @@ impl AdjustedCohortMetrics {
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_rest_part2(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.realized.compute_rest_part2(
@@ -115,8 +110,23 @@ impl AdjustedCohortMetrics {
starting_indexes,
&self.supply.total.btc.height,
height_to_market_cap,
up_to_1h_value_created,
up_to_1h_value_destroyed,
exit,
)
)?;
self.relative.compute(
starting_indexes.height,
&self.unrealized.base,
&self.realized.base,
&self.supply.total.sats.height,
height_to_market_cap,
all_supply_sats,
&self.unrealized.peak_regret_ext.peak_regret.height,
exit,
)?;
Ok(())
}
}

View File

@@ -26,23 +26,49 @@ pub struct AllCohortMetrics<M: StorageMode = Rw> {
pub realized: Box<RealizedWithExtendedAdjusted<M>>,
pub cost_basis: Box<CostBasisWithExtended<M>>,
pub unrealized: Box<UnrealizedWithPeakRegret<M>>,
pub relative: Box<RelativeForAll>,
pub relative: Box<RelativeForAll<M>>,
}
impl CohortMetricsBase for AllCohortMetrics {
fn filter(&self) -> &Filter { &self.filter }
fn supply(&self) -> &SupplyMetrics { &self.supply }
fn supply_mut(&mut self) -> &mut SupplyMetrics { &mut self.supply }
fn outputs(&self) -> &OutputsMetrics { &self.outputs }
fn outputs_mut(&mut self) -> &mut OutputsMetrics { &mut self.outputs }
fn activity(&self) -> &ActivityMetrics { &self.activity }
fn activity_mut(&mut self) -> &mut ActivityMetrics { &mut self.activity }
fn realized_base(&self) -> &RealizedBase { &self.realized }
fn realized_base_mut(&mut self) -> &mut RealizedBase { &mut self.realized }
fn unrealized_base(&self) -> &UnrealizedBase { &self.unrealized }
fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase { &mut self.unrealized }
fn cost_basis_base(&self) -> &CostBasisBase { &self.cost_basis }
fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase { &mut self.cost_basis }
fn filter(&self) -> &Filter {
&self.filter
}
fn supply(&self) -> &SupplyMetrics {
&self.supply
}
fn supply_mut(&mut self) -> &mut SupplyMetrics {
&mut self.supply
}
fn outputs(&self) -> &OutputsMetrics {
&self.outputs
}
fn outputs_mut(&mut self) -> &mut OutputsMetrics {
&mut self.outputs
}
fn activity(&self) -> &ActivityMetrics {
&self.activity
}
fn activity_mut(&mut self) -> &mut ActivityMetrics {
&mut self.activity
}
fn realized_base(&self) -> &RealizedBase {
&self.realized
}
fn realized_base_mut(&mut self) -> &mut RealizedBase {
&mut self.realized
}
fn unrealized_base(&self) -> &UnrealizedBase {
&self.unrealized
}
fn unrealized_base_mut(&mut self) -> &mut UnrealizedBase {
&mut self.unrealized
}
fn cost_basis_base(&self) -> &CostBasisBase {
&self.cost_basis
}
fn cost_basis_base_mut(&mut self) -> &mut CostBasisBase {
&mut self.cost_basis
}
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
self.supply.validate_computed_versions(base_version)?;
self.activity.validate_computed_versions(base_version)?;
@@ -50,14 +76,21 @@ impl CohortMetricsBase for AllCohortMetrics {
Ok(())
}
fn compute_then_truncate_push_unrealized_states(
&mut self, height: Height, height_price: Cents, state: &mut CohortState,
&mut self,
height: Height,
height_price: Cents,
state: &mut CohortState,
) -> Result<()> {
state.apply_pending();
self.cost_basis.truncate_push_minmax(height, state)?;
let (height_unrealized_state, _) = state.compute_unrealized_states(height_price, None);
self.unrealized.base.truncate_push(height, &height_unrealized_state)?;
self.unrealized
.base
.truncate_push(height, &height_unrealized_state)?;
let spot = height_price.to_dollars();
self.cost_basis.extended.truncate_push_percentiles(height, state, spot)?;
self.cost_basis
.extended
.truncate_push_percentiles(height, state, spot)?;
Ok(())
}
fn collect_all_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
@@ -82,18 +115,11 @@ impl AllCohortMetrics {
pub(crate) fn forced_import_with_supply(
cfg: &ImportConfig,
supply: SupplyMetrics,
up_to_1h: &RealizedBase,
) -> Result<Self> {
let unrealized = UnrealizedWithPeakRegret::forced_import(cfg)?;
let realized = RealizedWithExtendedAdjusted::forced_import(cfg, up_to_1h)?;
let realized = RealizedWithExtendedAdjusted::forced_import(cfg)?;
let relative = RelativeForAll::forced_import(
cfg,
&unrealized.base,
&supply,
&realized.base,
&unrealized.peak_regret_ext.peak_regret,
);
let relative = RelativeForAll::forced_import(cfg)?;
Ok(Self {
filter: cfg.filter.clone(),
@@ -107,12 +133,15 @@ impl AllCohortMetrics {
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_rest_part2(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.realized.compute_rest_part2(
@@ -121,8 +150,21 @@ impl AllCohortMetrics {
starting_indexes,
&self.supply.total.btc.height,
height_to_market_cap,
up_to_1h_value_created,
up_to_1h_value_destroyed,
exit,
)
}
)?;
self.relative.compute(
starting_indexes.height,
&self.unrealized.base,
&self.realized.base,
&self.supply.total.sats.height,
height_to_market_cap,
&self.unrealized.peak_regret_ext.peak_regret.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,15 +1,15 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height, Version};
use brk_types::{Cents, Dollars, Height, Sats, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
use crate::{ComputeIndexes, blocks, distribution::state::CohortState, prices};
use crate::distribution::metrics::{
ActivityMetrics, CohortMetricsBase, CostBasisBase, ImportConfig, OutputsMetrics, RealizedBase,
RelativeWithRelToAll, SupplyMetrics, UnrealizedBase,
ActivityMetrics, CohortMetricsBase, CostBasisBase, ImportConfig, OutputsMetrics,
RealizedBase, RelativeWithRelToAll, SupplyMetrics, UnrealizedBase,
};
/// Basic cohort metrics: no extensions, with relative (rel_to_all).
@@ -24,7 +24,7 @@ pub struct BasicCohortMetrics<M: StorageMode = Rw> {
pub realized: Box<RealizedBase<M>>,
pub cost_basis: Box<CostBasisBase<M>>,
pub unrealized: Box<UnrealizedBase<M>>,
pub relative: Box<RelativeWithRelToAll>,
pub relative: Box<RelativeWithRelToAll<M>>,
}
impl CohortMetricsBase for BasicCohortMetrics {
@@ -70,15 +70,12 @@ impl CohortMetricsBase for BasicCohortMetrics {
impl BasicCohortMetrics {
pub(crate) fn forced_import(
cfg: &ImportConfig,
all_supply: &SupplyMetrics,
) -> Result<Self> {
let supply = SupplyMetrics::forced_import(cfg)?;
let unrealized = UnrealizedBase::forced_import(cfg)?;
let realized = RealizedBase::forced_import(cfg)?;
let relative = RelativeWithRelToAll::forced_import(
cfg, &unrealized, &supply, all_supply, &realized,
);
let relative = RelativeWithRelToAll::forced_import(cfg)?;
Ok(Self {
filter: cfg.filter.clone(),
@@ -102,6 +99,7 @@ impl BasicCohortMetrics {
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.realized.compute_rest_part2_base(
@@ -111,7 +109,19 @@ impl BasicCohortMetrics {
&self.supply.total.btc.height,
height_to_market_cap,
exit,
)
)?;
self.relative.compute(
starting_indexes.height,
&self.unrealized,
&self.realized,
&self.supply.total.sats.height,
height_to_market_cap,
all_supply_sats,
exit,
)?;
Ok(())
}
pub(crate) fn compute_from_stateful(

View File

@@ -1,7 +1,7 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height, Version};
use brk_types::{Cents, Dollars, Height, Sats, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
@@ -25,7 +25,7 @@ pub struct ExtendedCohortMetrics<M: StorageMode = Rw> {
pub realized: Box<RealizedWithExtended<M>>,
pub cost_basis: Box<CostBasisWithExtended<M>>,
pub unrealized: Box<UnrealizedWithPeakRegret<M>>,
pub relative: Box<RelativeWithExtended>,
pub relative: Box<RelativeWithExtended<M>>,
}
impl CohortMetricsBase for ExtendedCohortMetrics {
@@ -77,20 +77,12 @@ impl CohortMetricsBase for ExtendedCohortMetrics {
impl ExtendedCohortMetrics {
pub(crate) fn forced_import(
cfg: &ImportConfig,
all_supply: &SupplyMetrics,
) -> Result<Self> {
let supply = SupplyMetrics::forced_import(cfg)?;
let unrealized = UnrealizedWithPeakRegret::forced_import(cfg)?;
let realized = RealizedWithExtended::forced_import(cfg)?;
let relative = RelativeWithExtended::forced_import(
cfg,
&unrealized.base,
&supply,
all_supply,
&realized.base,
&unrealized.peak_regret_ext.peak_regret,
);
let relative = RelativeWithExtended::forced_import(cfg)?;
Ok(Self {
filter: cfg.filter.clone(),
@@ -110,6 +102,7 @@ impl ExtendedCohortMetrics {
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.realized.compute_rest_part2(
@@ -119,7 +112,21 @@ impl ExtendedCohortMetrics {
&self.supply.total.btc.height,
height_to_market_cap,
exit,
)
)?;
self.relative.compute(
starting_indexes.height,
&self.unrealized.base,
&self.realized.base,
&self.supply.total.sats.height,
height_to_market_cap,
all_supply_sats,
&self.supply.total.usd.height,
&self.unrealized.peak_regret_ext.peak_regret.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,7 +1,7 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height, Version};
use brk_types::{Cents, Dollars, Height, Sats, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
@@ -25,7 +25,7 @@ pub struct ExtendedAdjustedCohortMetrics<M: StorageMode = Rw> {
pub realized: Box<RealizedWithExtendedAdjusted<M>>,
pub cost_basis: Box<CostBasisWithExtended<M>>,
pub unrealized: Box<UnrealizedWithPeakRegret<M>>,
pub relative: Box<RelativeWithExtended>,
pub relative: Box<RelativeWithExtended<M>>,
}
impl CohortMetricsBase for ExtendedAdjustedCohortMetrics {
@@ -76,21 +76,12 @@ impl CohortMetricsBase for ExtendedAdjustedCohortMetrics {
impl ExtendedAdjustedCohortMetrics {
pub(crate) fn forced_import(
cfg: &ImportConfig,
all_supply: &SupplyMetrics,
up_to_1h: &RealizedBase,
) -> Result<Self> {
let supply = SupplyMetrics::forced_import(cfg)?;
let unrealized = UnrealizedWithPeakRegret::forced_import(cfg)?;
let realized = RealizedWithExtendedAdjusted::forced_import(cfg, up_to_1h)?;
let realized = RealizedWithExtendedAdjusted::forced_import(cfg)?;
let relative = RelativeWithExtended::forced_import(
cfg,
&unrealized.base,
&supply,
all_supply,
&realized.base,
&unrealized.peak_regret_ext.peak_regret,
);
let relative = RelativeWithExtended::forced_import(cfg)?;
Ok(Self {
filter: cfg.filter.clone(),
@@ -104,12 +95,16 @@ impl ExtendedAdjustedCohortMetrics {
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_rest_part2(
&mut self,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.realized.compute_rest_part2(
@@ -118,8 +113,24 @@ impl ExtendedAdjustedCohortMetrics {
starting_indexes,
&self.supply.total.btc.height,
height_to_market_cap,
up_to_1h_value_created,
up_to_1h_value_destroyed,
exit,
)
)?;
self.relative.compute(
starting_indexes.height,
&self.unrealized.base,
&self.realized.base,
&self.supply.total.sats.height,
height_to_market_cap,
all_supply_sats,
&self.supply.total.usd.height,
&self.unrealized.peak_regret_ext.peak_regret.height,
exit,
)?;
Ok(())
}
}

View File

@@ -1,7 +1,7 @@
use brk_cohort::Filter;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height, Version};
use brk_types::{Cents, Dollars, Height, Sats, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
@@ -24,7 +24,7 @@ pub struct PeakRegretCohortMetrics<M: StorageMode = Rw> {
pub realized: Box<RealizedBase<M>>,
pub cost_basis: Box<CostBasisBase<M>>,
pub unrealized: Box<UnrealizedWithPeakRegret<M>>,
pub relative: Box<RelativeWithPeakRegret>,
pub relative: Box<RelativeWithPeakRegret<M>>,
}
impl CohortMetricsBase for PeakRegretCohortMetrics {
@@ -72,20 +72,12 @@ impl CohortMetricsBase for PeakRegretCohortMetrics {
impl PeakRegretCohortMetrics {
pub(crate) fn forced_import(
cfg: &ImportConfig,
all_supply: &SupplyMetrics,
) -> Result<Self> {
let supply = SupplyMetrics::forced_import(cfg)?;
let unrealized = UnrealizedWithPeakRegret::forced_import(cfg)?;
let realized = RealizedBase::forced_import(cfg)?;
let relative = RelativeWithPeakRegret::forced_import(
cfg,
&unrealized.base,
&supply,
all_supply,
&realized,
&unrealized.peak_regret_ext.peak_regret,
);
let relative = RelativeWithPeakRegret::forced_import(cfg)?;
Ok(Self {
filter: cfg.filter.clone(),
@@ -105,6 +97,7 @@ impl PeakRegretCohortMetrics {
prices: &prices::Vecs,
starting_indexes: &ComputeIndexes,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.realized.compute_rest_part2_base(
@@ -114,7 +107,20 @@ impl PeakRegretCohortMetrics {
&self.supply.total.btc.height,
height_to_market_cap,
exit,
)
)?;
self.relative.compute(
starting_indexes.height,
&self.unrealized.base,
&self.realized,
&self.supply.total.sats.height,
height_to_market_cap,
all_supply_sats,
&self.unrealized.peak_regret_ext.peak_regret.height,
exit,
)?;
Ok(())
}
}

View File

@@ -2,7 +2,7 @@ use brk_cohort::{CohortContext, Filter};
use brk_types::Version;
use vecdb::Database;
use crate::{indexes, prices};
use crate::indexes;
/// Configuration for importing metrics.
pub struct ImportConfig<'a> {
@@ -12,7 +12,6 @@ pub struct ImportConfig<'a> {
pub context: CohortContext,
pub version: Version,
pub indexes: &'a indexes::Vecs,
pub prices: &'a prices::Vecs,
}
impl<'a> ImportConfig<'a> {

View File

@@ -6,7 +6,7 @@ use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::{
ComputeIndexes,
distribution::state::CohortState,
internal::{ComputedFromHeightLast, Price, PriceFromHeight},
internal::{ComputedFromHeightLast, Price},
};
use crate::distribution::metrics::ImportConfig;
@@ -24,13 +24,13 @@ pub struct CostBasisBase<M: StorageMode = Rw> {
impl CostBasisBase {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
min: PriceFromHeight::forced_import(
min: Price::forced_import(
cfg.db,
&cfg.name("min_cost_basis"),
cfg.version,
cfg.indexes,
)?,
max: PriceFromHeight::forced_import(
max: Price::forced_import(
cfg.db,
&cfg.name("max_cost_basis"),
cfg.version,
@@ -40,7 +40,7 @@ impl CostBasisBase {
}
pub(crate) fn min_stateful_height_len(&self) -> usize {
self.min.height.len().min(self.max.height.len())
self.min.usd.height.len().min(self.max.usd.height.len())
}
pub(crate) fn truncate_push_minmax(
@@ -48,14 +48,14 @@ impl CostBasisBase {
height: Height,
state: &CohortState,
) -> Result<()> {
self.min.height.truncate_push(
self.min.usd.height.truncate_push(
height,
state
.cost_basis_data_first_key_value()
.map(|(cents, _)| cents.into())
.unwrap_or(Dollars::NAN),
)?;
self.max.height.truncate_push(
self.max.usd.height.truncate_push(
height,
state
.cost_basis_data_last_key_value()
@@ -67,8 +67,8 @@ impl CostBasisBase {
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![
&mut self.min.height as &mut dyn AnyStoredVec,
&mut self.max.height,
&mut self.min.usd.height as &mut dyn AnyStoredVec,
&mut self.max.usd.height,
]
}
@@ -78,14 +78,14 @@ impl CostBasisBase {
others: &[&Self],
exit: &Exit,
) -> Result<()> {
self.min.height.compute_min_of_others(
self.min.usd.height.compute_min_of_others(
starting_indexes.height,
&others.iter().map(|v| &v.min.height).collect::<Vec<_>>(),
&others.iter().map(|v| &v.min.usd.height).collect::<Vec<_>>(),
exit,
)?;
self.max.height.compute_max_of_others(
self.max.usd.height.compute_max_of_others(
starting_indexes.height,
&others.iter().map(|v| &v.max.height).collect::<Vec<_>>(),
&others.iter().map(|v| &v.max.usd.height).collect::<Vec<_>>(),
exit,
)?;
Ok(())

View File

@@ -100,14 +100,14 @@ impl CostBasisExtended {
.vecs
.iter_mut()
.flatten()
.map(|v| &mut v.height as &mut dyn AnyStoredVec),
.map(|v| &mut v.usd.height as &mut dyn AnyStoredVec),
);
vecs.extend(
self.invested_capital
.vecs
.iter_mut()
.flatten()
.map(|v| &mut v.height as &mut dyn AnyStoredVec),
.map(|v| &mut v.usd.height as &mut dyn AnyStoredVec),
);
vecs.push(&mut self.spot_cost_basis_percentile.height);
vecs.push(&mut self.spot_invested_capital_percentile.height);

View File

@@ -152,13 +152,24 @@ pub trait CohortMetricsBase: Send + Sync {
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.supply_mut()
.compute(prices, starting_indexes.height, exit)?;
self.supply_mut()
.compute_rest_part1(blocks, starting_indexes, exit)?;
self.outputs_mut()
.compute_rest(blocks, starting_indexes, exit)?;
self.activity_mut()
.sent
.compute(prices, starting_indexes.height, exit)?;
self.activity_mut()
.compute_rest_part1(blocks, starting_indexes, exit)?;
self.realized_base_mut()
.sent_in_profit
.compute(prices, starting_indexes.height, exit)?;
self.realized_base_mut()
.sent_in_loss
.compute(prices, starting_indexes.height, exit)?;
self.realized_base_mut()
.compute_rest_part1(starting_indexes, exit)?;

View File

@@ -1,26 +1,21 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, StoredF64, Version};
use vecdb::{Exit, Ident, ReadableCloneableVec, Rw, StorageMode};
use brk_types::{Dollars, Height, StoredF64, Version};
use vecdb::{Exit, Ident, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::{
ComputeIndexes, blocks,
internal::{
ComputedFromHeightLast, DollarsMinus, LazyBinaryFromHeightLast,
LazyFromHeightLast, Ratio64,
},
internal::{ComputedFromHeightLast, LazyFromHeightLast, Ratio64},
};
use crate::distribution::metrics::ImportConfig;
use super::RealizedBase;
/// Adjusted realized metrics (only for adjusted cohorts: all, sth, max_age).
#[derive(Traversable)]
pub struct RealizedAdjusted<M: StorageMode = Rw> {
// === Adjusted Value (lazy: cohort - up_to_1h) ===
pub adjusted_value_created: LazyBinaryFromHeightLast<Dollars, Dollars, Dollars>,
pub adjusted_value_destroyed: LazyBinaryFromHeightLast<Dollars, Dollars, Dollars>,
// === Adjusted Value (computed: cohort - up_to_1h) ===
pub adjusted_value_created: ComputedFromHeightLast<Dollars, M>,
pub adjusted_value_destroyed: ComputedFromHeightLast<Dollars, M>,
// === Adjusted Value Created/Destroyed Rolling Sums ===
pub adjusted_value_created_24h: ComputedFromHeightLast<Dollars, M>,
@@ -34,10 +29,10 @@ pub struct RealizedAdjusted<M: StorageMode = Rw> {
// === Adjusted SOPR (rolling window ratios) ===
pub adjusted_sopr: LazyFromHeightLast<StoredF64>,
pub adjusted_sopr_24h: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub adjusted_sopr_7d: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub adjusted_sopr_30d: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub adjusted_sopr_1y: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub adjusted_sopr_24h: ComputedFromHeightLast<StoredF64, M>,
pub adjusted_sopr_7d: ComputedFromHeightLast<StoredF64, M>,
pub adjusted_sopr_30d: ComputedFromHeightLast<StoredF64, M>,
pub adjusted_sopr_1y: ComputedFromHeightLast<StoredF64, M>,
pub adjusted_sopr_24h_7d_ema: ComputedFromHeightLast<StoredF64, M>,
pub adjusted_sopr_7d_ema: LazyFromHeightLast<StoredF64>,
pub adjusted_sopr_24h_30d_ema: ComputedFromHeightLast<StoredF64, M>,
@@ -45,35 +40,32 @@ pub struct RealizedAdjusted<M: StorageMode = Rw> {
}
impl RealizedAdjusted {
pub(crate) fn forced_import(
cfg: &ImportConfig,
base: &RealizedBase,
up_to_1h: &RealizedBase,
) -> Result<Self> {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v1 = Version::ONE;
macro_rules! import_rolling {
($name:expr) => {
ComputedFromHeightLast::forced_import(cfg.db, &cfg.name($name), cfg.version + v1, cfg.indexes)?
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name($name),
cfg.version + v1,
cfg.indexes,
)?
};
}
let adjusted_value_created = LazyBinaryFromHeightLast::from_both_binary_block::<
DollarsMinus, Dollars, Dollars, Dollars, Dollars,
>(
let adjusted_value_created = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("adjusted_value_created"),
cfg.version,
&base.value_created,
&up_to_1h.value_created,
);
let adjusted_value_destroyed = LazyBinaryFromHeightLast::from_both_binary_block::<
DollarsMinus, Dollars, Dollars, Dollars, Dollars,
>(
cfg.indexes,
)?;
let adjusted_value_destroyed = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("adjusted_value_destroyed"),
cfg.version,
&base.value_destroyed,
&up_to_1h.value_destroyed,
);
cfg.indexes,
)?;
let adjusted_value_created_24h = import_rolling!("adjusted_value_created_24h");
let adjusted_value_created_7d = import_rolling!("adjusted_value_created_7d");
@@ -84,31 +76,50 @@ impl RealizedAdjusted {
let adjusted_value_destroyed_30d = import_rolling!("adjusted_value_destroyed_30d");
let adjusted_value_destroyed_1y = import_rolling!("adjusted_value_destroyed_1y");
let adjusted_sopr_24h = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("adjusted_sopr_24h"), cfg.version + v1, &adjusted_value_created_24h, &adjusted_value_destroyed_24h,
);
let adjusted_sopr_7d = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("adjusted_sopr_7d"), cfg.version + v1, &adjusted_value_created_7d, &adjusted_value_destroyed_7d,
);
let adjusted_sopr_30d = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("adjusted_sopr_30d"), cfg.version + v1, &adjusted_value_created_30d, &adjusted_value_destroyed_30d,
);
let adjusted_sopr_1y = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("adjusted_sopr_1y"), cfg.version + v1, &adjusted_value_created_1y, &adjusted_value_destroyed_1y,
);
let adjusted_sopr = LazyFromHeightLast::from_binary::<Ident, Dollars, Dollars>(
&cfg.name("adjusted_sopr"), cfg.version + v1, &adjusted_sopr_24h,
let adjusted_sopr_24h = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("adjusted_sopr_24h"),
cfg.version + v1,
cfg.indexes,
)?;
let adjusted_sopr_7d = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("adjusted_sopr_7d"),
cfg.version + v1,
cfg.indexes,
)?;
let adjusted_sopr_30d = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("adjusted_sopr_30d"),
cfg.version + v1,
cfg.indexes,
)?;
let adjusted_sopr_1y = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("adjusted_sopr_1y"),
cfg.version + v1,
cfg.indexes,
)?;
let adjusted_sopr = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("adjusted_sopr"),
cfg.version + v1,
adjusted_sopr_24h.height.read_only_boxed_clone(),
&adjusted_sopr_24h,
);
let adjusted_sopr_24h_7d_ema = import_rolling!("adjusted_sopr_24h_7d_ema");
let adjusted_sopr_7d_ema = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("adjusted_sopr_7d_ema"), cfg.version + v1,
adjusted_sopr_24h_7d_ema.height.read_only_boxed_clone(), &adjusted_sopr_24h_7d_ema,
&cfg.name("adjusted_sopr_7d_ema"),
cfg.version + v1,
adjusted_sopr_24h_7d_ema.height.read_only_boxed_clone(),
&adjusted_sopr_24h_7d_ema,
);
let adjusted_sopr_24h_30d_ema = import_rolling!("adjusted_sopr_24h_30d_ema");
let adjusted_sopr_30d_ema = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("adjusted_sopr_30d_ema"), cfg.version + v1,
adjusted_sopr_24h_30d_ema.height.read_only_boxed_clone(), &adjusted_sopr_24h_30d_ema,
&cfg.name("adjusted_sopr_30d_ema"),
cfg.version + v1,
adjusted_sopr_24h_30d_ema.height.read_only_boxed_clone(),
&adjusted_sopr_24h_30d_ema,
);
Ok(RealizedAdjusted {
@@ -134,36 +145,137 @@ impl RealizedAdjusted {
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_rest_part2_adj(
&mut self,
blocks: &blocks::Vecs,
starting_indexes: &ComputeIndexes,
base_value_created: &impl ReadableVec<Height, Dollars>,
base_value_destroyed: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
// Compute adjusted_value_created = base.value_created - up_to_1h.value_created
self.adjusted_value_created.height.compute_subtract(
starting_indexes.height,
base_value_created,
up_to_1h_value_created,
exit,
)?;
self.adjusted_value_destroyed.height.compute_subtract(
starting_indexes.height,
base_value_destroyed,
up_to_1h_value_destroyed,
exit,
)?;
// Adjusted value created/destroyed rolling sums
self.adjusted_value_created_24h.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_24h_ago, &self.adjusted_value_created.height, exit)?;
self.adjusted_value_created_7d.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_1w_ago, &self.adjusted_value_created.height, exit)?;
self.adjusted_value_created_30d.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_1m_ago, &self.adjusted_value_created.height, exit)?;
self.adjusted_value_created_1y.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_1y_ago, &self.adjusted_value_created.height, exit)?;
self.adjusted_value_destroyed_24h.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_24h_ago, &self.adjusted_value_destroyed.height, exit)?;
self.adjusted_value_destroyed_7d.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_1w_ago, &self.adjusted_value_destroyed.height, exit)?;
self.adjusted_value_destroyed_30d.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_1m_ago, &self.adjusted_value_destroyed.height, exit)?;
self.adjusted_value_destroyed_1y.height.compute_rolling_sum(starting_indexes.height, &blocks.count.height_1y_ago, &self.adjusted_value_destroyed.height, exit)?;
// Adjusted SOPR EMAs
self.adjusted_sopr_24h_7d_ema.height.compute_rolling_average(
self.adjusted_value_created_24h.height.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_24h_ago,
&self.adjusted_value_created.height,
exit,
)?;
self.adjusted_value_created_7d.height.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.adjusted_sopr.height,
&self.adjusted_value_created.height,
exit,
)?;
self.adjusted_sopr_24h_30d_ema.height.compute_rolling_average(
self.adjusted_value_created_30d.height.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.adjusted_sopr.height,
&self.adjusted_value_created.height,
exit,
)?;
self.adjusted_value_created_1y.height.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_1y_ago,
&self.adjusted_value_created.height,
exit,
)?;
self.adjusted_value_destroyed_24h
.height
.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_24h_ago,
&self.adjusted_value_destroyed.height,
exit,
)?;
self.adjusted_value_destroyed_7d
.height
.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.adjusted_value_destroyed.height,
exit,
)?;
self.adjusted_value_destroyed_30d
.height
.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.adjusted_value_destroyed.height,
exit,
)?;
self.adjusted_value_destroyed_1y
.height
.compute_rolling_sum(
starting_indexes.height,
&blocks.count.height_1y_ago,
&self.adjusted_value_destroyed.height,
exit,
)?;
// SOPR ratios from rolling sums
self.adjusted_sopr_24h
.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.adjusted_value_created_24h.height,
&self.adjusted_value_destroyed_24h.height,
exit,
)?;
self.adjusted_sopr_7d
.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.adjusted_value_created_7d.height,
&self.adjusted_value_destroyed_7d.height,
exit,
)?;
self.adjusted_sopr_30d
.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.adjusted_value_created_30d.height,
&self.adjusted_value_destroyed_30d.height,
exit,
)?;
self.adjusted_sopr_1y
.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.adjusted_value_created_1y.height,
&self.adjusted_value_destroyed_1y.height,
exit,
)?;
// Adjusted SOPR EMAs
self.adjusted_sopr_24h_7d_ema
.height
.compute_rolling_average(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.adjusted_sopr.height,
exit,
)?;
self.adjusted_sopr_24h_30d_ema
.height
.compute_rolling_average(
starting_indexes.height,
&blocks.count.height_1m_ago,
&self.adjusted_sopr.height,
exit,
)?;
Ok(())
}

View File

@@ -1,24 +1,21 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{
Bitcoin, Cents, CentsSats, CentsSquaredSats, Dollars, Height, StoredF32, StoredF64,
Version,
Bitcoin, Cents, CentsSats, CentsSquaredSats, Dollars, Height, StoredF32, StoredF64, Version,
};
use vecdb::{
AnyStoredVec, AnyVec, BytesVec, Exit, WritableVec, Ident, ImportableVec,
ReadableCloneableVec, ReadableVec, Negate, Rw, StorageMode,
AnyStoredVec, AnyVec, BytesVec, Exit, Ident, ImportableVec, Negate, ReadableCloneableVec,
ReadableVec, Rw, StorageMode, WritableVec,
};
use crate::{
ComputeIndexes, blocks,
distribution::state::RealizedState,
internal::{
CentsUnsignedToDollars, ComputedFromHeightCum, ComputedFromHeightLast,
ComputedFromHeightRatio, DollarsPlus,
DollarsSquaredDivide, LazyBinaryFromHeightLast,
LazyBinaryPriceFromHeight, LazyComputedValueFromHeightCum, LazyFromHeightLast,
LazyPriceFromCents, PercentageDollarsF32, Price, PriceFromHeight,
Ratio64, StoredF32Identity, ValueEmaFromHeight,
CentsUnsignedToDollars, ComputedFromHeightCumulative, ComputedFromHeightLast,
ComputedFromHeightRatio, DollarsPlus, LazyComputedValueFromHeightCumulative, LazyFromHeightLast,
PercentageDollarsF32, Price, Ratio64,
StoredF32Identity, ValueEmaFromHeight,
},
prices,
};
@@ -37,12 +34,12 @@ pub struct RealizedBase<M: StorageMode = Rw> {
// === Investor Price ===
pub investor_price_cents: ComputedFromHeightLast<Cents, M>,
pub investor_price: LazyPriceFromCents,
pub investor_price: Price<LazyFromHeightLast<Dollars, Cents>>,
pub investor_price_extra: ComputedFromHeightRatio<M>,
// === Floor/Ceiling Price Bands ===
pub lower_price_band: LazyBinaryPriceFromHeight,
pub upper_price_band: LazyBinaryPriceFromHeight,
pub lower_price_band: Price<ComputedFromHeightLast<Dollars, M>>,
pub upper_price_band: Price<ComputedFromHeightLast<Dollars, M>>,
// === Raw values for aggregation ===
pub cap_raw: M::Stored<BytesVec<Height, CentsSats>>,
@@ -52,21 +49,19 @@ pub struct RealizedBase<M: StorageMode = Rw> {
pub mvrv: LazyFromHeightLast<StoredF32>,
// === Realized Profit/Loss ===
pub realized_profit: ComputedFromHeightCum<Dollars, M>,
pub realized_profit: ComputedFromHeightCumulative<Dollars, M>,
pub realized_profit_7d_ema: ComputedFromHeightLast<Dollars, M>,
pub realized_loss: ComputedFromHeightCum<Dollars, M>,
pub realized_loss: ComputedFromHeightCumulative<Dollars, M>,
pub realized_loss_7d_ema: ComputedFromHeightLast<Dollars, M>,
pub neg_realized_loss: LazyFromHeightLast<Dollars>,
pub net_realized_pnl: ComputedFromHeightCum<Dollars, M>,
pub net_realized_pnl: ComputedFromHeightCumulative<Dollars, M>,
pub net_realized_pnl_7d_ema: ComputedFromHeightLast<Dollars, M>,
pub realized_value: ComputedFromHeightLast<Dollars, M>,
// === Realized vs Realized Cap Ratios (lazy) ===
pub realized_profit_rel_to_realized_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub realized_loss_rel_to_realized_cap: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub net_realized_pnl_rel_to_realized_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
// === Realized vs Realized Cap Ratios ===
pub realized_profit_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
pub realized_loss_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
pub net_realized_pnl_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
// === Total Realized PnL ===
pub total_realized_pnl: LazyFromHeightLast<Dollars>,
@@ -77,9 +72,9 @@ pub struct RealizedBase<M: StorageMode = Rw> {
pub loss_value_created: ComputedFromHeightLast<Dollars, M>,
pub loss_value_destroyed: ComputedFromHeightLast<Dollars, M>,
// === Value Created/Destroyed Totals (lazy) ===
pub value_created: LazyBinaryFromHeightLast<Dollars, Dollars, Dollars>,
pub value_destroyed: LazyBinaryFromHeightLast<Dollars, Dollars, Dollars>,
// === Value Created/Destroyed Totals ===
pub value_created: ComputedFromHeightLast<Dollars, M>,
pub value_destroyed: ComputedFromHeightLast<Dollars, M>,
// === Capitulation/Profit Flow (lazy aliases) ===
pub capitulation_flow: LazyFromHeightLast<Dollars>,
@@ -97,10 +92,10 @@ pub struct RealizedBase<M: StorageMode = Rw> {
// === SOPR (rolling window ratios) ===
pub sopr: LazyFromHeightLast<StoredF64>,
pub sopr_24h: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub sopr_7d: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub sopr_30d: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub sopr_1y: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub sopr_24h: ComputedFromHeightLast<StoredF64, M>,
pub sopr_7d: ComputedFromHeightLast<StoredF64, M>,
pub sopr_30d: ComputedFromHeightLast<StoredF64, M>,
pub sopr_1y: ComputedFromHeightLast<StoredF64, M>,
pub sopr_24h_7d_ema: ComputedFromHeightLast<StoredF64, M>,
pub sopr_7d_ema: LazyFromHeightLast<StoredF64>,
pub sopr_24h_30d_ema: ComputedFromHeightLast<StoredF64, M>,
@@ -114,10 +109,10 @@ pub struct RealizedBase<M: StorageMode = Rw> {
// === Sell Side Risk (rolling window ratios) ===
pub sell_side_risk_ratio: LazyFromHeightLast<StoredF32>,
pub sell_side_risk_ratio_24h: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub sell_side_risk_ratio_7d: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub sell_side_risk_ratio_30d: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub sell_side_risk_ratio_1y: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub sell_side_risk_ratio_24h: ComputedFromHeightLast<StoredF32, M>,
pub sell_side_risk_ratio_7d: ComputedFromHeightLast<StoredF32, M>,
pub sell_side_risk_ratio_30d: ComputedFromHeightLast<StoredF32, M>,
pub sell_side_risk_ratio_1y: ComputedFromHeightLast<StoredF32, M>,
pub sell_side_risk_ratio_24h_7d_ema: ComputedFromHeightLast<StoredF32, M>,
pub sell_side_risk_ratio_7d_ema: LazyFromHeightLast<StoredF32>,
pub sell_side_risk_ratio_24h_30d_ema: ComputedFromHeightLast<StoredF32, M>,
@@ -125,17 +120,19 @@ pub struct RealizedBase<M: StorageMode = Rw> {
// === Net Realized PnL Deltas ===
pub net_realized_pnl_cumulative_30d_delta: ComputedFromHeightLast<Dollars, M>,
pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap:
ComputedFromHeightLast<StoredF32, M>,
pub net_realized_pnl_cumulative_30d_delta_rel_to_market_cap:
ComputedFromHeightLast<StoredF32, M>,
// === Peak Regret ===
pub peak_regret: ComputedFromHeightCum<Dollars, M>,
pub peak_regret_rel_to_realized_cap: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub peak_regret: ComputedFromHeightCumulative<Dollars, M>,
pub peak_regret_rel_to_realized_cap: ComputedFromHeightLast<StoredF32, M>,
// === Sent in Profit/Loss ===
pub sent_in_profit: LazyComputedValueFromHeightCum<M>,
pub sent_in_profit: LazyComputedValueFromHeightCumulative<M>,
pub sent_in_profit_14d_ema: ValueEmaFromHeight<M>,
pub sent_in_loss: LazyComputedValueFromHeightCum<M>,
pub sent_in_loss: LazyComputedValueFromHeightCumulative<M>,
pub sent_in_loss_14d_ema: ValueEmaFromHeight<M>,
}
@@ -162,7 +159,7 @@ impl RealizedBase {
&realized_cap_cents,
);
let realized_profit = ComputedFromHeightCum::forced_import(
let realized_profit = ComputedFromHeightCumulative::forced_import(
cfg.db,
&cfg.name("realized_profit"),
cfg.version,
@@ -176,7 +173,7 @@ impl RealizedBase {
cfg.indexes,
)?;
let realized_loss = ComputedFromHeightCum::forced_import(
let realized_loss = ComputedFromHeightCumulative::forced_import(
cfg.db,
&cfg.name("realized_loss"),
cfg.version,
@@ -190,14 +187,14 @@ impl RealizedBase {
cfg.indexes,
)?;
let neg_realized_loss = LazyFromHeightLast::from_computed::<Negate>(
let neg_realized_loss = LazyFromHeightLast::from_height_source::<Negate>(
&cfg.name("neg_realized_loss"),
cfg.version + v1,
realized_loss.height.read_only_boxed_clone(),
&realized_loss,
cfg.indexes,
);
let net_realized_pnl = ComputedFromHeightCum::forced_import(
let net_realized_pnl = ComputedFromHeightCumulative::forced_import(
cfg.db,
&cfg.name("net_realized_pnl"),
cfg.version,
@@ -211,7 +208,7 @@ impl RealizedBase {
cfg.indexes,
)?;
let peak_regret = ComputedFromHeightCum::forced_import(
let peak_regret = ComputedFromHeightCumulative::forced_import(
cfg.db,
&cfg.name("realized_peak_regret"),
cfg.version + v2,
@@ -232,31 +229,28 @@ impl RealizedBase {
&realized_value,
);
let realized_profit_rel_to_realized_cap =
LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("realized_profit_rel_to_realized_cap"),
cfg.version + v1,
&realized_profit,
&realized_cap,
);
let realized_profit_rel_to_realized_cap = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("realized_profit_rel_to_realized_cap"),
cfg.version + v1,
cfg.indexes,
)?;
let realized_loss_rel_to_realized_cap =
LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("realized_loss_rel_to_realized_cap"),
cfg.version + v1,
&realized_loss,
&realized_cap,
);
let realized_loss_rel_to_realized_cap = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("realized_loss_rel_to_realized_cap"),
cfg.version + v1,
cfg.indexes,
)?;
let net_realized_pnl_rel_to_realized_cap =
LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("net_realized_pnl_rel_to_realized_cap"),
cfg.version + v1,
&net_realized_pnl,
&realized_cap,
);
let net_realized_pnl_rel_to_realized_cap = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("net_realized_pnl_rel_to_realized_cap"),
cfg.version + v1,
cfg.indexes,
)?;
let realized_price = PriceFromHeight::forced_import(
let realized_price = Price::forced_import(
cfg.db,
&cfg.name("realized_price"),
cfg.version + v1,
@@ -270,7 +264,7 @@ impl RealizedBase {
cfg.indexes,
)?;
let investor_price = LazyPriceFromCents::from_computed::<CentsUnsignedToDollars>(
let investor_price = Price::from_computed::<CentsUnsignedToDollars>(
&cfg.name("investor_price"),
cfg.version,
&investor_price_cents,
@@ -279,27 +273,24 @@ impl RealizedBase {
let investor_price_extra = ComputedFromHeightRatio::forced_import_from_lazy(
cfg.db,
&cfg.name("investor_price"),
&investor_price.usd,
cfg.version,
cfg.indexes,
extended,
)?;
let lower_price_band =
LazyBinaryPriceFromHeight::from_price_and_lazy_price::<DollarsSquaredDivide>(
&cfg.name("lower_price_band"),
cfg.version,
&realized_price,
&investor_price,
);
let lower_price_band = Price::forced_import(
cfg.db,
&cfg.name("lower_price_band"),
cfg.version,
cfg.indexes,
)?;
let upper_price_band =
LazyBinaryPriceFromHeight::from_lazy_price_and_price::<DollarsSquaredDivide>(
&cfg.name("upper_price_band"),
cfg.version,
&investor_price,
&realized_price,
);
let upper_price_band = Price::forced_import(
cfg.db,
&cfg.name("upper_price_band"),
cfg.version,
cfg.indexes,
)?;
let cap_raw = BytesVec::forced_import(cfg.db, &cfg.name("cap_raw"), cfg.version)?;
let investor_cap_raw =
@@ -330,18 +321,18 @@ impl RealizedBase {
cfg.indexes,
)?;
let value_created = LazyBinaryFromHeightLast::from_computed_last::<DollarsPlus>(
let value_created = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("value_created"),
cfg.version,
&profit_value_created,
&loss_value_created,
);
let value_destroyed = LazyBinaryFromHeightLast::from_computed_last::<DollarsPlus>(
cfg.indexes,
)?;
let value_destroyed = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("value_destroyed"),
cfg.version,
&profit_value_destroyed,
&loss_value_destroyed,
);
cfg.indexes,
)?;
let capitulation_flow = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("capitulation_flow"),
@@ -359,7 +350,7 @@ impl RealizedBase {
let realized_price_extra = ComputedFromHeightRatio::forced_import(
cfg.db,
&cfg.name("realized_price"),
Some(&realized_price),
Some(&realized_price.usd),
cfg.version + v1,
cfg.indexes,
extended,
@@ -375,7 +366,12 @@ impl RealizedBase {
// === Rolling sum intermediates ===
macro_rules! import_rolling {
($name:expr) => {
ComputedFromHeightLast::forced_import(cfg.db, &cfg.name($name), cfg.version + v1, cfg.indexes)?
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name($name),
cfg.version + v1,
cfg.indexes,
)?
};
}
@@ -393,69 +389,70 @@ impl RealizedBase {
let realized_value_30d = import_rolling!("realized_value_30d");
let realized_value_1y = import_rolling!("realized_value_1y");
// === Rolling window lazy ratios ===
let sopr_24h = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("sopr_24h"), cfg.version + v1, &value_created_24h, &value_destroyed_24h,
);
let sopr_7d = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("sopr_7d"), cfg.version + v1, &value_created_7d, &value_destroyed_7d,
);
let sopr_30d = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("sopr_30d"), cfg.version + v1, &value_created_30d, &value_destroyed_30d,
);
let sopr_1y = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("sopr_1y"), cfg.version + v1, &value_created_1y, &value_destroyed_1y,
);
let sopr = LazyFromHeightLast::from_binary::<Ident, Dollars, Dollars>(
&cfg.name("sopr"), cfg.version + v1, &sopr_24h,
// === Rolling window stored ratios ===
let sopr_24h = import_rolling!("sopr_24h");
let sopr_7d = import_rolling!("sopr_7d");
let sopr_30d = import_rolling!("sopr_30d");
let sopr_1y = import_rolling!("sopr_1y");
let sopr = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("sopr"),
cfg.version + v1,
sopr_24h.height.read_only_boxed_clone(),
&sopr_24h,
);
let sell_side_risk_ratio_24h = LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("sell_side_risk_ratio_24h"), cfg.version + v1, &realized_value_24h, &realized_cap,
);
let sell_side_risk_ratio_7d = LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("sell_side_risk_ratio_7d"), cfg.version + v1, &realized_value_7d, &realized_cap,
);
let sell_side_risk_ratio_30d = LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("sell_side_risk_ratio_30d"), cfg.version + v1, &realized_value_30d, &realized_cap,
);
let sell_side_risk_ratio_1y = LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("sell_side_risk_ratio_1y"), cfg.version + v1, &realized_value_1y, &realized_cap,
);
let sell_side_risk_ratio = LazyFromHeightLast::from_binary::<Ident, Dollars, Dollars>(
&cfg.name("sell_side_risk_ratio"), cfg.version + v1, &sell_side_risk_ratio_24h,
let sell_side_risk_ratio_24h = import_rolling!("sell_side_risk_ratio_24h");
let sell_side_risk_ratio_7d = import_rolling!("sell_side_risk_ratio_7d");
let sell_side_risk_ratio_30d = import_rolling!("sell_side_risk_ratio_30d");
let sell_side_risk_ratio_1y = import_rolling!("sell_side_risk_ratio_1y");
let sell_side_risk_ratio = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("sell_side_risk_ratio"),
cfg.version + v1,
sell_side_risk_ratio_24h.height.read_only_boxed_clone(),
&sell_side_risk_ratio_24h,
);
// === EMA imports + identity aliases ===
let sopr_24h_7d_ema = import_rolling!("sopr_24h_7d_ema");
let sopr_7d_ema = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("sopr_7d_ema"), cfg.version + v1,
sopr_24h_7d_ema.height.read_only_boxed_clone(), &sopr_24h_7d_ema,
&cfg.name("sopr_7d_ema"),
cfg.version + v1,
sopr_24h_7d_ema.height.read_only_boxed_clone(),
&sopr_24h_7d_ema,
);
let sopr_24h_30d_ema = import_rolling!("sopr_24h_30d_ema");
let sopr_30d_ema = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("sopr_30d_ema"), cfg.version + v1,
sopr_24h_30d_ema.height.read_only_boxed_clone(), &sopr_24h_30d_ema,
&cfg.name("sopr_30d_ema"),
cfg.version + v1,
sopr_24h_30d_ema.height.read_only_boxed_clone(),
&sopr_24h_30d_ema,
);
let sell_side_risk_ratio_24h_7d_ema = import_rolling!("sell_side_risk_ratio_24h_7d_ema");
let sell_side_risk_ratio_7d_ema = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("sell_side_risk_ratio_7d_ema"), cfg.version + v1,
sell_side_risk_ratio_24h_7d_ema.height.read_only_boxed_clone(), &sell_side_risk_ratio_24h_7d_ema,
&cfg.name("sell_side_risk_ratio_7d_ema"),
cfg.version + v1,
sell_side_risk_ratio_24h_7d_ema
.height
.read_only_boxed_clone(),
&sell_side_risk_ratio_24h_7d_ema,
);
let sell_side_risk_ratio_24h_30d_ema = import_rolling!("sell_side_risk_ratio_24h_30d_ema");
let sell_side_risk_ratio_30d_ema = LazyFromHeightLast::from_computed::<Ident>(
&cfg.name("sell_side_risk_ratio_30d_ema"), cfg.version + v1,
sell_side_risk_ratio_24h_30d_ema.height.read_only_boxed_clone(), &sell_side_risk_ratio_24h_30d_ema,
&cfg.name("sell_side_risk_ratio_30d_ema"),
cfg.version + v1,
sell_side_risk_ratio_24h_30d_ema
.height
.read_only_boxed_clone(),
&sell_side_risk_ratio_24h_30d_ema,
);
let peak_regret_rel_to_realized_cap =
LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<PercentageDollarsF32, _>(
&cfg.name("peak_regret_rel_to_realized_cap"),
cfg.version + v1,
&peak_regret,
&realized_cap,
);
let peak_regret_rel_to_realized_cap = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("peak_regret_rel_to_realized_cap"),
cfg.version + v1,
cfg.indexes,
)?;
Ok(Self {
realized_cap_cents,
@@ -548,12 +545,11 @@ impl RealizedBase {
)?,
peak_regret,
peak_regret_rel_to_realized_cap,
sent_in_profit: LazyComputedValueFromHeightCum::forced_import(
sent_in_profit: LazyComputedValueFromHeightCumulative::forced_import(
cfg.db,
&cfg.name("sent_in_profit"),
cfg.version,
cfg.indexes,
cfg.prices,
)?,
sent_in_profit_14d_ema: ValueEmaFromHeight::forced_import(
cfg.db,
@@ -561,12 +557,11 @@ impl RealizedBase {
cfg.version,
cfg.indexes,
)?,
sent_in_loss: LazyComputedValueFromHeightCum::forced_import(
sent_in_loss: LazyComputedValueFromHeightCumulative::forced_import(
cfg.db,
&cfg.name("sent_in_loss"),
cfg.version,
cfg.indexes,
cfg.prices,
)?,
sent_in_loss_14d_ema: ValueEmaFromHeight::forced_import(
cfg.db,
@@ -804,9 +799,9 @@ impl RealizedBase {
exit: &Exit,
) -> Result<()> {
self.realized_profit
.compute_cumulative(starting_indexes.height, exit)?;
.compute_rest(starting_indexes.height, exit)?;
self.realized_loss
.compute_cumulative(starting_indexes.height, exit)?;
.compute_rest(starting_indexes.height, exit)?;
self.net_realized_pnl
.compute(starting_indexes.height, exit, |vec| {
@@ -827,12 +822,7 @@ impl RealizedBase {
)?;
self.peak_regret
.compute_cumulative(starting_indexes.height, exit)?;
self.sent_in_profit
.compute_cumulative(starting_indexes.height, exit)?;
self.sent_in_loss
.compute_cumulative(starting_indexes.height, exit)?;
.compute_rest(starting_indexes.height, exit)?;
Ok(())
}
@@ -848,7 +838,7 @@ impl RealizedBase {
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.realized_price.height.compute_divide(
self.realized_price.usd.height.compute_divide(
starting_indexes.height,
&self.realized_cap.height,
height_to_supply,
@@ -860,7 +850,12 @@ impl RealizedBase {
prices,
starting_indexes,
exit,
Some(&self.realized_price.height),
Some(&self.realized_price.usd.height),
)?;
self.realized_price_extra.compute_usd_bands(
starting_indexes,
&self.realized_price.usd.height,
exit,
)?;
self.investor_price_extra.compute_rest(
@@ -868,7 +863,12 @@ impl RealizedBase {
prices,
starting_indexes,
exit,
Some(&self.investor_price.height),
Some(&self.investor_price.usd.height),
)?;
self.investor_price_extra.compute_usd_bands(
starting_indexes,
&self.investor_price.usd.height,
exit,
)?;
self.realized_cap_30d_delta.height.compute_rolling_change(
@@ -878,39 +878,160 @@ impl RealizedBase {
exit,
)?;
// Compute value_created/destroyed from stored components
self.value_created
.compute_binary::<Dollars, Dollars, DollarsPlus>(
starting_indexes.height,
&self.profit_value_created.height,
&self.loss_value_created.height,
exit,
)?;
self.value_destroyed
.compute_binary::<Dollars, Dollars, DollarsPlus>(
starting_indexes.height,
&self.profit_value_destroyed.height,
&self.loss_value_destroyed.height,
exit,
)?;
// === Rolling sum intermediates ===
macro_rules! rolling_sum {
($target:expr, $window:expr, $source:expr) => {
$target.height.compute_rolling_sum(
starting_indexes.height, $window, $source, exit,
starting_indexes.height,
$window,
$source,
exit,
)?
};
}
rolling_sum!(self.value_created_24h, &blocks.count.height_24h_ago, &self.value_created.height);
rolling_sum!(self.value_created_7d, &blocks.count.height_1w_ago, &self.value_created.height);
rolling_sum!(self.value_created_30d, &blocks.count.height_1m_ago, &self.value_created.height);
rolling_sum!(self.value_created_1y, &blocks.count.height_1y_ago, &self.value_created.height);
rolling_sum!(self.value_destroyed_24h, &blocks.count.height_24h_ago, &self.value_destroyed.height);
rolling_sum!(self.value_destroyed_7d, &blocks.count.height_1w_ago, &self.value_destroyed.height);
rolling_sum!(self.value_destroyed_30d, &blocks.count.height_1m_ago, &self.value_destroyed.height);
rolling_sum!(self.value_destroyed_1y, &blocks.count.height_1y_ago, &self.value_destroyed.height);
rolling_sum!(
self.value_created_24h,
&blocks.count.height_24h_ago,
&self.value_created.height
);
rolling_sum!(
self.value_created_7d,
&blocks.count.height_1w_ago,
&self.value_created.height
);
rolling_sum!(
self.value_created_30d,
&blocks.count.height_1m_ago,
&self.value_created.height
);
rolling_sum!(
self.value_created_1y,
&blocks.count.height_1y_ago,
&self.value_created.height
);
rolling_sum!(
self.value_destroyed_24h,
&blocks.count.height_24h_ago,
&self.value_destroyed.height
);
rolling_sum!(
self.value_destroyed_7d,
&blocks.count.height_1w_ago,
&self.value_destroyed.height
);
rolling_sum!(
self.value_destroyed_30d,
&blocks.count.height_1m_ago,
&self.value_destroyed.height
);
rolling_sum!(
self.value_destroyed_1y,
&blocks.count.height_1y_ago,
&self.value_destroyed.height
);
// Realized value rolling sums
rolling_sum!(self.realized_value_24h, &blocks.count.height_24h_ago, &self.realized_value.height);
rolling_sum!(self.realized_value_7d, &blocks.count.height_1w_ago, &self.realized_value.height);
rolling_sum!(self.realized_value_30d, &blocks.count.height_1m_ago, &self.realized_value.height);
rolling_sum!(self.realized_value_1y, &blocks.count.height_1y_ago, &self.realized_value.height);
rolling_sum!(
self.realized_value_24h,
&blocks.count.height_24h_ago,
&self.realized_value.height
);
rolling_sum!(
self.realized_value_7d,
&blocks.count.height_1w_ago,
&self.realized_value.height
);
rolling_sum!(
self.realized_value_30d,
&blocks.count.height_1m_ago,
&self.realized_value.height
);
rolling_sum!(
self.realized_value_1y,
&blocks.count.height_1y_ago,
&self.realized_value.height
);
// 7d rolling averages
self.realized_profit_7d_ema
.height
.compute_rolling_average(
// Compute SOPR from rolling sums
self.sopr_24h.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.value_created_24h.height,
&self.value_destroyed_24h.height,
exit,
)?;
self.sopr_7d.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.value_created_7d.height,
&self.value_destroyed_7d.height,
exit,
)?;
self.sopr_30d.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.value_created_30d.height,
&self.value_destroyed_30d.height,
exit,
)?;
self.sopr_1y.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height,
&self.value_created_1y.height,
&self.value_destroyed_1y.height,
exit,
)?;
// Compute sell-side risk ratios
self.sell_side_risk_ratio_24h
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.realized_profit.height,
&self.realized_value_24h.height,
&self.realized_cap.height,
exit,
)?;
self.sell_side_risk_ratio_7d
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&self.realized_value_7d.height,
&self.realized_cap.height,
exit,
)?;
self.sell_side_risk_ratio_30d
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&self.realized_value_30d.height,
&self.realized_cap.height,
exit,
)?;
self.sell_side_risk_ratio_1y
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&self.realized_value_1y.height,
&self.realized_cap.height,
exit,
)?;
// 7d rolling averages
self.realized_profit_7d_ema.height.compute_rolling_average(
starting_indexes.height,
&blocks.count.height_1w_ago,
&self.realized_profit.height,
exit,
)?;
self.realized_loss_7d_ema.height.compute_rolling_average(
starting_indexes.height,
&blocks.count.height_1w_ago,
@@ -974,6 +1095,36 @@ impl RealizedBase {
exit,
)?;
// Realized profit/loss/net relative to realized cap
self.realized_profit_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&self.realized_profit.height,
&self.realized_cap.height,
exit,
)?;
self.realized_loss_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&self.realized_loss.height,
&self.realized_cap.height,
exit,
)?;
self.net_realized_pnl_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&self.net_realized_pnl.height,
&self.realized_cap.height,
exit,
)?;
self.peak_regret_rel_to_realized_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
starting_indexes.height,
&self.peak_regret.height,
&self.realized_cap.height,
exit,
)?;
// Net realized PnL cumulative 30d delta
self.net_realized_pnl_cumulative_30d_delta
.height

View File

@@ -6,7 +6,7 @@ use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::{
ComputeIndexes, blocks,
internal::{
ComputedFromHeightLast, LazyBinaryFromHeightLast, Ratio64,
ComputedFromHeightLast, Ratio64,
},
};
@@ -29,11 +29,11 @@ pub struct RealizedExtended<M: StorageMode = Rw> {
pub realized_loss_30d: ComputedFromHeightLast<Dollars, M>,
pub realized_loss_1y: ComputedFromHeightLast<Dollars, M>,
// === Realized Profit to Loss Ratio (lazy from rolling sums) ===
pub realized_profit_to_loss_ratio_24h: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub realized_profit_to_loss_ratio_7d: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub realized_profit_to_loss_ratio_30d: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
pub realized_profit_to_loss_ratio_1y: LazyBinaryFromHeightLast<StoredF64, Dollars, Dollars>,
// === Realized Profit to Loss Ratio (from rolling sums) ===
pub realized_profit_to_loss_ratio_24h: ComputedFromHeightLast<StoredF64, M>,
pub realized_profit_to_loss_ratio_7d: ComputedFromHeightLast<StoredF64, M>,
pub realized_profit_to_loss_ratio_30d: ComputedFromHeightLast<StoredF64, M>,
pub realized_profit_to_loss_ratio_1y: ComputedFromHeightLast<StoredF64, M>,
}
impl RealizedExtended {
@@ -46,28 +46,6 @@ impl RealizedExtended {
};
}
let realized_profit_24h = import_rolling!("realized_profit_24h");
let realized_profit_7d = import_rolling!("realized_profit_7d");
let realized_profit_30d = import_rolling!("realized_profit_30d");
let realized_profit_1y = import_rolling!("realized_profit_1y");
let realized_loss_24h = import_rolling!("realized_loss_24h");
let realized_loss_7d = import_rolling!("realized_loss_7d");
let realized_loss_30d = import_rolling!("realized_loss_30d");
let realized_loss_1y = import_rolling!("realized_loss_1y");
let realized_profit_to_loss_ratio_24h = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("realized_profit_to_loss_ratio_24h"), cfg.version + v1, &realized_profit_24h, &realized_loss_24h,
);
let realized_profit_to_loss_ratio_7d = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("realized_profit_to_loss_ratio_7d"), cfg.version + v1, &realized_profit_7d, &realized_loss_7d,
);
let realized_profit_to_loss_ratio_30d = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("realized_profit_to_loss_ratio_30d"), cfg.version + v1, &realized_profit_30d, &realized_loss_30d,
);
let realized_profit_to_loss_ratio_1y = LazyBinaryFromHeightLast::from_computed_last::<Ratio64>(
&cfg.name("realized_profit_to_loss_ratio_1y"), cfg.version + v1, &realized_profit_1y, &realized_loss_1y,
);
Ok(RealizedExtended {
realized_cap_rel_to_own_market_cap: ComputedFromHeightLast::forced_import(
cfg.db,
@@ -75,18 +53,18 @@ impl RealizedExtended {
cfg.version,
cfg.indexes,
)?,
realized_profit_24h,
realized_profit_7d,
realized_profit_30d,
realized_profit_1y,
realized_loss_24h,
realized_loss_7d,
realized_loss_30d,
realized_loss_1y,
realized_profit_to_loss_ratio_24h,
realized_profit_to_loss_ratio_7d,
realized_profit_to_loss_ratio_30d,
realized_profit_to_loss_ratio_1y,
realized_profit_24h: import_rolling!("realized_profit_24h"),
realized_profit_7d: import_rolling!("realized_profit_7d"),
realized_profit_30d: import_rolling!("realized_profit_30d"),
realized_profit_1y: import_rolling!("realized_profit_1y"),
realized_loss_24h: import_rolling!("realized_loss_24h"),
realized_loss_7d: import_rolling!("realized_loss_7d"),
realized_loss_30d: import_rolling!("realized_loss_30d"),
realized_loss_1y: import_rolling!("realized_loss_1y"),
realized_profit_to_loss_ratio_24h: import_rolling!("realized_profit_to_loss_ratio_24h"),
realized_profit_to_loss_ratio_7d: import_rolling!("realized_profit_to_loss_ratio_7d"),
realized_profit_to_loss_ratio_30d: import_rolling!("realized_profit_to_loss_ratio_30d"),
realized_profit_to_loss_ratio_1y: import_rolling!("realized_profit_to_loss_ratio_1y"),
})
}
@@ -116,6 +94,20 @@ impl RealizedExtended {
exit,
)?;
// Realized profit to loss ratios
self.realized_profit_to_loss_ratio_24h.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height, &self.realized_profit_24h.height, &self.realized_loss_24h.height, exit,
)?;
self.realized_profit_to_loss_ratio_7d.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height, &self.realized_profit_7d.height, &self.realized_loss_7d.height, exit,
)?;
self.realized_profit_to_loss_ratio_30d.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height, &self.realized_profit_30d.height, &self.realized_loss_30d.height, exit,
)?;
self.realized_profit_to_loss_ratio_1y.compute_binary::<Dollars, Dollars, Ratio64>(
starting_indexes.height, &self.realized_profit_1y.height, &self.realized_loss_1y.height, exit,
)?;
Ok(())
}
}

View File

@@ -23,9 +23,9 @@ pub struct RealizedWithAdjusted<M: StorageMode = Rw> {
}
impl RealizedWithAdjusted {
pub(crate) fn forced_import(cfg: &ImportConfig, up_to_1h: &RealizedBase) -> Result<Self> {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let base = RealizedBase::forced_import(cfg)?;
let adjusted = RealizedAdjusted::forced_import(cfg, &base, up_to_1h)?;
let adjusted = RealizedAdjusted::forced_import(cfg)?;
Ok(Self { base, adjusted })
}
@@ -37,6 +37,8 @@ impl RealizedWithAdjusted {
starting_indexes: &ComputeIndexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base.compute_rest_part2_base(
@@ -51,6 +53,10 @@ impl RealizedWithAdjusted {
self.adjusted.compute_rest_part2_adj(
blocks,
starting_indexes,
&self.base.value_created.height,
&self.base.value_destroyed.height,
up_to_1h_value_created,
up_to_1h_value_destroyed,
exit,
)?;

View File

@@ -25,10 +25,10 @@ pub struct RealizedWithExtendedAdjusted<M: StorageMode = Rw> {
}
impl RealizedWithExtendedAdjusted {
pub(crate) fn forced_import(cfg: &ImportConfig, up_to_1h: &RealizedBase) -> Result<Self> {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let base = RealizedBase::forced_import(cfg)?;
let extended = RealizedExtended::forced_import(cfg)?;
let adjusted = RealizedAdjusted::forced_import(cfg, &base, up_to_1h)?;
let adjusted = RealizedAdjusted::forced_import(cfg)?;
Ok(Self {
base,
extended,
@@ -44,6 +44,8 @@ impl RealizedWithExtendedAdjusted {
starting_indexes: &ComputeIndexes,
height_to_supply: &impl ReadableVec<Height, Bitcoin>,
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_created: &impl ReadableVec<Height, Dollars>,
up_to_1h_value_destroyed: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base.compute_rest_part2_base(
@@ -66,6 +68,10 @@ impl RealizedWithExtendedAdjusted {
self.adjusted.compute_rest_part2_adj(
blocks,
starting_indexes,
&self.base.value_created.height,
&self.base.value_destroyed.height,
up_to_1h_value_created,
up_to_1h_value_destroyed,
exit,
)?;

View File

@@ -1,131 +1,117 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Sats, StoredF32, StoredF64, Version};
use brk_types::{Dollars, Height, Sats, StoredF32, StoredF64, Version};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::{
LazyBinaryComputedFromHeightLast, LazyBinaryFromHeightLast, LazyFromHeightLast,
ComputedFromHeightLast,
NegPercentageDollarsF32, PercentageDollarsF32, PercentageSatsF64,
};
use crate::distribution::metrics::{ImportConfig, SupplyMetrics, UnrealizedBase};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
/// Base relative metrics (always computed when relative is enabled).
/// All fields are non-Optional - market_cap and realized_cap are always
/// available when relative metrics are enabled.
#[derive(Clone, Traversable)]
pub struct RelativeBase {
#[derive(Traversable)]
pub struct RelativeBase<M: StorageMode = Rw> {
// === Supply in Profit/Loss Relative to Own Supply ===
pub supply_in_profit_rel_to_own_supply: LazyBinaryFromHeightLast<StoredF64, Sats, Sats>,
pub supply_in_loss_rel_to_own_supply: LazyBinaryFromHeightLast<StoredF64, Sats, Sats>,
pub supply_in_profit_rel_to_own_supply: ComputedFromHeightLast<StoredF64, M>,
pub supply_in_loss_rel_to_own_supply: ComputedFromHeightLast<StoredF64, M>,
// === Unrealized vs Market Cap ===
pub unrealized_profit_rel_to_market_cap: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub unrealized_loss_rel_to_market_cap: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub neg_unrealized_loss_rel_to_market_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub net_unrealized_pnl_rel_to_market_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub nupl: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub unrealized_profit_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub unrealized_loss_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub neg_unrealized_loss_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub net_unrealized_pnl_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub nupl: ComputedFromHeightLast<StoredF32, M>,
// === Invested Capital in Profit/Loss as % of Realized Cap ===
pub invested_capital_in_profit_pct: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub invested_capital_in_loss_pct: LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
pub invested_capital_in_profit_pct: ComputedFromHeightLast<StoredF32, M>,
pub invested_capital_in_loss_pct: ComputedFromHeightLast<StoredF32, M>,
}
impl RelativeBase {
/// Import base relative metrics.
///
/// `market_cap` is either `all_supply.total.usd` (for non-"all" cohorts)
/// or `supply.total.usd` (for the "all" cohort itself).
pub(crate) fn forced_import(
cfg: &ImportConfig,
unrealized: &UnrealizedBase,
supply: &SupplyMetrics,
market_cap: &LazyBinaryComputedFromHeightLast<Dollars, Sats, Dollars>,
realized_cap: &LazyFromHeightLast<Dollars, Cents>,
) -> Self {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v1 = Version::ONE;
let v2 = Version::new(2);
Self {
supply_in_profit_rel_to_own_supply:
LazyBinaryFromHeightLast::from_computed_last::<PercentageSatsF64>(
&cfg.name("supply_in_profit_rel_to_own_supply"),
cfg.version + v1,
&unrealized.supply_in_profit.sats,
&supply.total.sats,
),
supply_in_loss_rel_to_own_supply:
LazyBinaryFromHeightLast::from_computed_last::<PercentageSatsF64>(
&cfg.name("supply_in_loss_rel_to_own_supply"),
cfg.version + v1,
&unrealized.supply_in_loss.sats,
&supply.total.sats,
),
Ok(Self {
supply_in_profit_rel_to_own_supply: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("supply_in_profit_rel_to_own_supply"), cfg.version + v1, cfg.indexes,
)?,
supply_in_loss_rel_to_own_supply: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("supply_in_loss_rel_to_own_supply"), cfg.version + v1, cfg.indexes,
)?,
unrealized_profit_rel_to_market_cap: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("unrealized_profit_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
)?,
unrealized_loss_rel_to_market_cap: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
)?,
neg_unrealized_loss_rel_to_market_cap: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("neg_unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
)?,
net_unrealized_pnl_rel_to_market_cap: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("net_unrealized_pnl_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
)?,
nupl: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("nupl"), cfg.version + v2, cfg.indexes,
)?,
invested_capital_in_profit_pct: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("invested_capital_in_profit_pct"), cfg.version, cfg.indexes,
)?,
invested_capital_in_loss_pct: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("invested_capital_in_loss_pct"), cfg.version, cfg.indexes,
)?,
})
}
unrealized_profit_rel_to_market_cap:
LazyBinaryFromHeightLast::from_block_last_and_lazy_binary_computed_block_last::<
PercentageDollarsF32, _, _,
>(
&cfg.name("unrealized_profit_rel_to_market_cap"),
cfg.version + v2,
&unrealized.unrealized_profit,
market_cap,
),
unrealized_loss_rel_to_market_cap:
LazyBinaryFromHeightLast::from_block_last_and_lazy_binary_computed_block_last::<
PercentageDollarsF32, _, _,
>(
&cfg.name("unrealized_loss_rel_to_market_cap"),
cfg.version + v2,
&unrealized.unrealized_loss,
market_cap,
),
neg_unrealized_loss_rel_to_market_cap:
LazyBinaryFromHeightLast::from_block_last_and_lazy_binary_computed_block_last::<
NegPercentageDollarsF32, _, _,
>(
&cfg.name("neg_unrealized_loss_rel_to_market_cap"),
cfg.version + v2,
&unrealized.unrealized_loss,
market_cap,
),
net_unrealized_pnl_rel_to_market_cap:
LazyBinaryFromHeightLast::from_binary_block_and_lazy_binary_block_last::<
PercentageDollarsF32, _, _, _, _,
>(
&cfg.name("net_unrealized_pnl_rel_to_market_cap"),
cfg.version + v2,
&unrealized.net_unrealized_pnl,
market_cap,
),
nupl:
LazyBinaryFromHeightLast::from_binary_block_and_lazy_binary_block_last::<
PercentageDollarsF32, _, _, _, _,
>(
&cfg.name("nupl"),
cfg.version + v2,
&unrealized.net_unrealized_pnl,
market_cap,
),
invested_capital_in_profit_pct:
LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<
PercentageDollarsF32, _,
>(
&cfg.name("invested_capital_in_profit_pct"),
cfg.version,
&unrealized.invested_capital_in_profit,
realized_cap,
),
invested_capital_in_loss_pct:
LazyBinaryFromHeightLast::from_block_last_and_lazy_block_last::<
PercentageDollarsF32, _,
>(
&cfg.name("invested_capital_in_loss_pct"),
cfg.version,
&unrealized.invested_capital_in_loss,
realized_cap,
),
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.supply_in_profit_rel_to_own_supply
.compute_binary::<Sats, Sats, PercentageSatsF64>(
max_from, &unrealized.supply_in_profit.sats.height, supply_total_sats, exit,
)?;
self.supply_in_loss_rel_to_own_supply
.compute_binary::<Sats, Sats, PercentageSatsF64>(
max_from, &unrealized.supply_in_loss.sats.height, supply_total_sats, exit,
)?;
self.unrealized_profit_rel_to_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.unrealized_profit.height, market_cap, exit,
)?;
self.unrealized_loss_rel_to_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.unrealized_loss.height, market_cap, exit,
)?;
self.neg_unrealized_loss_rel_to_market_cap
.compute_binary::<Dollars, Dollars, NegPercentageDollarsF32>(
max_from, &unrealized.unrealized_loss.height, market_cap, exit,
)?;
self.net_unrealized_pnl_rel_to_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.net_unrealized_pnl.height, market_cap, exit,
)?;
self.nupl
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.net_unrealized_pnl.height, market_cap, exit,
)?;
self.invested_capital_in_profit_pct
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.invested_capital_in_profit.height, &realized.realized_cap.height, exit,
)?;
self.invested_capital_in_loss_pct
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.invested_capital_in_loss.height, &realized.realized_cap.height, exit,
)?;
Ok(())
}
}

View File

@@ -1,71 +1,88 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Sats, StoredF32, Version};
use brk_types::{Dollars, Height, StoredF32};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::{
LazyBinaryComputedFromHeightLast, LazyBinaryFromHeightLast,
NegPercentageDollarsF32, PercentageDollarsF32,
ComputedFromHeightLast, NegPercentageDollarsF32, PercentageDollarsF32,
};
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
/// Extended relative metrics for own market cap (extended && rel_to_all).
#[derive(Clone, Traversable)]
pub struct RelativeExtendedOwnMarketCap {
#[derive(Traversable)]
pub struct RelativeExtendedOwnMarketCap<M: StorageMode = Rw> {
pub unrealized_profit_rel_to_own_market_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
pub unrealized_loss_rel_to_own_market_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
pub neg_unrealized_loss_rel_to_own_market_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
pub net_unrealized_pnl_rel_to_own_market_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
}
impl RelativeExtendedOwnMarketCap {
pub(crate) fn forced_import(
cfg: &ImportConfig,
unrealized: &UnrealizedBase,
own_market_cap: &LazyBinaryComputedFromHeightLast<Dollars, Sats, Dollars>,
) -> Self {
let v2 = Version::new(2);
) -> Result<Self> {
let v2 = brk_types::Version::new(2);
Self {
Ok(Self {
unrealized_profit_rel_to_own_market_cap:
LazyBinaryFromHeightLast::from_block_last_and_lazy_binary_computed_block_last::<
PercentageDollarsF32, _, _,
>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("unrealized_profit_rel_to_own_market_cap"),
cfg.version + v2,
&unrealized.unrealized_profit,
own_market_cap,
),
cfg.indexes,
)?,
unrealized_loss_rel_to_own_market_cap:
LazyBinaryFromHeightLast::from_block_last_and_lazy_binary_computed_block_last::<
PercentageDollarsF32, _, _,
>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("unrealized_loss_rel_to_own_market_cap"),
cfg.version + v2,
&unrealized.unrealized_loss,
own_market_cap,
),
cfg.indexes,
)?,
neg_unrealized_loss_rel_to_own_market_cap:
LazyBinaryFromHeightLast::from_block_last_and_lazy_binary_computed_block_last::<
NegPercentageDollarsF32, _, _,
>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("neg_unrealized_loss_rel_to_own_market_cap"),
cfg.version + v2,
&unrealized.unrealized_loss,
own_market_cap,
),
cfg.indexes,
)?,
net_unrealized_pnl_rel_to_own_market_cap:
LazyBinaryFromHeightLast::from_binary_block_and_lazy_binary_block_last::<
PercentageDollarsF32, _, _, _, _,
>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("net_unrealized_pnl_rel_to_own_market_cap"),
cfg.version + v2,
&unrealized.net_unrealized_pnl,
own_market_cap,
),
}
cfg.indexes,
)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
own_market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.unrealized_profit_rel_to_own_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.unrealized_profit.height, own_market_cap, exit,
)?;
self.unrealized_loss_rel_to_own_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.unrealized_loss.height, own_market_cap, exit,
)?;
self.neg_unrealized_loss_rel_to_own_market_cap
.compute_binary::<Dollars, Dollars, NegPercentageDollarsF32>(
max_from, &unrealized.unrealized_loss.height, own_market_cap, exit,
)?;
self.net_unrealized_pnl_rel_to_own_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.net_unrealized_pnl.height, own_market_cap, exit,
)?;
Ok(())
}
}

View File

@@ -1,62 +1,88 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, StoredF32, Version};
use brk_types::{Dollars, Height, StoredF32};
use vecdb::{Exit, Rw, StorageMode};
use crate::internal::{
LazyBinaryFromHeightLast, NegPercentageDollarsF32, PercentageDollarsF32,
ComputedFromHeightLast, NegPercentageDollarsF32, PercentageDollarsF32,
};
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
/// Extended relative metrics for own total unrealized PnL (extended only).
#[derive(Clone, Traversable)]
pub struct RelativeExtendedOwnPnl {
#[derive(Traversable)]
pub struct RelativeExtendedOwnPnl<M: StorageMode = Rw> {
pub unrealized_profit_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
pub unrealized_loss_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
pub neg_unrealized_loss_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
pub net_unrealized_pnl_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
}
impl RelativeExtendedOwnPnl {
pub(crate) fn forced_import(
cfg: &ImportConfig,
unrealized: &UnrealizedBase,
) -> Self {
let v1 = Version::ONE;
let v2 = Version::new(2);
) -> Result<Self> {
let v1 = brk_types::Version::ONE;
let v2 = brk_types::Version::new(2);
Self {
Ok(Self {
unrealized_profit_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast::from_block_last_and_binary_block::<PercentageDollarsF32, _, _>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("unrealized_profit_rel_to_own_total_unrealized_pnl"),
cfg.version + v1,
&unrealized.unrealized_profit,
&unrealized.total_unrealized_pnl,
),
cfg.indexes,
)?,
unrealized_loss_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast::from_block_last_and_binary_block::<PercentageDollarsF32, _, _>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("unrealized_loss_rel_to_own_total_unrealized_pnl"),
cfg.version + v1,
&unrealized.unrealized_loss,
&unrealized.total_unrealized_pnl,
),
cfg.indexes,
)?,
neg_unrealized_loss_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast::from_block_last_and_binary_block::<NegPercentageDollarsF32, _, _>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("neg_unrealized_loss_rel_to_own_total_unrealized_pnl"),
cfg.version + v1,
&unrealized.unrealized_loss,
&unrealized.total_unrealized_pnl,
),
cfg.indexes,
)?,
net_unrealized_pnl_rel_to_own_total_unrealized_pnl:
LazyBinaryFromHeightLast::from_both_binary_block::<PercentageDollarsF32, _, _, _, _>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("net_unrealized_pnl_rel_to_own_total_unrealized_pnl"),
cfg.version + v2,
&unrealized.net_unrealized_pnl,
&unrealized.total_unrealized_pnl,
),
}
cfg.indexes,
)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
exit: &Exit,
) -> Result<()> {
self.unrealized_profit_rel_to_own_total_unrealized_pnl
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.unrealized_profit.height, &unrealized.total_unrealized_pnl.height, exit,
)?;
self.unrealized_loss_rel_to_own_total_unrealized_pnl
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.unrealized_loss.height, &unrealized.total_unrealized_pnl.height, exit,
)?;
self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl
.compute_binary::<Dollars, Dollars, NegPercentageDollarsF32>(
max_from, &unrealized.unrealized_loss.height, &unrealized.total_unrealized_pnl.height, exit,
)?;
self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.net_unrealized_pnl.height, &unrealized.total_unrealized_pnl.height, exit,
)?;
Ok(())
}
}

View File

@@ -1,43 +1,58 @@
use brk_types::Dollars;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::ComputedFromHeightLast;
use crate::distribution::metrics::{ImportConfig, RealizedBase, SupplyMetrics, UnrealizedBase};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
use super::{RelativeBase, RelativeExtendedOwnPnl, RelativePeakRegret};
/// Relative metrics for the "all" cohort (base + own_pnl + peak_regret, NO rel_to_all).
#[derive(Clone, Deref, DerefMut, Traversable)]
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct RelativeForAll {
pub struct RelativeForAll<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase,
pub base: RelativeBase<M>,
#[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl,
pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
#[traversable(flatten)]
pub peak_regret: RelativePeakRegret,
pub peak_regret: RelativePeakRegret<M>,
}
impl RelativeForAll {
pub(crate) fn forced_import(
cfg: &ImportConfig,
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeBase::forced_import(cfg)?,
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg)?,
peak_regret: RelativePeakRegret::forced_import(cfg)?,
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
supply: &SupplyMetrics,
realized_base: &RealizedBase,
peak_regret: &ComputedFromHeightLast<Dollars>,
) -> Self {
// For the "all" cohort, market_cap = own market cap
let market_cap = &supply.total.usd;
Self {
base: RelativeBase::forced_import(
cfg, unrealized, supply, market_cap, &realized_base.realized_cap,
),
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg, unrealized),
peak_regret: RelativePeakRegret::forced_import(cfg, peak_regret, market_cap),
}
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
peak_regret_val: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base.compute(
max_from,
unrealized,
realized,
supply_total_sats,
market_cap,
exit,
)?;
self.extended_own_pnl.compute(max_from, unrealized, exit)?;
self.peak_regret
.compute(max_from, peak_regret_val, market_cap, exit)?;
Ok(())
}
}

View File

@@ -1,36 +1,46 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Sats, StoredF32};
use brk_types::{Dollars, Height, StoredF32};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::{
ComputedFromHeightLast, LazyBinaryComputedFromHeightLast, LazyBinaryFromHeightLast,
PercentageDollarsF32,
ComputedFromHeightLast, PercentageDollarsF32,
};
use crate::distribution::metrics::ImportConfig;
/// Peak regret relative metric.
#[derive(Clone, Traversable)]
pub struct RelativePeakRegret {
#[derive(Traversable)]
pub struct RelativePeakRegret<M: StorageMode = Rw> {
pub unrealized_peak_regret_rel_to_market_cap:
LazyBinaryFromHeightLast<StoredF32, Dollars, Dollars>,
ComputedFromHeightLast<StoredF32, M>,
}
impl RelativePeakRegret {
pub(crate) fn forced_import(
cfg: &ImportConfig,
peak_regret: &ComputedFromHeightLast<Dollars>,
market_cap: &LazyBinaryComputedFromHeightLast<Dollars, Sats, Dollars>,
) -> Self {
Self {
) -> Result<Self> {
Ok(Self {
unrealized_peak_regret_rel_to_market_cap:
LazyBinaryFromHeightLast::from_block_last_and_lazy_binary_computed_block_last::<
PercentageDollarsF32, _, _,
>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("unrealized_peak_regret_rel_to_market_cap"),
cfg.version,
peak_regret,
market_cap,
),
}
cfg.indexes,
)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
peak_regret: &impl ReadableVec<Height, Dollars>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.unrealized_peak_regret_rel_to_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, peak_regret, market_cap, exit,
)
}
}

View File

@@ -1,53 +1,72 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Sats, StoredF64, Version};
use brk_types::{Height, Sats, StoredF64};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::{LazyBinaryFromHeightLast, PercentageSatsF64};
use crate::internal::{ComputedFromHeightLast, PercentageSatsF64};
use crate::distribution::metrics::{ImportConfig, SupplyMetrics, UnrealizedBase};
use crate::distribution::metrics::{ImportConfig, UnrealizedBase};
/// Relative-to-all metrics (not present for the "all" cohort itself).
#[derive(Clone, Traversable)]
pub struct RelativeToAll {
#[derive(Traversable)]
pub struct RelativeToAll<M: StorageMode = Rw> {
pub supply_rel_to_circulating_supply:
LazyBinaryFromHeightLast<StoredF64, Sats, Sats>,
ComputedFromHeightLast<StoredF64, M>,
pub supply_in_profit_rel_to_circulating_supply:
LazyBinaryFromHeightLast<StoredF64, Sats, Sats>,
ComputedFromHeightLast<StoredF64, M>,
pub supply_in_loss_rel_to_circulating_supply:
LazyBinaryFromHeightLast<StoredF64, Sats, Sats>,
ComputedFromHeightLast<StoredF64, M>,
}
impl RelativeToAll {
pub(crate) fn forced_import(
cfg: &ImportConfig,
unrealized: &UnrealizedBase,
supply: &SupplyMetrics,
all_supply: &SupplyMetrics,
) -> Self {
let v1 = Version::ONE;
let gs = &all_supply.total.sats;
Self {
) -> Result<Self> {
Ok(Self {
supply_rel_to_circulating_supply:
LazyBinaryFromHeightLast::from_computed_last::<PercentageSatsF64>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("supply_rel_to_circulating_supply"),
cfg.version + v1,
&supply.total.sats,
gs,
),
cfg.version + brk_types::Version::ONE,
cfg.indexes,
)?,
supply_in_profit_rel_to_circulating_supply:
LazyBinaryFromHeightLast::from_computed_last::<PercentageSatsF64>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("supply_in_profit_rel_to_circulating_supply"),
cfg.version + v1,
&unrealized.supply_in_profit.sats,
gs,
),
cfg.version + brk_types::Version::ONE,
cfg.indexes,
)?,
supply_in_loss_rel_to_circulating_supply:
LazyBinaryFromHeightLast::from_computed_last::<PercentageSatsF64>(
ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("supply_in_loss_rel_to_circulating_supply"),
cfg.version + v1,
&unrealized.supply_in_loss.sats,
gs,
),
}
cfg.version + brk_types::Version::ONE,
cfg.indexes,
)?,
})
}
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.supply_rel_to_circulating_supply
.compute_binary::<Sats, Sats, PercentageSatsF64>(
max_from, supply_total_sats, all_supply_sats, exit,
)?;
self.supply_in_profit_rel_to_circulating_supply
.compute_binary::<Sats, Sats, PercentageSatsF64>(
max_from, &unrealized.supply_in_profit.sats.height, all_supply_sats, exit,
)?;
self.supply_in_loss_rel_to_circulating_supply
.compute_binary::<Sats, Sats, PercentageSatsF64>(
max_from, &unrealized.supply_in_loss.sats.height, all_supply_sats, exit,
)?;
Ok(())
}
}

View File

@@ -1,10 +1,10 @@
use brk_types::Dollars;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::ComputedFromHeightLast;
use crate::distribution::metrics::{ImportConfig, RealizedBase, SupplyMetrics, UnrealizedBase};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
use super::{
RelativeBase, RelativeExtendedOwnMarketCap, RelativeExtendedOwnPnl,
@@ -13,44 +13,52 @@ use super::{
/// Full extended relative metrics (base + rel_to_all + own_market_cap + own_pnl + peak_regret).
/// Used by: sth, lth, age_range cohorts.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct RelativeWithExtended {
pub struct RelativeWithExtended<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase,
pub base: RelativeBase<M>,
#[traversable(flatten)]
pub rel_to_all: RelativeToAll,
pub rel_to_all: RelativeToAll<M>,
#[traversable(flatten)]
pub extended_own_market_cap: RelativeExtendedOwnMarketCap,
pub extended_own_market_cap: RelativeExtendedOwnMarketCap<M>,
#[traversable(flatten)]
pub extended_own_pnl: RelativeExtendedOwnPnl,
pub extended_own_pnl: RelativeExtendedOwnPnl<M>,
#[traversable(flatten)]
pub peak_regret: RelativePeakRegret,
pub peak_regret: RelativePeakRegret<M>,
}
impl RelativeWithExtended {
pub(crate) fn forced_import(
cfg: &ImportConfig,
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeBase::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)?,
peak_regret: RelativePeakRegret::forced_import(cfg)?,
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
supply: &SupplyMetrics,
all_supply: &SupplyMetrics,
realized_base: &RealizedBase,
peak_regret: &ComputedFromHeightLast<Dollars>,
) -> Self {
let market_cap = &all_supply.total.usd;
let own_market_cap = &supply.total.usd;
Self {
base: RelativeBase::forced_import(
cfg, unrealized, supply, market_cap, &realized_base.realized_cap,
),
rel_to_all: RelativeToAll::forced_import(cfg, unrealized, supply, all_supply),
extended_own_market_cap: RelativeExtendedOwnMarketCap::forced_import(
cfg, unrealized, own_market_cap,
),
extended_own_pnl: RelativeExtendedOwnPnl::forced_import(cfg, unrealized),
peak_regret: RelativePeakRegret::forced_import(cfg, peak_regret, market_cap),
}
realized: &RealizedBase,
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>,
peak_regret_val: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base.compute(max_from, unrealized, realized, supply_total_sats, market_cap, exit)?;
self.rel_to_all.compute(max_from, unrealized, supply_total_sats, all_supply_sats, exit)?;
self.extended_own_market_cap.compute(max_from, unrealized, own_market_cap, exit)?;
self.extended_own_pnl.compute(max_from, unrealized, exit)?;
self.peak_regret.compute(max_from, peak_regret_val, market_cap, exit)?;
Ok(())
}
}

View File

@@ -1,44 +1,66 @@
use brk_types::Dollars;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::internal::ComputedFromHeightLast;
use crate::distribution::metrics::{ImportConfig, RealizedBase, SupplyMetrics, UnrealizedBase};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
use super::{RelativeBase, RelativePeakRegret, RelativeToAll};
/// Relative metrics with rel_to_all + peak_regret (no extended).
/// Used by: max_age, min_age cohorts.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct RelativeWithPeakRegret {
pub struct RelativeWithPeakRegret<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase,
pub base: RelativeBase<M>,
#[traversable(flatten)]
pub rel_to_all: RelativeToAll,
pub rel_to_all: RelativeToAll<M>,
#[traversable(flatten)]
pub peak_regret: RelativePeakRegret,
pub peak_regret: RelativePeakRegret<M>,
}
impl RelativeWithPeakRegret {
pub(crate) fn forced_import(
cfg: &ImportConfig,
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeBase::forced_import(cfg)?,
rel_to_all: RelativeToAll::forced_import(cfg)?,
peak_regret: RelativePeakRegret::forced_import(cfg)?,
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
supply: &SupplyMetrics,
all_supply: &SupplyMetrics,
realized_base: &RealizedBase,
peak_regret: &ComputedFromHeightLast<Dollars>,
) -> Self {
let market_cap = &all_supply.total.usd;
Self {
base: RelativeBase::forced_import(
cfg, unrealized, supply, market_cap, &realized_base.realized_cap,
),
rel_to_all: RelativeToAll::forced_import(cfg, unrealized, supply, all_supply),
peak_regret: RelativePeakRegret::forced_import(cfg, peak_regret, market_cap),
}
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
peak_regret_val: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
self.base.compute(
max_from,
unrealized,
realized,
supply_total_sats,
market_cap,
exit,
)?;
self.rel_to_all.compute(
max_from,
unrealized,
supply_total_sats,
all_supply_sats,
exit,
)?;
self.peak_regret
.compute(max_from, peak_regret_val, market_cap, exit)?;
Ok(())
}
}

View File

@@ -1,37 +1,60 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats};
use derive_more::{Deref, DerefMut};
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
use crate::distribution::metrics::{ImportConfig, RealizedBase, SupplyMetrics, UnrealizedBase};
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
use super::{RelativeBase, RelativeToAll};
/// Relative metrics with rel_to_all (no extended, no peak_regret).
/// Used by: epoch, year, type, amount, address cohorts.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[derive(Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct RelativeWithRelToAll {
pub struct RelativeWithRelToAll<M: StorageMode = Rw> {
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub base: RelativeBase,
pub base: RelativeBase<M>,
#[traversable(flatten)]
pub rel_to_all: RelativeToAll,
pub rel_to_all: RelativeToAll<M>,
}
impl RelativeWithRelToAll {
pub(crate) fn forced_import(
cfg: &ImportConfig,
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
Ok(Self {
base: RelativeBase::forced_import(cfg)?,
rel_to_all: RelativeToAll::forced_import(cfg)?,
})
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute(
&mut self,
max_from: Height,
unrealized: &UnrealizedBase,
supply: &SupplyMetrics,
all_supply: &SupplyMetrics,
realized_base: &RealizedBase,
) -> Self {
let market_cap = &all_supply.total.usd;
Self {
base: RelativeBase::forced_import(
cfg, unrealized, supply, market_cap, &realized_base.realized_cap,
),
rel_to_all: RelativeToAll::forced_import(cfg, unrealized, supply, all_supply),
}
realized: &RealizedBase,
supply_total_sats: &impl ReadableVec<Height, Sats>,
market_cap: &impl ReadableVec<Height, Dollars>,
all_supply_sats: &impl ReadableVec<Height, Sats>,
exit: &Exit,
) -> Result<()> {
self.base.compute(
max_from,
unrealized,
realized,
supply_total_sats,
market_cap,
exit,
)?;
self.rel_to_all.compute(
max_from,
unrealized,
supply_total_sats,
all_supply_sats,
exit,
)?;
Ok(())
}
}

View File

@@ -2,13 +2,13 @@ use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Sats, Version};
use crate::{ComputeIndexes, blocks};
use crate::{ComputeIndexes, blocks, prices};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
use crate::internal::{
HalfPriceTimesSats, HalveDollars, HalveSats, HalveSatsToBitcoin,
LazyBinaryValueFromHeightLast, ValueChangeFromHeight, ValueFromHeightLast,
HalveDollars, HalveSats, HalveSatsToBitcoin,
LazyValueFromHeightLast, ValueChangeFromHeight, ValueFromHeightLast,
};
use super::ImportConfig;
@@ -17,7 +17,7 @@ use super::ImportConfig;
#[derive(Traversable)]
pub struct SupplyMetrics<M: StorageMode = Rw> {
pub total: ValueFromHeightLast<M>,
pub halved: LazyBinaryValueFromHeightLast,
pub halved: LazyValueFromHeightLast,
/// 30-day change in supply (net position change) - sats, btc, usd
pub _30d_change: ValueChangeFromHeight<M>,
}
@@ -30,15 +30,13 @@ impl SupplyMetrics {
&cfg.name("supply"),
cfg.version,
cfg.indexes,
cfg.prices,
)?;
let supply_halved = LazyBinaryValueFromHeightLast::from_block_source::<
let supply_halved = LazyValueFromHeightLast::from_block_source::<
HalveSats,
HalveSatsToBitcoin,
HalfPriceTimesSats,
HalveDollars,
>(&cfg.name("supply_halved"), &supply, cfg.prices, cfg.version);
>(&cfg.name("supply_halved"), &supply, cfg.version);
let _30d_change = ValueChangeFromHeight::forced_import(
cfg.db,
@@ -67,7 +65,21 @@ impl SupplyMetrics {
/// Returns a parallel iterator over all vecs for parallel writing.
pub(crate) fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
vec![&mut self.total.sats.height as &mut dyn AnyStoredVec].into_par_iter()
vec![
&mut self.total.sats.height as &mut dyn AnyStoredVec,
&mut self.total.usd.height as &mut dyn AnyStoredVec,
]
.into_par_iter()
}
/// Eagerly compute USD height values from sats × price.
pub(crate) fn compute(
&mut self,
prices: &prices::Vecs,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.total.compute(prices, max_from, exit)
}
/// Validate computed versions against base version.

View File

@@ -10,8 +10,7 @@ use crate::{
ComputeIndexes,
distribution::state::UnrealizedState,
internal::{
ComputedFromHeightLast, DollarsMinus, DollarsPlus, LazyBinaryFromHeightLast,
LazyFromHeightLast, ValueFromHeightLast,
ComputedFromHeightLast, LazyFromHeightLast, ValueFromHeightLast,
},
prices,
};
@@ -48,8 +47,8 @@ pub struct UnrealizedBase<M: StorageMode = Rw> {
pub neg_unrealized_loss: LazyFromHeightLast<Dollars>,
// === Net and Total ===
pub net_unrealized_pnl: LazyBinaryFromHeightLast<Dollars>,
pub total_unrealized_pnl: LazyBinaryFromHeightLast<Dollars>,
pub net_unrealized_pnl: ComputedFromHeightLast<Dollars, M>,
pub total_unrealized_pnl: ComputedFromHeightLast<Dollars, M>,
}
impl UnrealizedBase {
@@ -59,14 +58,12 @@ impl UnrealizedBase {
&cfg.name("supply_in_profit"),
cfg.version,
cfg.indexes,
cfg.prices,
)?;
let supply_in_loss = ValueFromHeightLast::forced_import(
cfg.db,
&cfg.name("supply_in_loss"),
cfg.version,
cfg.indexes,
cfg.prices,
)?;
let unrealized_profit = ComputedFromHeightLast::forced_import(
@@ -142,18 +139,18 @@ impl UnrealizedBase {
&unrealized_loss,
);
let net_unrealized_pnl = LazyBinaryFromHeightLast::from_computed_last::<DollarsMinus>(
let net_unrealized_pnl = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("net_unrealized_pnl"),
cfg.version,
&unrealized_profit,
&unrealized_loss,
);
let total_unrealized_pnl = LazyBinaryFromHeightLast::from_computed_last::<DollarsPlus>(
cfg.indexes,
)?;
let total_unrealized_pnl = ComputedFromHeightLast::forced_import(
cfg.db,
&cfg.name("total_unrealized_pnl"),
cfg.version,
&unrealized_profit,
&unrealized_loss,
);
cfg.indexes,
)?;
Ok(Self {
supply_in_profit,
@@ -240,7 +237,9 @@ impl UnrealizedBase {
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_loss.sats.height,
&mut self.supply_in_profit.usd.height as &mut dyn AnyStoredVec,
&mut self.supply_in_loss.sats.height as &mut dyn AnyStoredVec,
&mut self.supply_in_loss.usd.height as &mut dyn AnyStoredVec,
&mut self.unrealized_profit.height,
&mut self.unrealized_loss.height,
&mut self.invested_capital_in_profit.height,
@@ -419,6 +418,19 @@ impl UnrealizedBase {
exit,
)?;
self.net_unrealized_pnl.height.compute_subtract(
starting_indexes.height,
&self.unrealized_profit.height,
&self.unrealized_loss.height,
exit,
)?;
self.total_unrealized_pnl.height.compute_add(
starting_indexes.height,
&self.unrealized_profit.height,
&self.unrealized_loss.height,
exit,
)?;
Ok(())
}

View File

@@ -9,8 +9,8 @@ use brk_types::{
};
use tracing::{debug, info};
use vecdb::{
AnyVec, BytesVec, Database, Exit, WritableVec, ImportableVec, ReadableCloneableVec,
ReadableVec, Rw, StorageMode, LazyVecFrom1, PAGE_SIZE, Stamp,
AnyVec, BytesVec, Database, Exit, ImportableVec, LazyVecFrom1, PAGE_SIZE, ReadOnlyClone,
ReadableCloneableVec, ReadableVec, Rw, Stamp, StorageMode, WritableVec,
};
use crate::{
@@ -50,12 +50,12 @@ pub struct Vecs<M: StorageMode = Rw> {
pub empty_addr_count: AddrCountsVecs<M>,
pub address_activity: AddressActivityVecs<M>,
/// Total addresses ever seen (addr_count + empty_addr_count) - lazy, global + per-type
pub total_addr_count: TotalAddrCountVecs,
/// Total addresses ever seen (addr_count + empty_addr_count) - stored, global + per-type
pub total_addr_count: TotalAddrCountVecs<M>,
/// New addresses per block (delta of total) - lazy height, stored day1 stats, global + per-type
pub new_addr_count: NewAddrCountVecs<M>,
/// Growth rate (new / addr_count) - lazy ratio with distribution stats, global + per-type
pub growth_rate: GrowthRateVecs,
/// Growth rate (new / addr_count) - stored ratio with distribution stats, global + per-type
pub growth_rate: GrowthRateVecs<M>,
pub fundedaddressindex:
LazyVecFrom1<FundedAddressIndex, FundedAddressIndex, FundedAddressIndex, FundedAddressData>,
@@ -70,7 +70,6 @@ impl Vecs {
parent: &Path,
parent_version: Version,
indexes: &indexes::Vecs,
prices: &prices::Vecs,
) -> Result<Self> {
let db_path = parent.join(super::DB_NAME);
let states_path = db_path.join("states");
@@ -81,17 +80,9 @@ impl Vecs {
let version = parent_version + VERSION;
let utxo_cohorts = UTXOCohorts::forced_import(&db, version, indexes, prices, &states_path)?;
let utxo_cohorts = UTXOCohorts::forced_import(&db, version, indexes, &states_path)?;
// Create address cohorts with reference to utxo "all" cohort's supply for global ratios
let address_cohorts = AddressCohorts::forced_import(
&db,
version,
indexes,
prices,
&states_path,
&utxo_cohorts.all.metrics.supply,
)?;
let address_cohorts = AddressCohorts::forced_import(&db, version, indexes, &states_path)?;
// Create address data BytesVecs first so we can also use them for identity mappings
let fundedaddressindex_to_fundedaddressdata = BytesVec::forced_import_with(
@@ -123,21 +114,15 @@ impl Vecs {
let address_activity =
AddressActivityVecs::forced_import(&db, "address_activity", version, indexes)?;
// Lazy total = addr_count + empty_addr_count (global + per-type, with all derived indexes)
let total_addr_count = TotalAddrCountVecs::forced_import(
version,
indexes,
&addr_count,
&empty_addr_count,
)?;
// Stored total = addr_count + empty_addr_count (global + per-type, with all derived indexes)
let total_addr_count = TotalAddrCountVecs::forced_import(&db, version, indexes)?;
// Lazy delta of total (global + per-type)
let new_addr_count =
NewAddrCountVecs::forced_import(&db, version, indexes, &total_addr_count)?;
// Growth rate: new / addr_count (global + per-type)
let growth_rate =
GrowthRateVecs::forced_import(version, indexes, &new_addr_count, &addr_count)?;
let growth_rate = GrowthRateVecs::forced_import(&db, version, indexes)?;
let this = Self {
supply_state: BytesVec::forced_import_with(
@@ -359,14 +344,38 @@ impl Vecs {
self.empty_addr_count
.compute_rest(blocks, starting_indexes, exit)?;
// 6d. Compute new_addr_count cumulative (height is lazy delta)
// 6c. Compute total_addr_count = addr_count + empty_addr_count
self.total_addr_count.compute(
starting_indexes.height,
&self.addr_count,
&self.empty_addr_count,
exit,
)?;
// 6d. Compute new_addr_count cumulative + rolling (height is lazy delta)
let window_starts = blocks.count.window_starts();
self.new_addr_count
.compute_cumulative(starting_indexes, exit)?;
.compute(starting_indexes.height, &window_starts, exit)?;
// 6e. Compute growth_rate = new_addr_count / addr_count
self.growth_rate.compute(
starting_indexes.height,
&window_starts,
&self.new_addr_count,
&self.addr_count,
exit,
)?;
// 7. Compute rest part2 (relative metrics)
let supply_metrics = &self.utxo_cohorts.all.metrics.supply;
let height_to_market_cap = supply_metrics.total.usd.height.clone();
let height_to_market_cap = self
.utxo_cohorts
.all
.metrics
.supply
.total
.usd
.height
.read_only_clone();
aggregates::compute_rest_part2(
&mut self.utxo_cohorts,
@@ -400,5 +409,4 @@ impl Vecs {
.min(Height::from(self.empty_addr_count.min_stateful_height()))
.min(Height::from(self.address_activity.min_stateful_height()))
}
}