global: snapshot

This commit is contained in:
nym21
2026-03-01 21:20:47 +01:00
parent 4abb00b86d
commit 159c983a3f
27 changed files with 246 additions and 172 deletions
+20 -14
View File
@@ -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,
)?;
@@ -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<Self> {
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)?,
})
}
}
+7 -7
View File
@@ -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<M: StorageMode = Rw> {
pub thermo_cap: ComputedFromHeightLast<Dollars, M>,
pub investor_cap: ComputedFromHeightLast<Dollars, M>,
pub vaulted_cap: ComputedFromHeightLast<Dollars, M>,
pub active_cap: ComputedFromHeightLast<Dollars, M>,
pub cointime_cap: ComputedFromHeightLast<Dollars, M>,
pub thermo_cap: FiatFromHeightLast<Cents, M>,
pub investor_cap: FiatFromHeightLast<Cents, M>,
pub vaulted_cap: FiatFromHeightLast<Cents, M>,
pub active_cap: FiatFromHeightLast<Cents, M>,
pub cointime_cap: FiatFromHeightLast<Cents, M>,
}
@@ -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,
)?;
@@ -1091,8 +1091,9 @@ impl UTXOCohorts<Rw> {
.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<Rw> {
}
});
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<Rw> {
};
}
Cents::new((regret / Sats::ONE_BTC_U128) as u64).to_dollars()
Cents::new((regret / Sats::ONE_BTC_U128) as u64)
})
.collect::<Vec<_>>()
.try_into()
@@ -1158,6 +1159,7 @@ impl UTXOCohorts<Rw> {
.unrealized
.peak_regret_ext
.peak_regret
.cents
.height
.truncate_push(current_height, regret)?;
}
@@ -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,
)?;
@@ -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,
)?;
@@ -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,
)?;
@@ -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,
)?;
@@ -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,
)?;
@@ -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)?;
@@ -94,27 +94,27 @@ impl RelativeBase {
)?;
self.unrealized_profit_rel_to_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
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::<Dollars, Dollars, PercentageDollarsF32>(
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::<Dollars, Dollars, NegPercentageDollarsF32>(
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::<Dollars, Dollars, PercentageDollarsF32>(
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::<Dollars, Dollars, PercentageDollarsF32>(
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::<Dollars, Dollars, PercentageDollarsF32>(
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(())
}
@@ -69,19 +69,19 @@ impl RelativeExtendedOwnMarketCap {
) -> Result<()> {
self.unrealized_profit_rel_to_own_market_cap
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
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::<Dollars, Dollars, PercentageDollarsF32>(
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::<Dollars, Dollars, NegPercentageDollarsF32>(
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::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.net_unrealized_pnl.height, own_market_cap, exit,
max_from, &unrealized.net_unrealized_pnl.usd.height, own_market_cap, exit,
)?;
Ok(())
}
@@ -69,19 +69,19 @@ impl RelativeExtendedOwnPnl {
) -> Result<()> {
self.unrealized_profit_rel_to_own_total_unrealized_pnl
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.unrealized_profit.height, &unrealized.total_unrealized_pnl.height, exit,
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::<Dollars, Dollars, PercentageDollarsF32>(
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::<Dollars, Dollars, NegPercentageDollarsF32>(
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::<Dollars, Dollars, PercentageDollarsF32>(
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(())
}
@@ -35,6 +35,7 @@ impl RelativePeakRegret {
&mut self,
max_from: Height,
peak_regret: &impl ReadableVec<Height, Dollars>,
market_cap: &impl ReadableVec<Height, Dollars>,
exit: &Exit,
) -> Result<()> {
@@ -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<M: StorageMode = Rw> {
pub supply_in_loss: ValueFromHeightLast<M>,
// === Unrealized Profit/Loss ===
pub unrealized_profit: ComputedFromHeightLast<Dollars, M>,
pub unrealized_loss: ComputedFromHeightLast<Dollars, M>,
pub unrealized_profit: FiatFromHeightLast<Cents, M>,
pub unrealized_loss: FiatFromHeightLast<Cents, M>,
// === Invested Capital in Profit/Loss ===
pub invested_capital_in_profit: ComputedFromHeightLast<Dollars, M>,
pub invested_capital_in_loss: ComputedFromHeightLast<Dollars, M>,
pub invested_capital_in_profit: FiatFromHeightLast<Cents, M>,
pub invested_capital_in_loss: FiatFromHeightLast<Cents, M>,
// === Raw values for precise aggregation (used to compute pain/greed indices) ===
pub invested_capital_in_profit_raw: M::Stored<BytesVec<Height, CentsSats>>,
@@ -39,16 +42,16 @@ pub struct UnrealizedBase<M: StorageMode = Rw> {
pub investor_cap_in_loss_raw: M::Stored<BytesVec<Height, CentsSquaredSats>>,
// === Pain/Greed Indices ===
pub pain_index: ComputedFromHeightLast<Dollars, M>,
pub greed_index: ComputedFromHeightLast<Dollars, M>,
pub net_sentiment: ComputedFromHeightLast<Dollars, M>,
pub pain_index: FiatFromHeightLast<Cents, M>,
pub greed_index: FiatFromHeightLast<Cents, M>,
pub net_sentiment: FiatFromHeightLast<CentsSigned, M>,
// === Negated ===
pub neg_unrealized_loss: LazyFromHeightLast<Dollars>,
pub neg_unrealized_loss: LazyFromHeightLast<Dollars, Cents>,
// === Net and Total ===
pub net_unrealized_pnl: ComputedFromHeightLast<Dollars, M>,
pub total_unrealized_pnl: ComputedFromHeightLast<Dollars, M>,
pub net_unrealized_pnl: FiatFromHeightLast<CentsSigned, M>,
pub total_unrealized_pnl: FiatFromHeightLast<Cents, M>,
}
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::<Negate>(
let neg_unrealized_loss = LazyFromHeightLast::from_computed::<NegCentsUnsignedToDollars>(
&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::<Vec<_>>(),
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::<Vec<_>>(),
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::<Vec<_>>(),
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::<Vec<_>>(),
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::<Cents, Cents, CentsSubtractToCentsSigned>(
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::<Cents, Cents, CentsSubtractToCentsSigned>(
starting_indexes.height,
&self.greed_index.cents.height,
&self.pain_index.cents.height,
exit,
)?;
Ok(())
}
}
@@ -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<M: StorageMode = Rw> {
/// Unrealized peak regret: sum of (peak_price - reference_price) x supply
pub peak_regret: ComputedFromHeightLast<Dollars, M>,
pub peak_regret: FiatFromHeightLast<Cents, M>,
}
impl UnrealizedPeakRegret {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
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::<Vec<_>>(),
exit,
)?;
@@ -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<Self, Dollars>;
}
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<C: CentsType, M: StorageMode = Rw> {
pub cents: ComputedFromHeightLast<C, M>,
pub usd: LazyFromHeightLast<Dollars, C>,
}
impl<C: CentsType> FiatFromHeightLast<C> {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let cents = ComputedFromHeightLast::forced_import(
db,
&format!("{name}_cents"),
version,
indexes,
)?;
let usd = LazyFromHeightLast::from_computed::<C::ToDollars>(
&format!("{name}_usd"),
version,
cents.height.read_only_boxed_clone(),
&cents,
);
Ok(Self { cents, usd })
}
}
@@ -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::*;
@@ -32,12 +32,8 @@ impl Price<ComputedFromHeightLast<Cents>> {
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
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::<CentsUnsignedToDollars>(
&format!("{name}_usd"),
version,
@@ -51,26 +47,6 @@ impl Price<ComputedFromHeightLast<Cents>> {
);
Ok(Self { cents, usd, sats })
}
/// Wrap an already-imported ComputedFromHeightLast<Cents> with lazy USD + sats.
pub(crate) fn from_cents(
name: &str,
version: Version,
cents: ComputedFromHeightLast<Cents>,
) -> Self {
let usd = LazyFromHeightLast::from_computed::<CentsUnsignedToDollars>(
&format!("{name}_usd"),
version,
cents.height.read_only_boxed_clone(),
&cents,
);
let sats = LazyFromHeightLast::from_lazy::<DollarsToSatsFract, Cents>(
&format!("{name}_sats"),
version,
&usd,
);
Self { cents, usd, sats }
}
}
impl<ST> Price<LazyFromHeightLast<Cents, ST>>
@@ -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<Cents, Cents, CentsSigned> for CentsSubtractToCentsSigned {
#[inline(always)]
fn apply(a: Cents, b: Cents) -> CentsSigned {
CentsSigned::from(a.inner() as i64 - b.inner() as i64)
}
}
@@ -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::*;
@@ -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,
)?;
@@ -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,
)?;
@@ -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,
@@ -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<M: StorageMode = Rw> {
pub subsidy_dominance_7d: ComputedFromHeightLast<StoredF32, M>,
pub subsidy_dominance_30d: ComputedFromHeightLast<StoredF32, M>,
pub subsidy_dominance_1y: ComputedFromHeightLast<StoredF32, M>,
pub subsidy_usd_1y_sma: ComputedFromHeightLast<Dollars, M>,
pub subsidy_usd_1y_sma: FiatFromHeightLast<Cents, M>,
}
+8 -10
View File
@@ -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::<SatsIdentity, SatsToBitcoin, DollarsIdentity>(
"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::<DollarsIdentity, Cents>(