diff --git a/crates/brk_computer/src/cointime/cap/compute.rs b/crates/brk_computer/src/cointime/cap/compute.rs index 7e3cf618b..d428fc303 100644 --- a/crates/brk_computer/src/cointime/cap/compute.rs +++ b/crates/brk_computer/src/cointime/cap/compute.rs @@ -1,5 +1,5 @@ use brk_error::Result; -use brk_types::Dollars; +use brk_types::Cents; use vecdb::Exit; use super::super::{activity, value}; @@ -17,12 +17,12 @@ impl Vecs { value: &value::Vecs, exit: &Exit, ) -> Result<()> { - let realized_cap = &distribution + let realized_cap_cents = &distribution .utxo_cohorts .all .metrics .realized - .realized_cap + .realized_cap_cents .height; let circulating_supply = &distribution @@ -34,36 +34,42 @@ impl Vecs { .btc .height; - self.thermo_cap.height.compute_transform( + self.thermo_cap.cents.height.compute_transform( starting_indexes.height, - &mining.rewards.subsidy.cumulative.usd.height, + &mining.rewards.subsidy.cumulative.cents.height, |(i, v, ..)| (i, v), exit, )?; - self.investor_cap.height.compute_subtract( + self.investor_cap.cents.height.compute_subtract( starting_indexes.height, - realized_cap, - &self.thermo_cap.height, + realized_cap_cents, + &self.thermo_cap.cents.height, exit, )?; - self.vaulted_cap.height.compute_divide( + self.vaulted_cap.cents.height.compute_transform2( starting_indexes.height, - realized_cap, + realized_cap_cents, &activity.vaultedness.height, + |(i, cap, vaultedness, ..)| { + (i, Cents::from(f64::from(cap) / f64::from(vaultedness))) + }, exit, )?; - self.active_cap.height.compute_multiply( + self.active_cap.cents.height.compute_transform2( starting_indexes.height, - realized_cap, + realized_cap_cents, &activity.liveliness.height, + |(i, cap, liveliness, ..)| { + (i, Cents::from(f64::from(cap) * f64::from(liveliness))) + }, exit, )?; // cointime_cap = (cointime_value_destroyed_cumulative * circulating_supply) / coinblocks_stored_cumulative - self.cointime_cap.height.compute_transform3( + self.cointime_cap.cents.height.compute_transform3( starting_indexes.height, &value.cointime_value_destroyed.cumulative.height, circulating_supply, @@ -72,7 +78,7 @@ impl Vecs { let destroyed: f64 = *destroyed; let supply: f64 = supply.into(); let stored: f64 = *stored; - (i, Dollars::from(destroyed * supply / stored)) + (i, Cents::from(destroyed * supply / stored)) }, exit, )?; diff --git a/crates/brk_computer/src/cointime/cap/import.rs b/crates/brk_computer/src/cointime/cap/import.rs index eecce86e7..348836ebb 100644 --- a/crates/brk_computer/src/cointime/cap/import.rs +++ b/crates/brk_computer/src/cointime/cap/import.rs @@ -3,16 +3,16 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{indexes, internal::ComputedFromHeightLast}; +use crate::{indexes, internal::FiatFromHeightLast}; impl Vecs { pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { Ok(Self { - thermo_cap: ComputedFromHeightLast::forced_import(db, "thermo_cap", version, indexes)?, - investor_cap: ComputedFromHeightLast::forced_import(db, "investor_cap", version, indexes)?, - vaulted_cap: ComputedFromHeightLast::forced_import(db, "vaulted_cap", version, indexes)?, - active_cap: ComputedFromHeightLast::forced_import(db, "active_cap", version, indexes)?, - cointime_cap: ComputedFromHeightLast::forced_import(db, "cointime_cap", version, indexes)?, + thermo_cap: FiatFromHeightLast::forced_import(db, "thermo_cap", version, indexes)?, + investor_cap: FiatFromHeightLast::forced_import(db, "investor_cap", version, indexes)?, + vaulted_cap: FiatFromHeightLast::forced_import(db, "vaulted_cap", version, indexes)?, + active_cap: FiatFromHeightLast::forced_import(db, "active_cap", version, indexes)?, + cointime_cap: FiatFromHeightLast::forced_import(db, "cointime_cap", version, indexes)?, }) } } diff --git a/crates/brk_computer/src/cointime/cap/vecs.rs b/crates/brk_computer/src/cointime/cap/vecs.rs index cc37f3329..5607cf419 100644 --- a/crates/brk_computer/src/cointime/cap/vecs.rs +++ b/crates/brk_computer/src/cointime/cap/vecs.rs @@ -1,14 +1,14 @@ use brk_traversable::Traversable; -use brk_types::Dollars; +use brk_types::Cents; use vecdb::{Rw, StorageMode}; -use crate::internal::ComputedFromHeightLast; +use crate::internal::FiatFromHeightLast; #[derive(Traversable)] pub struct Vecs { - pub thermo_cap: ComputedFromHeightLast, - pub investor_cap: ComputedFromHeightLast, - pub vaulted_cap: ComputedFromHeightLast, - pub active_cap: ComputedFromHeightLast, - pub cointime_cap: ComputedFromHeightLast, + pub thermo_cap: FiatFromHeightLast, + pub investor_cap: FiatFromHeightLast, + pub vaulted_cap: FiatFromHeightLast, + pub active_cap: FiatFromHeightLast, + pub cointime_cap: FiatFromHeightLast, } diff --git a/crates/brk_computer/src/cointime/pricing/compute.rs b/crates/brk_computer/src/cointime/pricing/compute.rs index 292f22509..4a92efcf1 100644 --- a/crates/brk_computer/src/cointime/pricing/compute.rs +++ b/crates/brk_computer/src/cointime/pricing/compute.rs @@ -74,10 +74,10 @@ impl Vecs { self.true_market_mean.cents.height.compute_transform2( starting_indexes.height, - &cap.investor_cap.height, + &cap.investor_cap.cents.height, &supply.active_supply.btc.height, - |(i, cap_dollars, supply_btc, ..)| { - (i, Cents::from(f64::from(Cents::from(cap_dollars)) / f64::from(supply_btc))) + |(i, cap_cents, supply_btc, ..)| { + (i, Cents::from(f64::from(cap_cents) / f64::from(supply_btc))) }, exit, )?; @@ -93,10 +93,10 @@ impl Vecs { // cointime_price = cointime_cap / circulating_supply self.cointime_price.cents.height.compute_transform2( starting_indexes.height, - &cap.cointime_cap.height, + &cap.cointime_cap.cents.height, circulating_supply, - |(i, cap_dollars, supply_btc, ..)| { - (i, Cents::from(f64::from(Cents::from(cap_dollars)) / f64::from(supply_btc))) + |(i, cap_cents, supply_btc, ..)| { + (i, Cents::from(f64::from(cap_cents) / f64::from(supply_btc))) }, exit, )?; diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index 682c7d664..3cf8cfac1 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -1091,8 +1091,9 @@ impl UTXOCohorts { .unrealized .peak_regret_ext .peak_regret + .cents .height - .truncate_push(current_height, Dollars::ZERO)?; + .truncate_push(current_height, Cents::ZERO)?; } return Ok(()); } @@ -1116,12 +1117,12 @@ impl UTXOCohorts { } }); - let regrets: [Dollars; 21] = ranges + let regrets: [Cents; 21] = ranges .into_par_iter() .map(|(range_start, range_end)| { let effective_start = range_start.max(start_height); if effective_start >= range_end { - return Dollars::ZERO; + return Cents::ZERO; } let mut regret: u128 = 0; @@ -1146,7 +1147,7 @@ impl UTXOCohorts { }; } - Cents::new((regret / Sats::ONE_BTC_U128) as u64).to_dollars() + Cents::new((regret / Sats::ONE_BTC_U128) as u64) }) .collect::>() .try_into() @@ -1158,6 +1159,7 @@ impl UTXOCohorts { .unrealized .peak_regret_ext .peak_regret + .cents .height .truncate_push(current_height, regret)?; } diff --git a/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs b/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs index 2b2ce550e..21a08a65b 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/adjusted.rs @@ -122,7 +122,7 @@ impl AdjustedCohortMetrics { &self.supply.total.sats.height, height_to_market_cap, all_supply_sats, - &self.unrealized.peak_regret_ext.peak_regret.height, + &self.unrealized.peak_regret_ext.peak_regret.usd.height, exit, )?; diff --git a/crates/brk_computer/src/distribution/metrics/cohort/all.rs b/crates/brk_computer/src/distribution/metrics/cohort/all.rs index 81ba4a874..ba20387e8 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/all.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/all.rs @@ -160,7 +160,7 @@ impl AllCohortMetrics { &self.realized.base, &self.supply.total.sats.height, height_to_market_cap, - &self.unrealized.peak_regret_ext.peak_regret.height, + &self.unrealized.peak_regret_ext.peak_regret.usd.height, exit, )?; diff --git a/crates/brk_computer/src/distribution/metrics/cohort/extended.rs b/crates/brk_computer/src/distribution/metrics/cohort/extended.rs index a883b28b6..781c5dd2f 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/extended.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/extended.rs @@ -121,7 +121,7 @@ impl ExtendedCohortMetrics { height_to_market_cap, all_supply_sats, &self.supply.total.usd.height, - &self.unrealized.peak_regret_ext.peak_regret.height, + &self.unrealized.peak_regret_ext.peak_regret.usd.height, exit, )?; diff --git a/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs b/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs index 51a354e02..a766c9084 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/extended_adjusted.rs @@ -125,7 +125,7 @@ impl ExtendedAdjustedCohortMetrics { height_to_market_cap, all_supply_sats, &self.supply.total.usd.height, - &self.unrealized.peak_regret_ext.peak_regret.height, + &self.unrealized.peak_regret_ext.peak_regret.usd.height, exit, )?; diff --git a/crates/brk_computer/src/distribution/metrics/cohort/peak_regret.rs b/crates/brk_computer/src/distribution/metrics/cohort/peak_regret.rs index 7bf115e54..d4ae98f29 100644 --- a/crates/brk_computer/src/distribution/metrics/cohort/peak_regret.rs +++ b/crates/brk_computer/src/distribution/metrics/cohort/peak_regret.rs @@ -116,7 +116,7 @@ impl PeakRegretCohortMetrics { &self.supply.total.sats.height, height_to_market_cap, all_supply_sats, - &self.unrealized.peak_regret_ext.peak_regret.height, + &self.unrealized.peak_regret_ext.peak_regret.usd.height, exit, )?; diff --git a/crates/brk_computer/src/distribution/metrics/mod.rs b/crates/brk_computer/src/distribution/metrics/mod.rs index 2eae6d64b..2c70fc046 100644 --- a/crates/brk_computer/src/distribution/metrics/mod.rs +++ b/crates/brk_computer/src/distribution/metrics/mod.rs @@ -109,11 +109,12 @@ pub trait CohortMetricsBase: Send + Sync { .collect(); let values: Vec<_> = others .iter() - .map(|o| &o.unrealized_base().net_sentiment.height) + .map(|o| &o.unrealized_base().net_sentiment.cents.height) .collect(); self.unrealized_base_mut() .net_sentiment + .cents .height .compute_weighted_average_of_others(starting_indexes.height, &weights, &values, exit)?; @@ -133,11 +134,12 @@ pub trait CohortMetricsBase: Send + Sync { .collect(); let values: Vec<_> = others .iter() - .map(|o| &o.unrealized_base().net_sentiment.height) + .map(|o| &o.unrealized_base().net_sentiment.cents.height) .collect(); self.unrealized_base_mut() .net_sentiment + .cents .height .compute_weighted_average_of_others(starting_indexes.height, &weights, &values, exit)?; diff --git a/crates/brk_computer/src/distribution/metrics/relative/base.rs b/crates/brk_computer/src/distribution/metrics/relative/base.rs index ffaff7bac..cee7ebc26 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/base.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/base.rs @@ -94,27 +94,27 @@ impl RelativeBase { )?; self.unrealized_profit_rel_to_market_cap .compute_binary::( - max_from, &unrealized.unrealized_profit.height, market_cap, exit, + max_from, &unrealized.unrealized_profit.usd.height, market_cap, exit, )?; self.unrealized_loss_rel_to_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.height, market_cap, exit, + max_from, &unrealized.unrealized_loss.usd.height, market_cap, exit, )?; self.neg_unrealized_loss_rel_to_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.height, market_cap, exit, + max_from, &unrealized.unrealized_loss.usd.height, market_cap, exit, )?; self.net_unrealized_pnl_rel_to_market_cap .compute_binary::( - max_from, &unrealized.net_unrealized_pnl.height, market_cap, exit, + max_from, &unrealized.net_unrealized_pnl.usd.height, market_cap, exit, )?; self.invested_capital_in_profit_pct .compute_binary::( - max_from, &unrealized.invested_capital_in_profit.height, &realized.realized_cap.height, exit, + max_from, &unrealized.invested_capital_in_profit.usd.height, &realized.realized_cap.height, exit, )?; self.invested_capital_in_loss_pct .compute_binary::( - max_from, &unrealized.invested_capital_in_loss.height, &realized.realized_cap.height, exit, + max_from, &unrealized.invested_capital_in_loss.usd.height, &realized.realized_cap.height, exit, )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs b/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs index e8b625654..f0e5a408a 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/extended_own_market_cap.rs @@ -69,19 +69,19 @@ impl RelativeExtendedOwnMarketCap { ) -> Result<()> { self.unrealized_profit_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.unrealized_profit.height, own_market_cap, exit, + max_from, &unrealized.unrealized_profit.usd.height, own_market_cap, exit, )?; self.unrealized_loss_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.height, own_market_cap, exit, + max_from, &unrealized.unrealized_loss.usd.height, own_market_cap, exit, )?; self.neg_unrealized_loss_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.unrealized_loss.height, own_market_cap, exit, + max_from, &unrealized.unrealized_loss.usd.height, own_market_cap, exit, )?; self.net_unrealized_pnl_rel_to_own_market_cap .compute_binary::( - max_from, &unrealized.net_unrealized_pnl.height, own_market_cap, exit, + max_from, &unrealized.net_unrealized_pnl.usd.height, own_market_cap, exit, )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs b/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs index cd296d670..85baaecce 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/extended_own_pnl.rs @@ -69,19 +69,19 @@ impl RelativeExtendedOwnPnl { ) -> Result<()> { self.unrealized_profit_rel_to_own_total_unrealized_pnl .compute_binary::( - max_from, &unrealized.unrealized_profit.height, &unrealized.total_unrealized_pnl.height, exit, + max_from, &unrealized.unrealized_profit.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit, )?; self.unrealized_loss_rel_to_own_total_unrealized_pnl .compute_binary::( - max_from, &unrealized.unrealized_loss.height, &unrealized.total_unrealized_pnl.height, exit, + max_from, &unrealized.unrealized_loss.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit, )?; self.neg_unrealized_loss_rel_to_own_total_unrealized_pnl .compute_binary::( - max_from, &unrealized.unrealized_loss.height, &unrealized.total_unrealized_pnl.height, exit, + max_from, &unrealized.unrealized_loss.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit, )?; self.net_unrealized_pnl_rel_to_own_total_unrealized_pnl .compute_binary::( - max_from, &unrealized.net_unrealized_pnl.height, &unrealized.total_unrealized_pnl.height, exit, + max_from, &unrealized.net_unrealized_pnl.usd.height, &unrealized.total_unrealized_pnl.usd.height, exit, )?; Ok(()) } diff --git a/crates/brk_computer/src/distribution/metrics/relative/peak_regret.rs b/crates/brk_computer/src/distribution/metrics/relative/peak_regret.rs index 51f3d9227..84752e335 100644 --- a/crates/brk_computer/src/distribution/metrics/relative/peak_regret.rs +++ b/crates/brk_computer/src/distribution/metrics/relative/peak_regret.rs @@ -35,6 +35,7 @@ impl RelativePeakRegret { &mut self, max_from: Height, peak_regret: &impl ReadableVec, + market_cap: &impl ReadableVec, exit: &Exit, ) -> Result<()> { diff --git a/crates/brk_computer/src/distribution/metrics/unrealized/base.rs b/crates/brk_computer/src/distribution/metrics/unrealized/base.rs index 1d9ee1611..26e8e701d 100644 --- a/crates/brk_computer/src/distribution/metrics/unrealized/base.rs +++ b/crates/brk_computer/src/distribution/metrics/unrealized/base.rs @@ -1,8 +1,8 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Cents, CentsSats, CentsSquaredSats, Dollars, Height, Version}; +use brk_types::{Cents, CentsSats, CentsSigned, CentsSquaredSats, Height, Version}; use vecdb::{ - AnyStoredVec, AnyVec, BytesVec, Exit, ImportableVec, Negate, ReadableCloneableVec, ReadableVec, + AnyStoredVec, AnyVec, BytesVec, Exit, ImportableVec, ReadableCloneableVec, ReadableVec, Rw, StorageMode, WritableVec, }; @@ -10,11 +10,14 @@ use crate::{ ComputeIndexes, distribution::state::UnrealizedState, internal::{ - ComputedFromHeightLast, LazyFromHeightLast, ValueFromHeightLast, + CentsSubtractToCentsSigned, FiatFromHeightLast, LazyFromHeightLast, NegCentsUnsignedToDollars, + ValueFromHeightLast, }, prices, }; +use brk_types::Dollars; + use crate::distribution::metrics::ImportConfig; /// Base unrealized profit/loss metrics (always computed). @@ -25,12 +28,12 @@ pub struct UnrealizedBase { pub supply_in_loss: ValueFromHeightLast, // === Unrealized Profit/Loss === - pub unrealized_profit: ComputedFromHeightLast, - pub unrealized_loss: ComputedFromHeightLast, + pub unrealized_profit: FiatFromHeightLast, + pub unrealized_loss: FiatFromHeightLast, // === Invested Capital in Profit/Loss === - pub invested_capital_in_profit: ComputedFromHeightLast, - pub invested_capital_in_loss: ComputedFromHeightLast, + pub invested_capital_in_profit: FiatFromHeightLast, + pub invested_capital_in_loss: FiatFromHeightLast, // === Raw values for precise aggregation (used to compute pain/greed indices) === pub invested_capital_in_profit_raw: M::Stored>, @@ -39,16 +42,16 @@ pub struct UnrealizedBase { pub investor_cap_in_loss_raw: M::Stored>, // === Pain/Greed Indices === - pub pain_index: ComputedFromHeightLast, - pub greed_index: ComputedFromHeightLast, - pub net_sentiment: ComputedFromHeightLast, + pub pain_index: FiatFromHeightLast, + pub greed_index: FiatFromHeightLast, + pub net_sentiment: FiatFromHeightLast, // === Negated === - pub neg_unrealized_loss: LazyFromHeightLast, + pub neg_unrealized_loss: LazyFromHeightLast, // === Net and Total === - pub net_unrealized_pnl: ComputedFromHeightLast, - pub total_unrealized_pnl: ComputedFromHeightLast, + pub net_unrealized_pnl: FiatFromHeightLast, + pub total_unrealized_pnl: FiatFromHeightLast, } impl UnrealizedBase { @@ -66,26 +69,26 @@ impl UnrealizedBase { cfg.indexes, )?; - let unrealized_profit = ComputedFromHeightLast::forced_import( + let unrealized_profit = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("unrealized_profit"), cfg.version, cfg.indexes, )?; - let unrealized_loss = ComputedFromHeightLast::forced_import( + let unrealized_loss = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("unrealized_loss"), cfg.version, cfg.indexes, )?; - let invested_capital_in_profit = ComputedFromHeightLast::forced_import( + let invested_capital_in_profit = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("invested_capital_in_profit"), cfg.version, cfg.indexes, )?; - let invested_capital_in_loss = ComputedFromHeightLast::forced_import( + let invested_capital_in_loss = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("invested_capital_in_loss"), cfg.version, @@ -113,39 +116,39 @@ impl UnrealizedBase { cfg.version, )?; - let pain_index = ComputedFromHeightLast::forced_import( + let pain_index = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("pain_index"), cfg.version, cfg.indexes, )?; - let greed_index = ComputedFromHeightLast::forced_import( + let greed_index = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("greed_index"), cfg.version, cfg.indexes, )?; - let net_sentiment = ComputedFromHeightLast::forced_import( + let net_sentiment = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("net_sentiment"), cfg.version + Version::ONE, cfg.indexes, )?; - let neg_unrealized_loss = LazyFromHeightLast::from_computed::( + let neg_unrealized_loss = LazyFromHeightLast::from_computed::( &cfg.name("neg_unrealized_loss"), cfg.version, - unrealized_loss.height.read_only_boxed_clone(), - &unrealized_loss, + unrealized_loss.cents.height.read_only_boxed_clone(), + &unrealized_loss.cents, ); - let net_unrealized_pnl = ComputedFromHeightLast::forced_import( + let net_unrealized_pnl = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("net_unrealized_pnl"), cfg.version, cfg.indexes, )?; - let total_unrealized_pnl = ComputedFromHeightLast::forced_import( + let total_unrealized_pnl = FiatFromHeightLast::forced_import( cfg.db, &cfg.name("total_unrealized_pnl"), cfg.version, @@ -178,10 +181,10 @@ impl UnrealizedBase { .height .len() .min(self.supply_in_loss.sats.height.len()) - .min(self.unrealized_profit.height.len()) - .min(self.unrealized_loss.height.len()) - .min(self.invested_capital_in_profit.height.len()) - .min(self.invested_capital_in_loss.height.len()) + .min(self.unrealized_profit.cents.height.len()) + .min(self.unrealized_loss.cents.height.len()) + .min(self.invested_capital_in_profit.cents.height.len()) + .min(self.invested_capital_in_loss.cents.height.len()) .min(self.invested_capital_in_profit_raw.len()) .min(self.invested_capital_in_loss_raw.len()) .min(self.investor_cap_in_profit_raw.len()) @@ -202,17 +205,21 @@ impl UnrealizedBase { .height .truncate_push(height, height_state.supply_in_loss)?; self.unrealized_profit + .cents .height - .truncate_push(height, height_state.unrealized_profit.to_dollars())?; + .truncate_push(height, height_state.unrealized_profit)?; self.unrealized_loss + .cents .height - .truncate_push(height, height_state.unrealized_loss.to_dollars())?; + .truncate_push(height, height_state.unrealized_loss)?; self.invested_capital_in_profit + .cents .height - .truncate_push(height, height_state.invested_capital_in_profit.to_dollars())?; + .truncate_push(height, height_state.invested_capital_in_profit)?; self.invested_capital_in_loss + .cents .height - .truncate_push(height, height_state.invested_capital_in_loss.to_dollars())?; + .truncate_push(height, height_state.invested_capital_in_loss)?; self.invested_capital_in_profit_raw.truncate_push( height, @@ -240,10 +247,10 @@ impl UnrealizedBase { &mut self.supply_in_profit.base.cents.height as &mut dyn AnyStoredVec, &mut self.supply_in_loss.base.sats.height as &mut dyn AnyStoredVec, &mut self.supply_in_loss.base.cents.height as &mut dyn AnyStoredVec, - &mut self.unrealized_profit.height, - &mut self.unrealized_loss.height, - &mut self.invested_capital_in_profit.height, - &mut self.invested_capital_in_loss.height, + &mut self.unrealized_profit.cents.height, + &mut self.unrealized_loss.cents.height, + &mut self.invested_capital_in_profit.cents.height, + &mut self.invested_capital_in_loss.cents.height, &mut self.invested_capital_in_profit_raw as &mut dyn AnyStoredVec, &mut self.invested_capital_in_loss_raw as &mut dyn AnyStoredVec, &mut self.investor_cap_in_profit_raw as &mut dyn AnyStoredVec, @@ -280,40 +287,43 @@ impl UnrealizedBase { exit, )?; self.unrealized_profit + .cents .height .compute_sum_of_others( starting_indexes.height, &others .iter() - .map(|v| &v.unrealized_profit.height) + .map(|v| &v.unrealized_profit.cents.height) .collect::>(), exit, )?; - self.unrealized_loss.height.compute_sum_of_others( + self.unrealized_loss.cents.height.compute_sum_of_others( starting_indexes.height, &others .iter() - .map(|v| &v.unrealized_loss.height) + .map(|v| &v.unrealized_loss.cents.height) .collect::>(), exit, )?; self.invested_capital_in_profit + .cents .height .compute_sum_of_others( starting_indexes.height, &others .iter() - .map(|v| &v.invested_capital_in_profit.height) + .map(|v| &v.invested_capital_in_profit.cents.height) .collect::>(), exit, )?; self.invested_capital_in_loss + .cents .height .compute_sum_of_others( starting_indexes.height, &others .iter() - .map(|v| &v.invested_capital_in_loss.height) + .map(|v| &v.invested_capital_in_loss.cents.height) .collect::>(), exit, )?; @@ -386,55 +396,58 @@ impl UnrealizedBase { exit: &Exit, ) -> Result<()> { // Pain index: investor_price_of_losers - spot - self.pain_index.height.compute_transform3( + self.pain_index.cents.height.compute_transform3( starting_indexes.height, &self.investor_cap_in_loss_raw, &self.invested_capital_in_loss_raw, &prices.price.cents.height, |(h, investor_cap, invested_cap, spot, ..)| { if invested_cap.inner() == 0 { - return (h, Dollars::ZERO); + return (h, Cents::ZERO); } let investor_price_losers = investor_cap.inner() / invested_cap.inner(); let spot_u128 = spot.as_u128(); ( h, - Cents::new((investor_price_losers - spot_u128) as u64).to_dollars(), + Cents::new((investor_price_losers - spot_u128) as u64), ) }, exit, )?; // Greed index: spot - investor_price_of_winners - self.greed_index.height.compute_transform3( + self.greed_index.cents.height.compute_transform3( starting_indexes.height, &self.investor_cap_in_profit_raw, &self.invested_capital_in_profit_raw, &prices.price.cents.height, |(h, investor_cap, invested_cap, spot, ..)| { if invested_cap.inner() == 0 { - return (h, Dollars::ZERO); + return (h, Cents::ZERO); } let investor_price_winners = investor_cap.inner() / invested_cap.inner(); let spot_u128 = spot.as_u128(); ( h, - Cents::new((spot_u128 - investor_price_winners) as u64).to_dollars(), + Cents::new((spot_u128 - investor_price_winners) as u64), ) }, exit, )?; - self.net_unrealized_pnl.height.compute_subtract( + self.net_unrealized_pnl + .cents + .height + .compute_binary::( + starting_indexes.height, + &self.unrealized_profit.cents.height, + &self.unrealized_loss.cents.height, + exit, + )?; + self.total_unrealized_pnl.cents.height.compute_add( 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, + &self.unrealized_profit.cents.height, + &self.unrealized_loss.cents.height, exit, )?; @@ -447,11 +460,15 @@ impl UnrealizedBase { starting_indexes: &ComputeIndexes, exit: &Exit, ) -> Result<()> { - Ok(self.net_sentiment.height.compute_subtract( - starting_indexes.height, - &self.greed_index.height, - &self.pain_index.height, - exit, - )?) + self.net_sentiment + .cents + .height + .compute_binary::( + starting_indexes.height, + &self.greed_index.cents.height, + &self.pain_index.cents.height, + exit, + )?; + Ok(()) } } diff --git a/crates/brk_computer/src/distribution/metrics/unrealized/peak_regret.rs b/crates/brk_computer/src/distribution/metrics/unrealized/peak_regret.rs index c16e3cc57..a8a848f4f 100644 --- a/crates/brk_computer/src/distribution/metrics/unrealized/peak_regret.rs +++ b/crates/brk_computer/src/distribution/metrics/unrealized/peak_regret.rs @@ -1,9 +1,9 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::Dollars; +use brk_types::Cents; use vecdb::{AnyStoredVec, Exit, Rw, StorageMode}; -use crate::{ComputeIndexes, internal::ComputedFromHeightLast}; +use crate::{ComputeIndexes, internal::FiatFromHeightLast}; use crate::distribution::metrics::ImportConfig; @@ -11,13 +11,13 @@ use crate::distribution::metrics::ImportConfig; #[derive(Traversable)] pub struct UnrealizedPeakRegret { /// Unrealized peak regret: sum of (peak_price - reference_price) x supply - pub peak_regret: ComputedFromHeightLast, + pub peak_regret: FiatFromHeightLast, } impl UnrealizedPeakRegret { pub(crate) fn forced_import(cfg: &ImportConfig) -> Result { Ok(Self { - peak_regret: ComputedFromHeightLast::forced_import( + peak_regret: FiatFromHeightLast::forced_import( cfg.db, &cfg.name("unrealized_peak_regret"), cfg.version, @@ -27,7 +27,7 @@ impl UnrealizedPeakRegret { } pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { - vec![&mut self.peak_regret.height] + vec![&mut self.peak_regret.cents.height] } pub(crate) fn compute_from_stateful( @@ -36,11 +36,11 @@ impl UnrealizedPeakRegret { others: &[&Self], exit: &Exit, ) -> Result<()> { - self.peak_regret.height.compute_sum_of_others( + self.peak_regret.cents.height.compute_sum_of_others( starting_indexes.height, &others .iter() - .map(|v| &v.peak_regret.height) + .map(|v| &v.peak_regret.cents.height) .collect::>(), exit, )?; diff --git a/crates/brk_computer/src/internal/from_height/fiat.rs b/crates/brk_computer/src/internal/from_height/fiat.rs new file mode 100644 index 000000000..668caa7db --- /dev/null +++ b/crates/brk_computer/src/internal/from_height/fiat.rs @@ -0,0 +1,55 @@ +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Cents, CentsSigned, Dollars, Version}; +use schemars::JsonSchema; +use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode, UnaryTransform}; + +use super::{ComputedFromHeightLast, LazyFromHeightLast}; +use crate::{ + indexes, + internal::{CentsSignedToDollars, CentsUnsignedToDollars, NumericValue}, +}; + +/// Trait that associates a cents type with its transform to Dollars. +pub trait CentsType: NumericValue + JsonSchema { + type ToDollars: UnaryTransform; +} + +impl CentsType for Cents { + type ToDollars = CentsUnsignedToDollars; +} + +impl CentsType for CentsSigned { + type ToDollars = CentsSignedToDollars; +} + +/// Height-indexed fiat monetary value: cents (eager, integer) + usd (lazy, float). +/// Generic over `C` to support both `Cents` (unsigned) and `CentsSigned` (signed). +#[derive(Traversable)] +pub struct FiatFromHeightLast { + pub cents: ComputedFromHeightLast, + pub usd: LazyFromHeightLast, +} + +impl FiatFromHeightLast { + pub(crate) fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let cents = ComputedFromHeightLast::forced_import( + db, + &format!("{name}_cents"), + version, + indexes, + )?; + let usd = LazyFromHeightLast::from_computed::( + &format!("{name}_usd"), + version, + cents.height.read_only_boxed_clone(), + ¢s, + ); + Ok(Self { cents, usd }) + } +} diff --git a/crates/brk_computer/src/internal/from_height/mod.rs b/crates/brk_computer/src/internal/from_height/mod.rs index de1d96aaf..7e8beb393 100644 --- a/crates/brk_computer/src/internal/from_height/mod.rs +++ b/crates/brk_computer/src/internal/from_height/mod.rs @@ -1,6 +1,7 @@ mod by_unit; mod constant; mod cumulative; +mod fiat; mod cumulative_full; mod cumulative_sum; mod distribution; @@ -23,6 +24,7 @@ pub use by_unit::*; pub use constant::*; pub use cumulative::*; pub use cumulative_full::*; +pub use fiat::*; pub use cumulative_sum::*; pub use distribution::*; pub use full::*; diff --git a/crates/brk_computer/src/internal/from_height/price.rs b/crates/brk_computer/src/internal/from_height/price.rs index c4537ae15..386b2cec9 100644 --- a/crates/brk_computer/src/internal/from_height/price.rs +++ b/crates/brk_computer/src/internal/from_height/price.rs @@ -32,12 +32,8 @@ impl Price> { version: Version, indexes: &indexes::Vecs, ) -> Result { - let cents = ComputedFromHeightLast::forced_import( - db, - &format!("{name}_cents"), - version, - indexes, - )?; + let cents = + ComputedFromHeightLast::forced_import(db, &format!("{name}_cents"), version, indexes)?; let usd = LazyFromHeightLast::from_computed::( &format!("{name}_usd"), version, @@ -51,26 +47,6 @@ impl Price> { ); Ok(Self { cents, usd, sats }) } - - /// Wrap an already-imported ComputedFromHeightLast with lazy USD + sats. - pub(crate) fn from_cents( - name: &str, - version: Version, - cents: ComputedFromHeightLast, - ) -> Self { - let usd = LazyFromHeightLast::from_computed::( - &format!("{name}_usd"), - version, - cents.height.read_only_boxed_clone(), - ¢s, - ); - let sats = LazyFromHeightLast::from_lazy::( - &format!("{name}_sats"), - version, - &usd, - ); - Self { cents, usd, sats } - } } impl Price> diff --git a/crates/brk_computer/src/internal/transform/cents_subtract_to_cents_signed.rs b/crates/brk_computer/src/internal/transform/cents_subtract_to_cents_signed.rs new file mode 100644 index 000000000..cbe816f8e --- /dev/null +++ b/crates/brk_computer/src/internal/transform/cents_subtract_to_cents_signed.rs @@ -0,0 +1,13 @@ +use brk_types::{Cents, CentsSigned}; +use vecdb::BinaryTransform; + +/// (Cents, Cents) -> CentsSigned (a - b) +/// Produces a signed result from two unsigned inputs. +pub struct CentsSubtractToCentsSigned; + +impl BinaryTransform for CentsSubtractToCentsSigned { + #[inline(always)] + fn apply(a: Cents, b: Cents) -> CentsSigned { + CentsSigned::from(a.inner() as i64 - b.inner() as i64) + } +} diff --git a/crates/brk_computer/src/internal/transform/mod.rs b/crates/brk_computer/src/internal/transform/mod.rs index 4daf9d0ea..c4a60bd99 100644 --- a/crates/brk_computer/src/internal/transform/mod.rs +++ b/crates/brk_computer/src/internal/transform/mod.rs @@ -1,6 +1,7 @@ mod block_count_target; mod cents_plus; mod cents_signed_to_dollars; +mod cents_subtract_to_cents_signed; mod cents_times_tenths; mod cents_to_dollars; mod cents_to_sats; @@ -42,6 +43,7 @@ mod volatility_sqrt7; pub use block_count_target::*; pub use cents_plus::*; pub use cents_signed_to_dollars::*; +pub use cents_subtract_to_cents_signed::*; pub use cents_times_tenths::*; pub use cents_to_dollars::*; pub use cents_to_sats::*; diff --git a/crates/brk_computer/src/market/indicators/compute.rs b/crates/brk_computer/src/market/indicators/compute.rs index 5275efd65..b4026a265 100644 --- a/crates/brk_computer/src/market/indicators/compute.rs +++ b/crates/brk_computer/src/market/indicators/compute.rs @@ -28,7 +28,7 @@ impl Vecs { self.puell_multiple.height.compute_divide( starting_indexes.height, &rewards.subsidy.base.usd.height, - &rewards.subsidy_usd_1y_sma.height, + &rewards.subsidy_usd_1y_sma.usd.height, exit, )?; diff --git a/crates/brk_computer/src/mining/rewards/compute.rs b/crates/brk_computer/src/mining/rewards/compute.rs index 9100e7c47..d11cfeac1 100644 --- a/crates/brk_computer/src/mining/rewards/compute.rs +++ b/crates/brk_computer/src/mining/rewards/compute.rs @@ -190,10 +190,10 @@ impl Vecs { exit, )?; - self.subsidy_usd_1y_sma.height.compute_rolling_average( + self.subsidy_usd_1y_sma.cents.height.compute_rolling_average( starting_indexes.height, &count_vecs.height_1y_ago, - &self.subsidy.base.usd.height, + &self.subsidy.base.cents.height, exit, )?; diff --git a/crates/brk_computer/src/mining/rewards/import.rs b/crates/brk_computer/src/mining/rewards/import.rs index 79ae238d0..5f2923131 100644 --- a/crates/brk_computer/src/mining/rewards/import.rs +++ b/crates/brk_computer/src/mining/rewards/import.rs @@ -6,7 +6,7 @@ use super::Vecs; use crate::{ indexes, internal::{ - ComputedFromHeightLast, ValueFromHeightFull, + ComputedFromHeightLast, FiatFromHeightLast, ValueFromHeightFull, ValueFromHeightSumCumulative, }, }; @@ -87,7 +87,7 @@ impl Vecs { version, indexes, )?, - subsidy_usd_1y_sma: ComputedFromHeightLast::forced_import( + subsidy_usd_1y_sma: FiatFromHeightLast::forced_import( db, "subsidy_usd_1y_sma", version, diff --git a/crates/brk_computer/src/mining/rewards/vecs.rs b/crates/brk_computer/src/mining/rewards/vecs.rs index d030c6aa4..4849e18b1 100644 --- a/crates/brk_computer/src/mining/rewards/vecs.rs +++ b/crates/brk_computer/src/mining/rewards/vecs.rs @@ -1,9 +1,9 @@ use brk_traversable::Traversable; -use brk_types::{Dollars, StoredF32}; +use brk_types::{Cents, StoredF32}; use vecdb::{Rw, StorageMode}; use crate::internal::{ - ComputedFromHeightLast, ValueFromHeightFull, + ComputedFromHeightLast, FiatFromHeightLast, ValueFromHeightFull, ValueFromHeightSumCumulative, }; @@ -24,5 +24,5 @@ pub struct Vecs { pub subsidy_dominance_7d: ComputedFromHeightLast, pub subsidy_dominance_30d: ComputedFromHeightLast, pub subsidy_dominance_1y: ComputedFromHeightLast, - pub subsidy_usd_1y_sma: ComputedFromHeightLast, + pub subsidy_usd_1y_sma: FiatFromHeightLast, } diff --git a/crates/brk_computer/src/supply/import.rs b/crates/brk_computer/src/supply/import.rs index f42b8a76d..98e4e76f7 100644 --- a/crates/brk_computer/src/supply/import.rs +++ b/crates/brk_computer/src/supply/import.rs @@ -3,14 +3,13 @@ use std::path::Path; use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Cents, Version}; -use vecdb::{Database, ReadableCloneableVec, PAGE_SIZE}; +use vecdb::{Database, PAGE_SIZE}; use super::Vecs; use crate::{ distribution, indexes, internal::{ - ComputedFromHeightLast, DollarsIdentity, - LazyFromHeightLast, LazyValueFromHeightLast, + ComputedFromHeightLast, DollarsIdentity, LazyFromHeightLast, LazyValueFromHeightLast, SatsIdentity, SatsToBitcoin, }, }; @@ -31,11 +30,11 @@ impl Vecs { let supply_metrics = &distribution.utxo_cohorts.all.metrics.supply; // Circulating supply - lazy refs to distribution - let circulating = LazyValueFromHeightLast::from_block_source::( - "circulating_supply", - &supply_metrics.total, - version, - ); + let circulating = LazyValueFromHeightLast::from_block_source::< + SatsIdentity, + SatsToBitcoin, + DollarsIdentity, + >("circulating_supply", &supply_metrics.total, version); // Burned/unspendable supply - computed from scripts let burned = super::burned::Vecs::forced_import(&db, version, indexes)?; @@ -45,8 +44,7 @@ impl Vecs { ComputedFromHeightLast::forced_import(&db, "inflation_rate", version, indexes)?; // Velocity - let velocity = - super::velocity::Vecs::forced_import(&db, version, indexes)?; + let velocity = super::velocity::Vecs::forced_import(&db, version, indexes)?; // Market cap - lazy identity from distribution supply in USD let market_cap = LazyFromHeightLast::from_lazy::(