mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-02 02:20:00 -07:00
global: MASSIVE snapshot
This commit is contained in:
@@ -2,17 +2,14 @@ use brk_cohort::ByAddressType;
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, StoredU64, Version};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use rayon::prelude::*;
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, Database, EagerVec, Exit, GenericStoredVec, ImportableVec,
|
||||
IterableCloneableVec, PcoVec, TypedVecIterator,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, indexes,
|
||||
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
|
||||
};
|
||||
use crate::{ComputeIndexes, indexes, internal::DerivedComputedBlockLast};
|
||||
|
||||
/// Address count per address type (runtime state).
|
||||
#[derive(Debug, Default, Deref, DerefMut)]
|
||||
@@ -142,11 +139,13 @@ impl AddressTypeToHeightToAddressCount {
|
||||
|
||||
/// Address count per address type, indexed by various indexes (dateindex, etc.).
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
pub struct AddressTypeToIndexesToAddressCount(ByAddressType<ComputedVecsFromHeight<StoredU64>>);
|
||||
pub struct AddressTypeToIndexesToAddressCount(ByAddressType<DerivedComputedBlockLast<StoredU64>>);
|
||||
|
||||
impl From<ByAddressType<ComputedVecsFromHeight<StoredU64>>> for AddressTypeToIndexesToAddressCount {
|
||||
impl From<ByAddressType<DerivedComputedBlockLast<StoredU64>>>
|
||||
for AddressTypeToIndexesToAddressCount
|
||||
{
|
||||
#[inline]
|
||||
fn from(value: ByAddressType<ComputedVecsFromHeight<StoredU64>>) -> Self {
|
||||
fn from(value: ByAddressType<DerivedComputedBlockLast<StoredU64>>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
@@ -160,17 +159,16 @@ impl AddressTypeToIndexesToAddressCount {
|
||||
sources: &AddressTypeToHeightToAddressCount,
|
||||
) -> Result<Self> {
|
||||
Ok(Self::from(ByAddressType::<
|
||||
ComputedVecsFromHeight<StoredU64>,
|
||||
DerivedComputedBlockLast<StoredU64>,
|
||||
>::try_zip_with_name(
|
||||
sources,
|
||||
|type_name, source| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
DerivedComputedBlockLast::forced_import(
|
||||
db,
|
||||
&format!("{type_name}_{name}"),
|
||||
Source::Vec(source.boxed_clone()),
|
||||
source.boxed_clone(),
|
||||
version,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)
|
||||
},
|
||||
)?))
|
||||
@@ -183,53 +181,53 @@ impl AddressTypeToIndexesToAddressCount {
|
||||
exit: &Exit,
|
||||
addresstype_to_height_to_addresscount: &AddressTypeToHeightToAddressCount,
|
||||
) -> Result<()> {
|
||||
self.p2pk65.compute_rest(
|
||||
self.p2pk65.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2pk65,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2pk65),
|
||||
)?;
|
||||
self.p2pk33.compute_rest(
|
||||
self.p2pk33.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2pk33,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2pk33),
|
||||
)?;
|
||||
self.p2pkh.compute_rest(
|
||||
self.p2pkh.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2pkh,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2pkh),
|
||||
)?;
|
||||
self.p2sh.compute_rest(
|
||||
self.p2sh.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2sh,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2sh),
|
||||
)?;
|
||||
self.p2wpkh.compute_rest(
|
||||
self.p2wpkh.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2wpkh,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2wpkh),
|
||||
)?;
|
||||
self.p2wsh.compute_rest(
|
||||
self.p2wsh.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2wsh,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2wsh),
|
||||
)?;
|
||||
self.p2tr.compute_rest(
|
||||
self.p2tr.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2tr,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2tr),
|
||||
)?;
|
||||
self.p2a.compute_rest(
|
||||
self.p2a.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&addresstype_to_height_to_addresscount.p2a,
|
||||
exit,
|
||||
Some(&addresstype_to_height_to_addresscount.p2a),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_types::Height;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use super::vec::AddressTypeToVec;
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{collections::hash_map::Entry, mem};
|
||||
|
||||
use brk_cohort::ByAddressType;
|
||||
use brk_types::{OutputType, TypeIndex};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use rustc_hash::FxHashMap;
|
||||
use smallvec::{Array, SmallVec};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_cohort::ByAddressType;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
|
||||
/// A vector for each address type.
|
||||
#[derive(Debug, Deref, DerefMut)]
|
||||
|
||||
@@ -6,7 +6,7 @@ use brk_cohort::{
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{DateIndex, Dollars, Height, Version};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use rayon::prelude::*;
|
||||
use vecdb::{AnyStoredVec, Database, Exit, IterableVec};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::{
|
||||
ComputeIndexes,
|
||||
distribution::state::AddressCohortState,
|
||||
indexes,
|
||||
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
|
||||
internal::DerivedComputedBlockLast,
|
||||
price,
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ pub struct AddressCohortVecs {
|
||||
pub height_to_addr_count: EagerVec<PcoVec<Height, StoredU64>>,
|
||||
|
||||
/// Address count indexed by various dimensions
|
||||
pub indexes_to_addr_count: ComputedVecsFromHeight<StoredU64>,
|
||||
pub indexes_to_addr_count: DerivedComputedBlockLast<StoredU64>,
|
||||
}
|
||||
|
||||
impl AddressCohortVecs {
|
||||
@@ -86,13 +86,12 @@ impl AddressCohortVecs {
|
||||
|
||||
metrics: CohortMetrics::forced_import(&cfg, all_supply)?,
|
||||
|
||||
indexes_to_addr_count: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_addr_count: DerivedComputedBlockLast::forced_import(
|
||||
db,
|
||||
&cfg.name("addr_count"),
|
||||
Source::Vec(height_to_addr_count.boxed_clone()),
|
||||
height_to_addr_count.boxed_clone(),
|
||||
version + VERSION,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
height_to_addr_count,
|
||||
})
|
||||
@@ -248,11 +247,11 @@ impl DynCohortVecs for AddressCohortVecs {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.indexes_to_addr_count.compute_rest(
|
||||
self.indexes_to_addr_count.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_addr_count,
|
||||
exit,
|
||||
Some(&self.height_to_addr_count),
|
||||
)?;
|
||||
self.metrics
|
||||
.compute_rest_part1(indexes, price, starting_indexes, exit)?;
|
||||
|
||||
@@ -7,7 +7,7 @@ use brk_cohort::{
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{DateIndex, Dollars, Height, Sats, Version};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use rayon::prelude::*;
|
||||
use vecdb::{AnyStoredVec, Database, Exit, IterableVec};
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ use crate::{
|
||||
state::{BlockState, Transacted},
|
||||
},
|
||||
inputs, outputs,
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -63,10 +62,10 @@ pub fn process_blocks(
|
||||
let height_to_first_txoutindex = &indexer.vecs.txout.height_to_first_txoutindex;
|
||||
let height_to_first_txinindex = &indexer.vecs.txin.height_to_first_txinindex;
|
||||
|
||||
// From transactions and inputs/outputs (via .height.u() or .height.unwrap_sum() patterns):
|
||||
let height_to_tx_count = transactions.count.indexes_to_tx_count.height.u();
|
||||
let height_to_output_count = outputs.count.indexes_to_count.height.unwrap_sum();
|
||||
let height_to_input_count = inputs.count.indexes_to_count.height.unwrap_sum();
|
||||
// From transactions and inputs/outputs (via .height or .height.sum_cum.sum patterns):
|
||||
let height_to_tx_count = &transactions.count.indexes_to_tx_count.height;
|
||||
let height_to_output_count = &outputs.count.indexes_to_count.height.sum_cum.sum.0;
|
||||
let height_to_input_count = &inputs.count.indexes_to_count.height.sum_cum.sum.0;
|
||||
// From blocks:
|
||||
let height_to_timestamp = &blocks.time.height_to_timestamp_fixed;
|
||||
let height_to_date = &blocks.time.height_to_date_fixed;
|
||||
@@ -77,7 +76,7 @@ pub fn process_blocks(
|
||||
|
||||
// From price (optional):
|
||||
let height_to_price = price.map(|p| &p.usd.chainindexes_to_price_close.height);
|
||||
let dateindex_to_price = price.map(|p| p.usd.timeindexes_to_price_close.dateindex.u());
|
||||
let dateindex_to_price = price.map(|p| &p.usd.timeindexes_to_price_close.dateindex);
|
||||
|
||||
// Access pre-computed vectors from context for thread-safe access
|
||||
let height_to_price_vec = &ctx.height_to_price;
|
||||
|
||||
@@ -9,8 +9,7 @@ use vecdb::{
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, indexes,
|
||||
internal::{ComputedValueVecsFromHeight, ComputedVecsFromHeight, Source, VecBuilderOptions},
|
||||
price,
|
||||
internal::{ComputedBlockSumCum, DerivedValueBlockSumCum},
|
||||
};
|
||||
|
||||
use super::ImportConfig;
|
||||
@@ -21,8 +20,8 @@ pub struct ActivityMetrics {
|
||||
/// Total satoshis sent at each height
|
||||
pub height_to_sent: EagerVec<PcoVec<Height, Sats>>,
|
||||
|
||||
/// Sent amounts indexed by various dimensions
|
||||
pub indexes_to_sent: ComputedValueVecsFromHeight,
|
||||
/// Sent amounts indexed by various dimensions (derives from height_to_sent)
|
||||
pub indexes_to_sent: DerivedValueBlockSumCum,
|
||||
|
||||
/// Satoshi-blocks destroyed (supply * blocks_old when spent)
|
||||
pub height_to_satblocks_destroyed: EagerVec<PcoVec<Height, Sats>>,
|
||||
@@ -31,28 +30,24 @@ pub struct ActivityMetrics {
|
||||
pub height_to_satdays_destroyed: EagerVec<PcoVec<Height, Sats>>,
|
||||
|
||||
/// Coin-blocks destroyed (in BTC rather than sats)
|
||||
pub indexes_to_coinblocks_destroyed: ComputedVecsFromHeight<StoredF64>,
|
||||
pub indexes_to_coinblocks_destroyed: ComputedBlockSumCum<StoredF64>,
|
||||
|
||||
/// Coin-days destroyed (in BTC rather than sats)
|
||||
pub indexes_to_coindays_destroyed: ComputedVecsFromHeight<StoredF64>,
|
||||
pub indexes_to_coindays_destroyed: ComputedBlockSumCum<StoredF64>,
|
||||
}
|
||||
|
||||
impl ActivityMetrics {
|
||||
/// Import activity metrics from database.
|
||||
pub fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let compute_dollars = cfg.compute_dollars();
|
||||
let sum_cum = VecBuilderOptions::default().add_sum().add_cumulative();
|
||||
|
||||
let height_to_sent: EagerVec<PcoVec<Height, Sats>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("sent"), cfg.version)?;
|
||||
let indexes_to_sent = ComputedValueVecsFromHeight::forced_import(
|
||||
let indexes_to_sent = DerivedValueBlockSumCum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("sent"),
|
||||
Source::Vec(height_to_sent.boxed_clone()),
|
||||
cfg.version,
|
||||
sum_cum,
|
||||
compute_dollars,
|
||||
cfg.indexes,
|
||||
height_to_sent.boxed_clone(),
|
||||
cfg.price,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
@@ -71,22 +66,18 @@ impl ActivityMetrics {
|
||||
cfg.version,
|
||||
)?,
|
||||
|
||||
indexes_to_coinblocks_destroyed: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_coinblocks_destroyed: ComputedBlockSumCum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("coinblocks_destroyed"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?,
|
||||
|
||||
indexes_to_coindays_destroyed: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_coindays_destroyed: ComputedBlockSumCum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("coindays_destroyed"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
@@ -174,16 +165,14 @@ impl ActivityMetrics {
|
||||
pub fn compute_rest_part1(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
price: Option<&price::Vecs>,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.indexes_to_sent.compute_rest(
|
||||
self.indexes_to_sent.derive_from(
|
||||
indexes,
|
||||
price,
|
||||
starting_indexes,
|
||||
&self.height_to_sent,
|
||||
exit,
|
||||
Some(&self.height_to_sent),
|
||||
)?;
|
||||
|
||||
self.indexes_to_coinblocks_destroyed
|
||||
|
||||
@@ -10,7 +10,7 @@ use vecdb::{
|
||||
use crate::{
|
||||
ComputeIndexes,
|
||||
distribution::state::CohortState,
|
||||
internal::{ComputedVecsFromHeight, CostBasisPercentiles, Source, VecBuilderOptions},
|
||||
internal::{CostBasisPercentiles, DerivedComputedBlockLast},
|
||||
};
|
||||
|
||||
use super::ImportConfig;
|
||||
@@ -20,11 +20,11 @@ use super::ImportConfig;
|
||||
pub struct CostBasisMetrics {
|
||||
/// Minimum cost basis for any UTXO at this height
|
||||
pub height_to_min_cost_basis: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_min_cost_basis: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_min_cost_basis: DerivedComputedBlockLast<Dollars>,
|
||||
|
||||
/// Maximum cost basis for any UTXO at this height
|
||||
pub height_to_max_cost_basis: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_max_cost_basis: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_max_cost_basis: DerivedComputedBlockLast<Dollars>,
|
||||
|
||||
/// Cost basis distribution percentiles (median, quartiles, etc.)
|
||||
pub percentiles: Option<CostBasisPercentiles>,
|
||||
@@ -34,7 +34,6 @@ impl CostBasisMetrics {
|
||||
/// Import cost basis metrics from database.
|
||||
pub fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let extended = cfg.extended();
|
||||
let last = VecBuilderOptions::default().add_last();
|
||||
|
||||
let height_to_min_cost_basis =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("min_cost_basis"), cfg.version)?;
|
||||
@@ -43,21 +42,19 @@ impl CostBasisMetrics {
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("max_cost_basis"), cfg.version)?;
|
||||
|
||||
Ok(Self {
|
||||
indexes_to_min_cost_basis: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_min_cost_basis: DerivedComputedBlockLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("min_cost_basis"),
|
||||
Source::Vec(height_to_min_cost_basis.boxed_clone()),
|
||||
height_to_min_cost_basis.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
indexes_to_max_cost_basis: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_max_cost_basis: DerivedComputedBlockLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("max_cost_basis"),
|
||||
Source::Vec(height_to_max_cost_basis.boxed_clone()),
|
||||
height_to_max_cost_basis.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
height_to_min_cost_basis,
|
||||
height_to_max_cost_basis,
|
||||
@@ -145,8 +142,7 @@ impl CostBasisMetrics {
|
||||
.vecs
|
||||
.iter_mut()
|
||||
.flatten()
|
||||
.filter_map(|v| v.dateindex.as_mut())
|
||||
.map(|v| v as &mut dyn AnyStoredVec),
|
||||
.map(|v| &mut v.dateindex as &mut dyn AnyStoredVec),
|
||||
);
|
||||
}
|
||||
vecs.into_par_iter()
|
||||
@@ -193,18 +189,18 @@ impl CostBasisMetrics {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.indexes_to_min_cost_basis.compute_rest(
|
||||
self.indexes_to_min_cost_basis.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_min_cost_basis,
|
||||
exit,
|
||||
Some(&self.height_to_min_cost_basis),
|
||||
)?;
|
||||
|
||||
self.indexes_to_max_cost_basis.compute_rest(
|
||||
self.indexes_to_max_cost_basis.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_max_cost_basis,
|
||||
exit,
|
||||
Some(&self.height_to_max_cost_basis),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -295,7 +295,7 @@ impl CohortMetrics {
|
||||
self.supply
|
||||
.compute_rest_part1(indexes, price, starting_indexes, exit)?;
|
||||
self.activity
|
||||
.compute_rest_part1(indexes, price, starting_indexes, exit)?;
|
||||
.compute_rest_part1(indexes, starting_indexes, exit)?;
|
||||
|
||||
if let Some(realized) = self.realized.as_mut() {
|
||||
realized.compute_rest_part1(indexes, starting_indexes, exit)?;
|
||||
|
||||
@@ -12,12 +12,12 @@ use crate::{
|
||||
distribution::state::RealizedState,
|
||||
indexes,
|
||||
internal::{
|
||||
ComputedRatioVecsFromDateIndex, ComputedVecsFromDateIndex, ComputedVecsFromHeight,
|
||||
DollarsMinus, LazyVecsFrom2FromHeight, LazyVecsFromDateIndex, LazyVecsFromHeight,
|
||||
PercentageDollarsF32, Source, StoredF32Identity, VecBuilderOptions,
|
||||
BinaryBlockSum, BinaryBlockSumCumLast, ComputedBlockLast, ComputedBlockSum,
|
||||
ComputedBlockSumCum, ComputedDateLast, ComputedRatioVecsDate, DerivedComputedBlockLast,
|
||||
DerivedComputedBlockSum, DerivedComputedBlockSumCum, DollarsMinus, LazyBlockSum,
|
||||
LazyBlockSumCum, LazyDateLast, PercentageDollarsF32, StoredF32Identity,
|
||||
},
|
||||
price,
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
use super::ImportConfig;
|
||||
@@ -27,48 +27,48 @@ use super::ImportConfig;
|
||||
pub struct RealizedMetrics {
|
||||
// === Realized Cap ===
|
||||
pub height_to_realized_cap: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_realized_cap: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_realized_price: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_realized_price_extra: ComputedRatioVecsFromDateIndex,
|
||||
pub indexes_to_realized_cap_rel_to_own_market_cap: Option<ComputedVecsFromHeight<StoredF32>>,
|
||||
pub indexes_to_realized_cap_30d_delta: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_realized_cap: DerivedComputedBlockLast<Dollars>,
|
||||
pub indexes_to_realized_price: ComputedBlockLast<Dollars>,
|
||||
pub indexes_to_realized_price_extra: ComputedRatioVecsDate,
|
||||
pub indexes_to_realized_cap_rel_to_own_market_cap: Option<ComputedBlockLast<StoredF32>>,
|
||||
pub indexes_to_realized_cap_30d_delta: ComputedDateLast<Dollars>,
|
||||
|
||||
// === MVRV (Market Value to Realized Value) ===
|
||||
// Proxy for indexes_to_realized_price_extra.ratio (close / realized_price = market_cap / realized_cap)
|
||||
pub indexes_to_mvrv: LazyVecsFromDateIndex<StoredF32>,
|
||||
pub indexes_to_mvrv: LazyDateLast<StoredF32>,
|
||||
|
||||
// === Realized Profit/Loss ===
|
||||
pub height_to_realized_profit: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_realized_profit: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_realized_profit: DerivedComputedBlockSumCum<Dollars>,
|
||||
pub height_to_realized_loss: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_realized_loss: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_neg_realized_loss: LazyVecsFromHeight<Dollars>,
|
||||
pub indexes_to_net_realized_pnl: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_realized_value: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_realized_loss: DerivedComputedBlockSumCum<Dollars>,
|
||||
pub indexes_to_neg_realized_loss: LazyBlockSumCum<Dollars>,
|
||||
pub indexes_to_net_realized_pnl: ComputedBlockSumCum<Dollars>,
|
||||
pub indexes_to_realized_value: ComputedBlockSum<Dollars>,
|
||||
|
||||
// === Realized vs Realized Cap Ratios (lazy) ===
|
||||
pub indexes_to_realized_profit_rel_to_realized_cap:
|
||||
LazyVecsFrom2FromHeight<StoredF32, Dollars, Dollars>,
|
||||
BinaryBlockSumCumLast<StoredF32, Dollars, Dollars>,
|
||||
pub indexes_to_realized_loss_rel_to_realized_cap:
|
||||
LazyVecsFrom2FromHeight<StoredF32, Dollars, Dollars>,
|
||||
BinaryBlockSumCumLast<StoredF32, Dollars, Dollars>,
|
||||
pub indexes_to_net_realized_pnl_rel_to_realized_cap:
|
||||
LazyVecsFrom2FromHeight<StoredF32, Dollars, Dollars>,
|
||||
BinaryBlockSumCumLast<StoredF32, Dollars, Dollars>,
|
||||
|
||||
// === Total Realized PnL ===
|
||||
pub indexes_to_total_realized_pnl: LazyVecsFromHeight<Dollars>,
|
||||
pub indexes_to_total_realized_pnl: LazyBlockSum<Dollars>,
|
||||
pub dateindex_to_realized_profit_to_loss_ratio: Option<EagerVec<PcoVec<DateIndex, StoredF64>>>,
|
||||
|
||||
// === Value Created/Destroyed ===
|
||||
pub height_to_value_created: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_value_created: ComputedVecsFromHeight<Dollars>,
|
||||
#[traversable(rename = "value_created_sum")]
|
||||
pub indexes_to_value_created: DerivedComputedBlockSum<Dollars>,
|
||||
pub height_to_value_destroyed: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_value_destroyed: ComputedVecsFromHeight<Dollars>,
|
||||
#[traversable(rename = "value_destroyed_sum")]
|
||||
pub indexes_to_value_destroyed: DerivedComputedBlockSum<Dollars>,
|
||||
|
||||
// === Adjusted Value (lazy: cohort - up_to_1h) ===
|
||||
pub indexes_to_adjusted_value_created:
|
||||
Option<LazyVecsFrom2FromHeight<Dollars, Dollars, Dollars>>,
|
||||
pub indexes_to_adjusted_value_destroyed:
|
||||
Option<LazyVecsFrom2FromHeight<Dollars, Dollars, Dollars>>,
|
||||
pub indexes_to_adjusted_value_created: Option<BinaryBlockSum<Dollars, Dollars, Dollars>>,
|
||||
pub indexes_to_adjusted_value_destroyed: Option<BinaryBlockSum<Dollars, Dollars, Dollars>>,
|
||||
|
||||
// === SOPR (Spent Output Profit Ratio) ===
|
||||
pub dateindex_to_sopr: EagerVec<PcoVec<DateIndex, StoredF64>>,
|
||||
@@ -84,11 +84,11 @@ pub struct RealizedMetrics {
|
||||
pub dateindex_to_sell_side_risk_ratio_30d_ema: EagerVec<PcoVec<DateIndex, StoredF32>>,
|
||||
|
||||
// === Net Realized PnL Deltas ===
|
||||
pub indexes_to_net_realized_pnl_cumulative_30d_delta: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_net_realized_pnl_cumulative_30d_delta: ComputedDateLast<Dollars>,
|
||||
pub indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap:
|
||||
ComputedVecsFromDateIndex<StoredF32>,
|
||||
ComputedDateLast<StoredF32>,
|
||||
pub indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_market_cap:
|
||||
ComputedVecsFromDateIndex<StoredF32>,
|
||||
ComputedDateLast<StoredF32>,
|
||||
}
|
||||
|
||||
impl RealizedMetrics {
|
||||
@@ -98,23 +98,19 @@ impl RealizedMetrics {
|
||||
let v3 = Version::new(3);
|
||||
let extended = cfg.extended();
|
||||
let compute_adjusted = cfg.compute_adjusted();
|
||||
let last = VecBuilderOptions::default().add_last();
|
||||
let sum = VecBuilderOptions::default().add_sum();
|
||||
let sum_cum = VecBuilderOptions::default().add_sum().add_cumulative();
|
||||
|
||||
let height_to_realized_loss: EagerVec<PcoVec<Height, Dollars>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("realized_loss"), cfg.version)?;
|
||||
|
||||
let indexes_to_realized_loss = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_realized_loss = DerivedComputedBlockSumCum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_loss"),
|
||||
Source::Vec(height_to_realized_loss.boxed_clone()),
|
||||
height_to_realized_loss.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?;
|
||||
|
||||
let indexes_to_neg_realized_loss = LazyVecsFromHeight::from_computed::<Negate>(
|
||||
let indexes_to_neg_realized_loss = LazyBlockSumCum::from_derived::<Negate>(
|
||||
&cfg.name("neg_realized_loss"),
|
||||
cfg.version + v1,
|
||||
height_to_realized_loss.boxed_clone(),
|
||||
@@ -122,24 +118,18 @@ impl RealizedMetrics {
|
||||
);
|
||||
|
||||
// realized_value is the source for total_realized_pnl (they're identical)
|
||||
let indexes_to_realized_value = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_realized_value = ComputedBlockSum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_value"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum,
|
||||
)?;
|
||||
|
||||
// total_realized_pnl is a lazy alias to realized_value
|
||||
let indexes_to_total_realized_pnl = LazyVecsFromHeight::from_computed::<Ident>(
|
||||
let indexes_to_total_realized_pnl = LazyBlockSum::from_computed::<Ident>(
|
||||
&cfg.name("total_realized_pnl"),
|
||||
cfg.version + v1,
|
||||
indexes_to_realized_value
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
indexes_to_realized_value.height.boxed_clone(),
|
||||
&indexes_to_realized_value,
|
||||
);
|
||||
|
||||
@@ -147,39 +137,35 @@ impl RealizedMetrics {
|
||||
let height_to_realized_cap: EagerVec<PcoVec<Height, Dollars>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("realized_cap"), cfg.version)?;
|
||||
|
||||
let indexes_to_realized_cap = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_realized_cap = DerivedComputedBlockLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap"),
|
||||
Source::Vec(height_to_realized_cap.boxed_clone()),
|
||||
height_to_realized_cap.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?;
|
||||
|
||||
let height_to_realized_profit: EagerVec<PcoVec<Height, Dollars>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("realized_profit"), cfg.version)?;
|
||||
|
||||
let indexes_to_realized_profit = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_realized_profit = DerivedComputedBlockSumCum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit"),
|
||||
Source::Vec(height_to_realized_profit.boxed_clone()),
|
||||
height_to_realized_profit.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?;
|
||||
|
||||
let indexes_to_net_realized_pnl = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_net_realized_pnl = ComputedBlockSumCum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?;
|
||||
|
||||
// Construct lazy ratio vecs (before struct assignment to satisfy borrow checker)
|
||||
let indexes_to_realized_profit_rel_to_realized_cap =
|
||||
LazyVecsFrom2FromHeight::from_computed::<PercentageDollarsF32>(
|
||||
BinaryBlockSumCumLast::from_derived::<PercentageDollarsF32>(
|
||||
&cfg.name("realized_profit_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
height_to_realized_profit.boxed_clone(),
|
||||
@@ -189,7 +175,7 @@ impl RealizedMetrics {
|
||||
);
|
||||
|
||||
let indexes_to_realized_loss_rel_to_realized_cap =
|
||||
LazyVecsFrom2FromHeight::from_computed::<PercentageDollarsF32>(
|
||||
BinaryBlockSumCumLast::from_derived::<PercentageDollarsF32>(
|
||||
&cfg.name("realized_loss_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
height_to_realized_loss.boxed_clone(),
|
||||
@@ -199,26 +185,20 @@ impl RealizedMetrics {
|
||||
);
|
||||
|
||||
let indexes_to_net_realized_pnl_rel_to_realized_cap =
|
||||
LazyVecsFrom2FromHeight::from_computed::<PercentageDollarsF32>(
|
||||
BinaryBlockSumCumLast::from_computed_derived::<PercentageDollarsF32>(
|
||||
&cfg.name("net_realized_pnl_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
indexes_to_net_realized_pnl
|
||||
.height
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.boxed_clone(),
|
||||
indexes_to_net_realized_pnl.height.boxed_clone(),
|
||||
height_to_realized_cap.boxed_clone(),
|
||||
&indexes_to_net_realized_pnl,
|
||||
&indexes_to_realized_cap,
|
||||
);
|
||||
|
||||
let indexes_to_realized_price = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_realized_price = ComputedBlockLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_price"),
|
||||
Source::Compute,
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?;
|
||||
|
||||
let height_to_value_created =
|
||||
@@ -226,28 +206,26 @@ impl RealizedMetrics {
|
||||
let height_to_value_destroyed =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("value_destroyed"), cfg.version)?;
|
||||
|
||||
let indexes_to_value_created = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_value_created = DerivedComputedBlockSum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("value_created"),
|
||||
Source::Vec(height_to_value_created.boxed_clone()),
|
||||
height_to_value_created.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum,
|
||||
)?;
|
||||
let indexes_to_value_destroyed = ComputedVecsFromHeight::forced_import(
|
||||
let indexes_to_value_destroyed = DerivedComputedBlockSum::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("value_destroyed"),
|
||||
Source::Vec(height_to_value_destroyed.boxed_clone()),
|
||||
height_to_value_destroyed.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
sum,
|
||||
)?;
|
||||
|
||||
// Create lazy adjusted vecs if compute_adjusted and up_to_1h is available
|
||||
let indexes_to_adjusted_value_created = (compute_adjusted && cfg.up_to_1h_realized.is_some())
|
||||
.then(|| {
|
||||
let indexes_to_adjusted_value_created =
|
||||
(compute_adjusted && cfg.up_to_1h_realized.is_some()).then(|| {
|
||||
let up_to_1h = cfg.up_to_1h_realized.unwrap();
|
||||
LazyVecsFrom2FromHeight::from_computed::<DollarsMinus>(
|
||||
BinaryBlockSum::from_derived::<DollarsMinus>(
|
||||
&cfg.name("adjusted_value_created"),
|
||||
cfg.version,
|
||||
height_to_value_created.boxed_clone(),
|
||||
@@ -259,7 +237,7 @@ impl RealizedMetrics {
|
||||
let indexes_to_adjusted_value_destroyed =
|
||||
(compute_adjusted && cfg.up_to_1h_realized.is_some()).then(|| {
|
||||
let up_to_1h = cfg.up_to_1h_realized.unwrap();
|
||||
LazyVecsFrom2FromHeight::from_computed::<DollarsMinus>(
|
||||
BinaryBlockSum::from_derived::<DollarsMinus>(
|
||||
&cfg.name("adjusted_value_destroyed"),
|
||||
cfg.version,
|
||||
height_to_value_destroyed.boxed_clone(),
|
||||
@@ -270,7 +248,7 @@ impl RealizedMetrics {
|
||||
});
|
||||
|
||||
// Create realized_price_extra first so we can reference its ratio for MVRV proxy
|
||||
let indexes_to_realized_price_extra = ComputedRatioVecsFromDateIndex::forced_import(
|
||||
let indexes_to_realized_price_extra = ComputedRatioVecsDate::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_price"),
|
||||
Some(&indexes_to_realized_price),
|
||||
@@ -282,14 +260,9 @@ impl RealizedMetrics {
|
||||
|
||||
// MVRV is a lazy proxy for realized_price_extra.ratio
|
||||
// ratio = close / realized_price = market_cap / realized_cap = MVRV
|
||||
let indexes_to_mvrv = LazyVecsFromDateIndex::from_computed::<StoredF32Identity>(
|
||||
let indexes_to_mvrv = LazyDateLast::from_source::<StoredF32Identity>(
|
||||
&cfg.name("mvrv"),
|
||||
cfg.version,
|
||||
indexes_to_realized_price_extra
|
||||
.ratio
|
||||
.dateindex
|
||||
.as_ref()
|
||||
.map(|v| v.boxed_clone()),
|
||||
&indexes_to_realized_price_extra.ratio,
|
||||
);
|
||||
|
||||
@@ -303,23 +276,19 @@ impl RealizedMetrics {
|
||||
indexes_to_mvrv,
|
||||
indexes_to_realized_cap_rel_to_own_market_cap: extended
|
||||
.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
ComputedBlockLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap_rel_to_own_market_cap"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)
|
||||
})
|
||||
.transpose()?,
|
||||
indexes_to_realized_cap_30d_delta: ComputedVecsFromDateIndex::forced_import(
|
||||
indexes_to_realized_cap_30d_delta: ComputedDateLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap_30d_delta"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
|
||||
// === Realized Profit/Loss ===
|
||||
@@ -416,32 +385,25 @@ impl RealizedMetrics {
|
||||
)?,
|
||||
|
||||
// === Net Realized PnL Deltas ===
|
||||
indexes_to_net_realized_pnl_cumulative_30d_delta:
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_cumulative_30d_delta"),
|
||||
Source::Compute,
|
||||
cfg.version + v3,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
indexes_to_net_realized_pnl_cumulative_30d_delta: ComputedDateLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_cumulative_30d_delta"),
|
||||
cfg.version + v3,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap:
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
ComputedDateLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_cumulative_30d_delta_rel_to_realized_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v3,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
indexes_to_net_realized_pnl_cumulative_30d_delta_rel_to_market_cap:
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
ComputedDateLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_cumulative_30d_delta_rel_to_market_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v3,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
@@ -558,25 +520,25 @@ impl RealizedMetrics {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.indexes_to_realized_cap.compute_rest(
|
||||
self.indexes_to_realized_cap.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_realized_cap,
|
||||
exit,
|
||||
Some(&self.height_to_realized_cap),
|
||||
)?;
|
||||
|
||||
self.indexes_to_realized_profit.compute_rest(
|
||||
self.indexes_to_realized_profit.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_realized_profit,
|
||||
exit,
|
||||
Some(&self.height_to_realized_profit),
|
||||
)?;
|
||||
|
||||
self.indexes_to_realized_loss.compute_rest(
|
||||
self.indexes_to_realized_loss.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_realized_loss,
|
||||
exit,
|
||||
Some(&self.height_to_realized_loss),
|
||||
)?;
|
||||
|
||||
// net_realized_pnl = profit - loss
|
||||
@@ -605,18 +567,18 @@ impl RealizedMetrics {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_value_created.compute_rest(
|
||||
self.indexes_to_value_created.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_value_created,
|
||||
exit,
|
||||
Some(&self.height_to_value_created),
|
||||
)?;
|
||||
|
||||
self.indexes_to_value_destroyed.compute_rest(
|
||||
self.indexes_to_value_destroyed.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_value_destroyed,
|
||||
exit,
|
||||
Some(&self.height_to_value_destroyed),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
@@ -651,7 +613,7 @@ impl RealizedMetrics {
|
||||
price,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(self.indexes_to_realized_price.dateindex.unwrap_last()),
|
||||
Some(&self.indexes_to_realized_price.dateindex.0),
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -660,7 +622,7 @@ impl RealizedMetrics {
|
||||
.compute_all(starting_indexes, exit, |vec| {
|
||||
vec.compute_change(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_realized_cap.dateindex.unwrap_last(),
|
||||
&self.indexes_to_realized_cap.dateindex.0,
|
||||
30,
|
||||
exit,
|
||||
)?;
|
||||
@@ -670,8 +632,8 @@ impl RealizedMetrics {
|
||||
// SOPR = value_created / value_destroyed
|
||||
self.dateindex_to_sopr.compute_divide(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_value_created.dateindex.unwrap_sum(),
|
||||
self.indexes_to_value_destroyed.dateindex.unwrap_sum(),
|
||||
&self.indexes_to_value_created.dateindex.0,
|
||||
&self.indexes_to_value_destroyed.dateindex.0,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -692,17 +654,13 @@ impl RealizedMetrics {
|
||||
// Optional: adjusted SOPR (lazy: cohort - up_to_1h)
|
||||
if let (Some(adjusted_sopr), Some(adj_created), Some(adj_destroyed)) = (
|
||||
self.dateindex_to_adjusted_sopr.as_mut(),
|
||||
self.indexes_to_adjusted_value_created
|
||||
.as_ref()
|
||||
.and_then(|v| v.dateindex.sum.as_ref()),
|
||||
self.indexes_to_adjusted_value_destroyed
|
||||
.as_ref()
|
||||
.and_then(|v| v.dateindex.sum.as_ref()),
|
||||
self.indexes_to_adjusted_value_created.as_ref(),
|
||||
self.indexes_to_adjusted_value_destroyed.as_ref(),
|
||||
) {
|
||||
adjusted_sopr.compute_divide(
|
||||
starting_indexes.dateindex,
|
||||
adj_created.as_ref(),
|
||||
adj_destroyed.as_ref(),
|
||||
&*adj_created.dateindex,
|
||||
&*adj_destroyed.dateindex,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -728,8 +686,8 @@ impl RealizedMetrics {
|
||||
// sell_side_risk_ratio = realized_value / realized_cap
|
||||
self.dateindex_to_sell_side_risk_ratio.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_realized_value.dateindex.unwrap_sum(),
|
||||
self.indexes_to_realized_cap.dateindex.unwrap_last(),
|
||||
&self.indexes_to_realized_value.dateindex.0,
|
||||
&self.indexes_to_realized_cap.dateindex.0,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -752,9 +710,7 @@ impl RealizedMetrics {
|
||||
.compute_all(starting_indexes, exit, |vec| {
|
||||
vec.compute_change(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_net_realized_pnl
|
||||
.dateindex
|
||||
.unwrap_cumulative(),
|
||||
&self.indexes_to_net_realized_pnl.dateindex.cumulative.0,
|
||||
30,
|
||||
exit,
|
||||
)?;
|
||||
@@ -766,10 +722,10 @@ impl RealizedMetrics {
|
||||
.compute_all(starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_net_realized_pnl_cumulative_30d_delta
|
||||
.dateindex
|
||||
.u(),
|
||||
self.indexes_to_realized_cap.dateindex.unwrap_last(),
|
||||
&self
|
||||
.indexes_to_net_realized_pnl_cumulative_30d_delta
|
||||
.dateindex,
|
||||
&self.indexes_to_realized_cap.dateindex.0,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -781,9 +737,9 @@ impl RealizedMetrics {
|
||||
.compute_all(starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_net_realized_pnl_cumulative_30d_delta
|
||||
.dateindex
|
||||
.u(),
|
||||
&self
|
||||
.indexes_to_net_realized_pnl_cumulative_30d_delta
|
||||
.dateindex,
|
||||
dateindex_to_market_cap,
|
||||
exit,
|
||||
)?;
|
||||
@@ -811,8 +767,8 @@ impl RealizedMetrics {
|
||||
if let Some(ratio) = self.dateindex_to_realized_profit_to_loss_ratio.as_mut() {
|
||||
ratio.compute_divide(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_realized_profit.dateindex.unwrap_sum(),
|
||||
self.indexes_to_realized_loss.dateindex.unwrap_sum(),
|
||||
&self.indexes_to_realized_profit.dateindex.sum.0,
|
||||
&self.indexes_to_realized_loss.dateindex.sum.0,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use brk_types::{Bitcoin, Dollars, Height, Sats, StoredF32, StoredF64, Version};
|
||||
use vecdb::{IterableCloneableVec, LazyVecFrom2};
|
||||
|
||||
use crate::internal::{
|
||||
LazyVecsFrom2FromDateIndex, NegPercentageDollarsF32, NegRatio32, PercentageBtcF64,
|
||||
BinaryDateLast, NegPercentageDollarsF32, NegRatio32, PercentageBtcF64,
|
||||
PercentageDollarsF32, PercentageSatsF64, Ratio32,
|
||||
};
|
||||
|
||||
@@ -15,28 +15,31 @@ use super::{ImportConfig, SupplyMetrics, UnrealizedMetrics};
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct RelativeMetrics {
|
||||
// === Supply Relative to Circulating Supply (lazy from global supply) ===
|
||||
// KISS: both sources are ComputedVecsDateLast<Sats>
|
||||
pub indexes_to_supply_rel_to_circulating_supply:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF64, Sats, Sats>>,
|
||||
Option<BinaryDateLast<StoredF64, Sats, Sats>>,
|
||||
|
||||
// === Supply in Profit/Loss Relative to Own Supply (lazy) ===
|
||||
pub height_to_supply_in_profit_rel_to_own_supply:
|
||||
LazyVecFrom2<Height, StoredF64, Height, Bitcoin, Height, Bitcoin>,
|
||||
pub height_to_supply_in_loss_rel_to_own_supply:
|
||||
LazyVecFrom2<Height, StoredF64, Height, Bitcoin, Height, Bitcoin>,
|
||||
// KISS: both unrealized and supply are now KISS types
|
||||
pub indexes_to_supply_in_profit_rel_to_own_supply:
|
||||
LazyVecsFrom2FromDateIndex<StoredF64, Sats, Sats>,
|
||||
BinaryDateLast<StoredF64, Sats, Sats>,
|
||||
pub indexes_to_supply_in_loss_rel_to_own_supply:
|
||||
LazyVecsFrom2FromDateIndex<StoredF64, Sats, Sats>,
|
||||
BinaryDateLast<StoredF64, Sats, Sats>,
|
||||
|
||||
// === Supply in Profit/Loss Relative to Circulating Supply (lazy from global supply) ===
|
||||
pub height_to_supply_in_profit_rel_to_circulating_supply:
|
||||
Option<LazyVecFrom2<Height, StoredF64, Height, Bitcoin, Height, Bitcoin>>,
|
||||
pub height_to_supply_in_loss_rel_to_circulating_supply:
|
||||
Option<LazyVecFrom2<Height, StoredF64, Height, Bitcoin, Height, Bitcoin>>,
|
||||
// KISS: both unrealized and global_supply are now KISS types
|
||||
pub indexes_to_supply_in_profit_rel_to_circulating_supply:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF64, Sats, Sats>>,
|
||||
Option<BinaryDateLast<StoredF64, Sats, Sats>>,
|
||||
pub indexes_to_supply_in_loss_rel_to_circulating_supply:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF64, Sats, Sats>>,
|
||||
Option<BinaryDateLast<StoredF64, Sats, Sats>>,
|
||||
|
||||
// === Unrealized vs Market Cap (lazy from global market cap) ===
|
||||
pub height_to_unrealized_profit_rel_to_market_cap:
|
||||
@@ -47,18 +50,20 @@ pub struct RelativeMetrics {
|
||||
Option<LazyVecFrom2<Height, StoredF32, Height, Dollars, Height, Dollars>>,
|
||||
pub height_to_net_unrealized_pnl_rel_to_market_cap:
|
||||
Option<LazyVecFrom2<Height, StoredF32, Height, Dollars, Height, Dollars>>,
|
||||
// KISS: DerivedDateLast + ComputedVecsDateLast
|
||||
pub indexes_to_unrealized_profit_rel_to_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_unrealized_loss_rel_to_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_neg_unrealized_loss_rel_to_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
// KISS: both ComputedVecsDateLast
|
||||
pub indexes_to_net_unrealized_pnl_rel_to_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
|
||||
// === NUPL (Net Unrealized Profit/Loss) ===
|
||||
// Proxy for indexes_to_net_unrealized_pnl_rel_to_market_cap
|
||||
pub indexes_to_nupl: Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
// KISS: both ComputedVecsDateLast
|
||||
pub indexes_to_nupl: Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
|
||||
// === Unrealized vs Own Market Cap (lazy) ===
|
||||
pub height_to_unrealized_profit_rel_to_own_market_cap:
|
||||
@@ -69,14 +74,16 @@ pub struct RelativeMetrics {
|
||||
Option<LazyVecFrom2<Height, StoredF32, Height, Dollars, Height, Dollars>>,
|
||||
pub height_to_net_unrealized_pnl_rel_to_own_market_cap:
|
||||
Option<LazyVecFrom2<Height, StoredF32, Height, Dollars, Height, Dollars>>,
|
||||
// KISS: DerivedDateLast + ComputedVecsDateLast
|
||||
pub indexes_to_unrealized_profit_rel_to_own_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_unrealized_loss_rel_to_own_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_neg_unrealized_loss_rel_to_own_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
// KISS: both ComputedVecsDateLast
|
||||
pub indexes_to_net_unrealized_pnl_rel_to_own_market_cap:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
|
||||
// === Unrealized vs Own Total Unrealized PnL (lazy) ===
|
||||
pub height_to_unrealized_profit_rel_to_own_total_unrealized_pnl:
|
||||
@@ -87,14 +94,15 @@ pub struct RelativeMetrics {
|
||||
Option<LazyVecFrom2<Height, StoredF32, Height, Dollars, Height, Dollars>>,
|
||||
pub height_to_net_unrealized_pnl_rel_to_own_total_unrealized_pnl:
|
||||
Option<LazyVecFrom2<Height, StoredF32, Height, Dollars, Height, Dollars>>,
|
||||
// KISS: DerivedDateLast + DerivedDateLast
|
||||
pub indexes_to_unrealized_profit_rel_to_own_total_unrealized_pnl:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_unrealized_loss_rel_to_own_total_unrealized_pnl:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_neg_unrealized_loss_rel_to_own_total_unrealized_pnl:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_net_unrealized_pnl_rel_to_own_total_unrealized_pnl:
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
Option<BinaryDateLast<StoredF32, Dollars, Dollars>>,
|
||||
}
|
||||
|
||||
impl RelativeMetrics {
|
||||
@@ -115,6 +123,7 @@ impl RelativeMetrics {
|
||||
|
||||
// Global sources from "all" cohort
|
||||
let global_supply_sats = all_supply.map(|s| &s.indexes_to_supply.sats);
|
||||
let global_supply_sats_dateindex = all_supply.map(|s| &s.indexes_to_supply.sats_dateindex);
|
||||
let global_supply_btc = all_supply.map(|s| &s.height_to_supply_value.bitcoin);
|
||||
let global_market_cap = all_supply.and_then(|s| s.indexes_to_supply.dollars.as_ref());
|
||||
let global_market_cap_height =
|
||||
@@ -129,10 +138,12 @@ impl RelativeMetrics {
|
||||
indexes_to_supply_rel_to_circulating_supply: (compute_rel_to_all
|
||||
&& global_supply_sats.is_some())
|
||||
.then(|| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageSatsF64>(
|
||||
BinaryDateLast::from_both_derived_last::<PercentageSatsF64>(
|
||||
&cfg.name("supply_rel_to_circulating_supply"),
|
||||
cfg.version + v1,
|
||||
supply.indexes_to_supply.sats_dateindex.boxed_clone(),
|
||||
&supply.indexes_to_supply.sats,
|
||||
global_supply_sats_dateindex.unwrap().boxed_clone(),
|
||||
global_supply_sats.unwrap(),
|
||||
)
|
||||
}),
|
||||
@@ -159,20 +170,23 @@ impl RelativeMetrics {
|
||||
supply.height_to_supply_value.bitcoin.boxed_clone(),
|
||||
),
|
||||
indexes_to_supply_in_profit_rel_to_own_supply:
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageSatsF64>(
|
||||
BinaryDateLast::from_both_derived_last::<PercentageSatsF64>(
|
||||
&cfg.name("supply_in_profit_rel_to_own_supply"),
|
||||
cfg.version + v1,
|
||||
unrealized.dateindex_to_supply_in_profit.boxed_clone(),
|
||||
&unrealized.indexes_to_supply_in_profit.sats,
|
||||
supply.indexes_to_supply.sats_dateindex.boxed_clone(),
|
||||
&supply.indexes_to_supply.sats,
|
||||
),
|
||||
indexes_to_supply_in_loss_rel_to_own_supply:
|
||||
BinaryDateLast::from_both_derived_last::<PercentageSatsF64>(
|
||||
&cfg.name("supply_in_loss_rel_to_own_supply"),
|
||||
cfg.version + v1,
|
||||
unrealized.dateindex_to_supply_in_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_supply_in_loss.sats,
|
||||
supply.indexes_to_supply.sats_dateindex.boxed_clone(),
|
||||
&supply.indexes_to_supply.sats,
|
||||
),
|
||||
indexes_to_supply_in_loss_rel_to_own_supply: LazyVecsFrom2FromDateIndex::from_computed::<
|
||||
PercentageSatsF64,
|
||||
>(
|
||||
&cfg.name("supply_in_loss_rel_to_own_supply"),
|
||||
cfg.version + v1,
|
||||
&unrealized.indexes_to_supply_in_loss.sats,
|
||||
&supply.indexes_to_supply.sats,
|
||||
),
|
||||
|
||||
// === Supply in Profit/Loss Relative to Circulating Supply (lazy from global supply) ===
|
||||
height_to_supply_in_profit_rel_to_circulating_supply: (compute_rel_to_all
|
||||
@@ -204,20 +218,24 @@ impl RelativeMetrics {
|
||||
indexes_to_supply_in_profit_rel_to_circulating_supply: (compute_rel_to_all
|
||||
&& global_supply_sats.is_some())
|
||||
.then(|| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageSatsF64>(
|
||||
BinaryDateLast::from_both_derived_last::<PercentageSatsF64>(
|
||||
&cfg.name("supply_in_profit_rel_to_circulating_supply"),
|
||||
cfg.version + v1,
|
||||
unrealized.dateindex_to_supply_in_profit.boxed_clone(),
|
||||
&unrealized.indexes_to_supply_in_profit.sats,
|
||||
global_supply_sats_dateindex.unwrap().boxed_clone(),
|
||||
global_supply_sats.unwrap(),
|
||||
)
|
||||
}),
|
||||
indexes_to_supply_in_loss_rel_to_circulating_supply: (compute_rel_to_all
|
||||
&& global_supply_sats.is_some())
|
||||
.then(|| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageSatsF64>(
|
||||
BinaryDateLast::from_both_derived_last::<PercentageSatsF64>(
|
||||
&cfg.name("supply_in_loss_rel_to_circulating_supply"),
|
||||
cfg.version + v1,
|
||||
unrealized.dateindex_to_supply_in_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_supply_in_loss.sats,
|
||||
global_supply_sats_dateindex.unwrap().boxed_clone(),
|
||||
global_supply_sats.unwrap(),
|
||||
)
|
||||
}),
|
||||
@@ -255,32 +273,36 @@ impl RelativeMetrics {
|
||||
mc.boxed_clone(),
|
||||
)
|
||||
}),
|
||||
// KISS: market_cap is now ComputedVecsDateLast
|
||||
indexes_to_unrealized_profit_rel_to_market_cap: global_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<PercentageDollarsF32>(
|
||||
&cfg.name("unrealized_profit_rel_to_market_cap"),
|
||||
cfg.version + v2,
|
||||
unrealized.dateindex_to_unrealized_profit.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_profit,
|
||||
mc,
|
||||
)
|
||||
}),
|
||||
indexes_to_unrealized_loss_rel_to_market_cap: global_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<PercentageDollarsF32>(
|
||||
&cfg.name("unrealized_loss_rel_to_market_cap"),
|
||||
cfg.version + v2,
|
||||
unrealized.dateindex_to_unrealized_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
mc,
|
||||
)
|
||||
}),
|
||||
indexes_to_neg_unrealized_loss_rel_to_market_cap: global_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<NegPercentageDollarsF32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<NegPercentageDollarsF32>(
|
||||
&cfg.name("neg_unrealized_loss_rel_to_market_cap"),
|
||||
cfg.version + v2,
|
||||
unrealized.dateindex_to_unrealized_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
mc,
|
||||
)
|
||||
}),
|
||||
indexes_to_net_unrealized_pnl_rel_to_market_cap: global_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
BinaryDateLast::from_computed_both_last::<PercentageDollarsF32>(
|
||||
&cfg.name("net_unrealized_pnl_rel_to_market_cap"),
|
||||
cfg.version + v2,
|
||||
&unrealized.indexes_to_net_unrealized_pnl,
|
||||
@@ -290,7 +312,7 @@ impl RelativeMetrics {
|
||||
|
||||
// NUPL is a proxy for net_unrealized_pnl_rel_to_market_cap
|
||||
indexes_to_nupl: global_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
BinaryDateLast::from_computed_both_last::<PercentageDollarsF32>(
|
||||
&cfg.name("nupl"),
|
||||
cfg.version + v2,
|
||||
&unrealized.indexes_to_net_unrealized_pnl,
|
||||
@@ -347,12 +369,14 @@ impl RelativeMetrics {
|
||||
})
|
||||
})
|
||||
.flatten(),
|
||||
// KISS: own_market_cap is now ComputedVecsDateLast
|
||||
indexes_to_unrealized_profit_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
own_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<PercentageDollarsF32>(
|
||||
&cfg.name("unrealized_profit_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
unrealized.dateindex_to_unrealized_profit.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_profit,
|
||||
mc,
|
||||
)
|
||||
@@ -362,9 +386,10 @@ impl RelativeMetrics {
|
||||
indexes_to_unrealized_loss_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
own_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<PercentageDollarsF32>(
|
||||
&cfg.name("unrealized_loss_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
unrealized.dateindex_to_unrealized_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
mc,
|
||||
)
|
||||
@@ -374,9 +399,10 @@ impl RelativeMetrics {
|
||||
indexes_to_neg_unrealized_loss_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
own_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<NegPercentageDollarsF32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<NegPercentageDollarsF32>(
|
||||
&cfg.name("neg_unrealized_loss_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
unrealized.dateindex_to_unrealized_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
mc,
|
||||
)
|
||||
@@ -386,7 +412,7 @@ impl RelativeMetrics {
|
||||
indexes_to_net_unrealized_pnl_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
own_market_cap.map(|mc| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
BinaryDateLast::from_computed_both_last::<PercentageDollarsF32>(
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
&unrealized.indexes_to_net_unrealized_pnl,
|
||||
@@ -430,31 +456,34 @@ impl RelativeMetrics {
|
||||
)
|
||||
}),
|
||||
indexes_to_unrealized_profit_rel_to_own_total_unrealized_pnl: extended.then(|| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<Ratio32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<Ratio32>(
|
||||
&cfg.name("unrealized_profit_rel_to_own_total_unrealized_pnl"),
|
||||
cfg.version + v1,
|
||||
unrealized.dateindex_to_unrealized_profit.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_profit,
|
||||
&unrealized.indexes_to_total_unrealized_pnl,
|
||||
)
|
||||
}),
|
||||
indexes_to_unrealized_loss_rel_to_own_total_unrealized_pnl: extended.then(|| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<Ratio32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<Ratio32>(
|
||||
&cfg.name("unrealized_loss_rel_to_own_total_unrealized_pnl"),
|
||||
cfg.version + v1,
|
||||
unrealized.dateindex_to_unrealized_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
&unrealized.indexes_to_total_unrealized_pnl,
|
||||
)
|
||||
}),
|
||||
indexes_to_neg_unrealized_loss_rel_to_own_total_unrealized_pnl: extended.then(|| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<NegRatio32>(
|
||||
BinaryDateLast::from_derived_last_and_computed_last::<NegRatio32>(
|
||||
&cfg.name("neg_unrealized_loss_rel_to_own_total_unrealized_pnl"),
|
||||
cfg.version + v1,
|
||||
unrealized.dateindex_to_unrealized_loss.boxed_clone(),
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
&unrealized.indexes_to_total_unrealized_pnl,
|
||||
)
|
||||
}),
|
||||
indexes_to_net_unrealized_pnl_rel_to_own_total_unrealized_pnl: extended.then(|| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<Ratio32>(
|
||||
BinaryDateLast::from_computed_both_last::<Ratio32>(
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_total_unrealized_pnl"),
|
||||
cfg.version + v1,
|
||||
&unrealized.indexes_to_net_unrealized_pnl,
|
||||
|
||||
@@ -10,9 +10,8 @@ use vecdb::{
|
||||
use crate::{
|
||||
ComputeIndexes, indexes,
|
||||
internal::{
|
||||
ComputedHeightValueVecs, ComputedValueVecsFromDateIndex, ComputedVecsFromHeight,
|
||||
HalfClosePriceTimesSats, HalveDollars, HalveSats, HalveSatsToBitcoin, LazyHeightValueVecs,
|
||||
LazyValueVecsFromDateIndex, Source, VecBuilderOptions,
|
||||
DerivedComputedBlockLast, HalfClosePriceTimesSats, HalveDollars, HalveSats,
|
||||
HalveSatsToBitcoin, LazyBlockValue, LazyDerivedBlockValue, LazyValueDateLast, ValueDateLast,
|
||||
},
|
||||
price,
|
||||
};
|
||||
@@ -22,26 +21,13 @@ use super::ImportConfig;
|
||||
/// Supply and UTXO count metrics for a cohort.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct SupplyMetrics {
|
||||
/// Total supply at each height
|
||||
pub height_to_supply: EagerVec<PcoVec<Height, Sats>>,
|
||||
|
||||
/// Supply value in BTC and USD (computed from height_to_supply)
|
||||
pub height_to_supply_value: ComputedHeightValueVecs,
|
||||
|
||||
/// Supply indexed by date
|
||||
pub indexes_to_supply: ComputedValueVecsFromDateIndex,
|
||||
|
||||
/// UTXO count at each height
|
||||
pub height_to_supply_value: LazyDerivedBlockValue,
|
||||
pub indexes_to_supply: ValueDateLast,
|
||||
pub height_to_utxo_count: EagerVec<PcoVec<Height, StoredU64>>,
|
||||
|
||||
/// UTXO count indexed by various dimensions
|
||||
pub indexes_to_utxo_count: ComputedVecsFromHeight<StoredU64>,
|
||||
|
||||
/// Half of supply value (used for computing median) - lazy from supply_value
|
||||
pub height_to_supply_half_value: LazyHeightValueVecs,
|
||||
|
||||
/// Half of supply indexed by date - lazy from indexes_to_supply
|
||||
pub indexes_to_supply_half: LazyValueVecsFromDateIndex,
|
||||
pub indexes_to_utxo_count: DerivedComputedBlockLast<StoredU64>,
|
||||
pub height_to_supply_half_value: LazyBlockValue,
|
||||
pub indexes_to_supply_half: LazyValueDateLast,
|
||||
}
|
||||
|
||||
impl SupplyMetrics {
|
||||
@@ -49,7 +35,6 @@ impl SupplyMetrics {
|
||||
pub fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let v1 = Version::ONE;
|
||||
let compute_dollars = cfg.compute_dollars();
|
||||
let last = VecBuilderOptions::default().add_last();
|
||||
|
||||
let height_to_supply: EagerVec<PcoVec<Height, Sats>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("supply"), cfg.version)?;
|
||||
@@ -58,26 +43,23 @@ impl SupplyMetrics {
|
||||
.price
|
||||
.map(|p| p.usd.chainindexes_to_price_close.height.boxed_clone());
|
||||
|
||||
let height_to_supply_value = ComputedHeightValueVecs::forced_import(
|
||||
cfg.db,
|
||||
let height_to_supply_value = LazyDerivedBlockValue::from_source(
|
||||
&cfg.name("supply"),
|
||||
Source::Vec(height_to_supply.boxed_clone()),
|
||||
height_to_supply.boxed_clone(),
|
||||
cfg.version,
|
||||
price_source.clone(),
|
||||
)?;
|
||||
);
|
||||
|
||||
let indexes_to_supply = ComputedValueVecsFromDateIndex::forced_import(
|
||||
let indexes_to_supply = ValueDateLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("supply"),
|
||||
Source::Compute,
|
||||
cfg.version + v1,
|
||||
last,
|
||||
compute_dollars,
|
||||
cfg.indexes,
|
||||
)?;
|
||||
|
||||
// Create lazy supply_half from supply sources
|
||||
let height_to_supply_half_value = LazyHeightValueVecs::from_sources::<
|
||||
let height_to_supply_half_value = LazyBlockValue::from_sources::<
|
||||
HalveSats,
|
||||
HalveSatsToBitcoin,
|
||||
HalfClosePriceTimesSats,
|
||||
@@ -89,7 +71,7 @@ impl SupplyMetrics {
|
||||
);
|
||||
|
||||
let indexes_to_supply_half =
|
||||
LazyValueVecsFromDateIndex::from_source::<HalveSats, HalveSatsToBitcoin, HalveDollars>(
|
||||
LazyValueDateLast::from_source::<HalveSats, HalveSatsToBitcoin, HalveDollars>(
|
||||
&cfg.name("supply_half"),
|
||||
&indexes_to_supply,
|
||||
cfg.version,
|
||||
@@ -99,13 +81,12 @@ impl SupplyMetrics {
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("utxo_count"), cfg.version)?;
|
||||
|
||||
Ok(Self {
|
||||
indexes_to_utxo_count: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_utxo_count: DerivedComputedBlockLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("utxo_count"),
|
||||
Source::Vec(height_to_utxo_count.boxed_clone()),
|
||||
height_to_utxo_count.boxed_clone(),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
height_to_supply,
|
||||
height_to_supply_value,
|
||||
@@ -208,11 +189,11 @@ impl SupplyMetrics {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_utxo_count.compute_rest(
|
||||
self.indexes_to_utxo_count.derive_from(
|
||||
indexes,
|
||||
starting_indexes,
|
||||
&self.height_to_utxo_count,
|
||||
exit,
|
||||
Some(&self.height_to_utxo_count),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -11,8 +11,8 @@ use crate::{
|
||||
ComputeIndexes,
|
||||
distribution::state::UnrealizedState,
|
||||
internal::{
|
||||
ComputedHeightValueVecs, ComputedValueVecsFromDateIndex, ComputedVecsFromDateIndex,
|
||||
DollarsMinus, DollarsPlus, LazyVecsFromDateIndex, Source, VecBuilderOptions,
|
||||
ComputedDateLast, DerivedDateLast, DollarsMinus, DollarsPlus, LazyDateLast,
|
||||
LazyDerivedBlockValue, ValueDerivedDateLast,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -23,42 +23,41 @@ use super::ImportConfig;
|
||||
pub struct UnrealizedMetrics {
|
||||
// === Supply in Profit/Loss ===
|
||||
pub height_to_supply_in_profit: EagerVec<PcoVec<Height, Sats>>,
|
||||
pub indexes_to_supply_in_profit: ComputedValueVecsFromDateIndex,
|
||||
pub indexes_to_supply_in_profit: ValueDerivedDateLast,
|
||||
pub height_to_supply_in_loss: EagerVec<PcoVec<Height, Sats>>,
|
||||
pub indexes_to_supply_in_loss: ComputedValueVecsFromDateIndex,
|
||||
pub indexes_to_supply_in_loss: ValueDerivedDateLast,
|
||||
pub dateindex_to_supply_in_profit: EagerVec<PcoVec<DateIndex, Sats>>,
|
||||
pub dateindex_to_supply_in_loss: EagerVec<PcoVec<DateIndex, Sats>>,
|
||||
pub height_to_supply_in_profit_value: ComputedHeightValueVecs,
|
||||
pub height_to_supply_in_loss_value: ComputedHeightValueVecs,
|
||||
pub height_to_supply_in_profit_value: LazyDerivedBlockValue,
|
||||
pub height_to_supply_in_loss_value: LazyDerivedBlockValue,
|
||||
|
||||
// === Unrealized Profit/Loss ===
|
||||
pub height_to_unrealized_profit: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_unrealized_profit: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_unrealized_profit: DerivedDateLast<Dollars>,
|
||||
pub height_to_unrealized_loss: EagerVec<PcoVec<Height, Dollars>>,
|
||||
pub indexes_to_unrealized_loss: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_unrealized_loss: DerivedDateLast<Dollars>,
|
||||
pub dateindex_to_unrealized_profit: EagerVec<PcoVec<DateIndex, Dollars>>,
|
||||
pub dateindex_to_unrealized_loss: EagerVec<PcoVec<DateIndex, Dollars>>,
|
||||
|
||||
// === Negated and Net ===
|
||||
pub height_to_neg_unrealized_loss: LazyVecFrom1<Height, Dollars, Height, Dollars>,
|
||||
pub indexes_to_neg_unrealized_loss: LazyVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_neg_unrealized_loss: LazyDateLast<Dollars>,
|
||||
|
||||
// net = profit - loss (height is lazy, indexes computed)
|
||||
pub height_to_net_unrealized_pnl:
|
||||
LazyVecFrom2<Height, Dollars, Height, Dollars, Height, Dollars>,
|
||||
pub indexes_to_net_unrealized_pnl: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_net_unrealized_pnl: ComputedDateLast<Dollars>,
|
||||
|
||||
// total = profit + loss (height is lazy, indexes computed)
|
||||
pub height_to_total_unrealized_pnl:
|
||||
LazyVecFrom2<Height, Dollars, Height, Dollars, Height, Dollars>,
|
||||
pub indexes_to_total_unrealized_pnl: ComputedVecsFromDateIndex<Dollars>,
|
||||
pub indexes_to_total_unrealized_pnl: ComputedDateLast<Dollars>,
|
||||
}
|
||||
|
||||
impl UnrealizedMetrics {
|
||||
/// Import unrealized metrics from database.
|
||||
pub fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let compute_dollars = cfg.compute_dollars();
|
||||
let last = VecBuilderOptions::default().add_last();
|
||||
|
||||
let dateindex_to_supply_in_profit =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("supply_in_profit"), cfg.version)?;
|
||||
@@ -76,33 +75,29 @@ impl UnrealizedMetrics {
|
||||
height_to_unrealized_loss.boxed_clone(),
|
||||
);
|
||||
|
||||
let indexes_to_unrealized_loss = ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
let indexes_to_unrealized_loss = DerivedDateLast::from_source(
|
||||
&cfg.name("unrealized_loss"),
|
||||
Source::Vec(dateindex_to_unrealized_loss.boxed_clone()),
|
||||
cfg.version,
|
||||
dateindex_to_unrealized_loss.boxed_clone(),
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?;
|
||||
);
|
||||
|
||||
let indexes_to_neg_unrealized_loss = LazyVecsFromDateIndex::from_computed::<Negate>(
|
||||
let indexes_to_neg_unrealized_loss = LazyDateLast::from_derived::<Negate>(
|
||||
&cfg.name("neg_unrealized_loss"),
|
||||
cfg.version,
|
||||
Some(dateindex_to_unrealized_loss.boxed_clone()),
|
||||
dateindex_to_unrealized_loss.boxed_clone(),
|
||||
&indexes_to_unrealized_loss,
|
||||
);
|
||||
|
||||
// Extract profit sources for lazy net/total vecs
|
||||
let height_to_unrealized_profit: EagerVec<PcoVec<Height, Dollars>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("unrealized_profit"), cfg.version)?;
|
||||
let indexes_to_unrealized_profit = ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
let indexes_to_unrealized_profit = DerivedDateLast::from_source(
|
||||
&cfg.name("unrealized_profit"),
|
||||
Source::Vec(dateindex_to_unrealized_profit.boxed_clone()),
|
||||
cfg.version,
|
||||
dateindex_to_unrealized_profit.boxed_clone(),
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?;
|
||||
);
|
||||
|
||||
// Create lazy height vecs from profit/loss sources
|
||||
let height_to_net_unrealized_pnl = LazyVecFrom2::transformed::<DollarsMinus>(
|
||||
@@ -119,21 +114,17 @@ impl UnrealizedMetrics {
|
||||
);
|
||||
|
||||
// indexes_to_net/total remain computed (needed by relative.rs)
|
||||
let indexes_to_net_unrealized_pnl = ComputedVecsFromDateIndex::forced_import(
|
||||
let indexes_to_net_unrealized_pnl = ComputedDateLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_unrealized_pnl"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?;
|
||||
let indexes_to_total_unrealized_pnl = ComputedVecsFromDateIndex::forced_import(
|
||||
let indexes_to_total_unrealized_pnl = ComputedDateLast::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("total_unrealized_pnl"),
|
||||
Source::Compute,
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?;
|
||||
|
||||
let height_to_supply_in_profit: EagerVec<PcoVec<Height, Sats>> =
|
||||
@@ -145,40 +136,36 @@ impl UnrealizedMetrics {
|
||||
.price
|
||||
.map(|p| p.usd.chainindexes_to_price_close.height.boxed_clone());
|
||||
|
||||
let height_to_supply_in_profit_value = ComputedHeightValueVecs::forced_import(
|
||||
cfg.db,
|
||||
let height_to_supply_in_profit_value = LazyDerivedBlockValue::from_source(
|
||||
&cfg.name("supply_in_profit"),
|
||||
Source::Vec(height_to_supply_in_profit.boxed_clone()),
|
||||
height_to_supply_in_profit.boxed_clone(),
|
||||
cfg.version,
|
||||
price_source.clone(),
|
||||
)?;
|
||||
let height_to_supply_in_loss_value = ComputedHeightValueVecs::forced_import(
|
||||
cfg.db,
|
||||
);
|
||||
let height_to_supply_in_loss_value = LazyDerivedBlockValue::from_source(
|
||||
&cfg.name("supply_in_loss"),
|
||||
Source::Vec(height_to_supply_in_loss.boxed_clone()),
|
||||
height_to_supply_in_loss.boxed_clone(),
|
||||
cfg.version,
|
||||
price_source,
|
||||
)?;
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
// === Supply in Profit/Loss ===
|
||||
height_to_supply_in_profit,
|
||||
indexes_to_supply_in_profit: ComputedValueVecsFromDateIndex::forced_import(
|
||||
indexes_to_supply_in_profit: ValueDerivedDateLast::from_source(
|
||||
cfg.db,
|
||||
&cfg.name("supply_in_profit"),
|
||||
Source::Vec(dateindex_to_supply_in_profit.boxed_clone()),
|
||||
dateindex_to_supply_in_profit.boxed_clone(),
|
||||
cfg.version,
|
||||
last,
|
||||
compute_dollars,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
height_to_supply_in_loss,
|
||||
indexes_to_supply_in_loss: ComputedValueVecsFromDateIndex::forced_import(
|
||||
indexes_to_supply_in_loss: ValueDerivedDateLast::from_source(
|
||||
cfg.db,
|
||||
&cfg.name("supply_in_loss"),
|
||||
Source::Vec(dateindex_to_supply_in_loss.boxed_clone()),
|
||||
dateindex_to_supply_in_loss.boxed_clone(),
|
||||
cfg.version,
|
||||
last,
|
||||
compute_dollars,
|
||||
cfg.indexes,
|
||||
)?,
|
||||
@@ -362,31 +349,14 @@ impl UnrealizedMetrics {
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.indexes_to_supply_in_profit.compute_rest(
|
||||
price,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.dateindex_to_supply_in_profit),
|
||||
)?;
|
||||
// KISS: compute_rest doesn't need source vec - lazy vecs are set up during import
|
||||
self.indexes_to_supply_in_profit
|
||||
.compute_rest(price, starting_indexes, exit)?;
|
||||
|
||||
self.indexes_to_supply_in_loss.compute_rest(
|
||||
price,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.dateindex_to_supply_in_loss),
|
||||
)?;
|
||||
self.indexes_to_supply_in_loss
|
||||
.compute_rest(price, starting_indexes, exit)?;
|
||||
|
||||
self.indexes_to_unrealized_profit.compute_rest(
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.dateindex_to_unrealized_profit),
|
||||
)?;
|
||||
|
||||
self.indexes_to_unrealized_loss.compute_rest(
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.dateindex_to_unrealized_loss),
|
||||
)?;
|
||||
// indexes_to_unrealized_profit/loss are Derived - no compute needed (lazy only)
|
||||
|
||||
// height_to_net/total are lazy, but indexes still need compute
|
||||
// total_unrealized_pnl = profit + loss
|
||||
|
||||
@@ -2,12 +2,9 @@ use std::path::Path;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_types::{Sats, SupplyState};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
|
||||
use super::{
|
||||
super::cost_basis::RealizedState,
|
||||
base::CohortState,
|
||||
};
|
||||
use super::{super::cost_basis::RealizedState, base::CohortState};
|
||||
|
||||
#[derive(Clone, Deref, DerefMut)]
|
||||
pub struct UTXOCohortState(CohortState);
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::{
|
||||
|
||||
use brk_error::{Error, Result};
|
||||
use brk_types::{CentsCompact, Dollars, Height, Sats, SupplyState};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use pco::standalone::{simple_decompress, simpler_compress};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::{
|
||||
state::BlockState,
|
||||
},
|
||||
indexes, inputs,
|
||||
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
|
||||
internal::ComputedBlockLast,
|
||||
outputs, price, transactions,
|
||||
};
|
||||
|
||||
@@ -49,8 +49,8 @@ pub struct Vecs {
|
||||
|
||||
pub addresstype_to_indexes_to_addr_count: AddressTypeToIndexesToAddressCount,
|
||||
pub addresstype_to_indexes_to_empty_addr_count: AddressTypeToIndexesToAddressCount,
|
||||
pub indexes_to_addr_count: ComputedVecsFromHeight<StoredU64>,
|
||||
pub indexes_to_empty_addr_count: ComputedVecsFromHeight<StoredU64>,
|
||||
pub indexes_to_addr_count: ComputedBlockLast<StoredU64>,
|
||||
pub indexes_to_empty_addr_count: ComputedBlockLast<StoredU64>,
|
||||
pub loadedaddressindex_to_loadedaddressindex:
|
||||
LazyVecFrom1<LoadedAddressIndex, LoadedAddressIndex, LoadedAddressIndex, LoadedAddressData>,
|
||||
pub emptyaddressindex_to_emptyaddressindex:
|
||||
@@ -123,21 +123,17 @@ impl Vecs {
|
||||
.with_saved_stamped_changes(SAVED_STAMPED_CHANGES),
|
||||
)?,
|
||||
|
||||
indexes_to_addr_count: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_addr_count: ComputedBlockLast::forced_import(
|
||||
&db,
|
||||
"addr_count",
|
||||
Source::Compute,
|
||||
version,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
indexes_to_empty_addr_count: ComputedVecsFromHeight::forced_import(
|
||||
indexes_to_empty_addr_count: ComputedBlockLast::forced_import(
|
||||
&db,
|
||||
"empty_addr_count",
|
||||
Source::Compute,
|
||||
version,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_last(),
|
||||
)?,
|
||||
|
||||
addresstype_to_indexes_to_addr_count:
|
||||
@@ -380,11 +376,12 @@ impl Vecs {
|
||||
.as_ref()
|
||||
.cloned();
|
||||
|
||||
// KISS: dateindex is no longer Option, just clone directly
|
||||
let dateindex_to_market_cap = supply_metrics
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.and_then(|v| v.dateindex.as_ref().cloned());
|
||||
.map(|v| v.dateindex.clone());
|
||||
|
||||
let height_to_market_cap_ref = height_to_market_cap.as_ref();
|
||||
let dateindex_to_market_cap_ref = dateindex_to_market_cap.as_ref();
|
||||
|
||||
Reference in New Issue
Block a user