mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-11 11:08:13 -07:00
global: adding support for safe lengths
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{Bitcoin, Dollars, Indexes, StoredF32};
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{Bitcoin, Dollars, StoredF32};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::{Vecs, gini};
|
||||
@@ -9,33 +10,35 @@ impl Vecs {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
mining: &mining::Vecs,
|
||||
distribution: &distribution::Vecs,
|
||||
transactions: &transactions::Vecs,
|
||||
market: &market::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
let starting_lengths = indexer.safe_lengths();
|
||||
|
||||
// Puell Multiple: daily_subsidy_usd / sma_365d_subsidy_usd
|
||||
self.puell_multiple
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
&mining.rewards.subsidy.block.usd,
|
||||
&mining.rewards.subsidy.average._1y.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Gini coefficient (UTXO distribution inequality)
|
||||
gini::compute(&mut self.gini, distribution, starting_indexes, exit)?;
|
||||
gini::compute(&mut self.gini, distribution, indexer, exit)?;
|
||||
|
||||
// RHODL Ratio: 1d-1w realized cap / 1y-2y realized cap
|
||||
self.rhodl_ratio
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
&distribution
|
||||
.utxo_cohorts
|
||||
.age_range
|
||||
@@ -69,7 +72,7 @@ impl Vecs {
|
||||
self.nvt
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
market_cap,
|
||||
&transactions.volume.transfer_volume.sum._24h.usd.height,
|
||||
exit,
|
||||
@@ -79,7 +82,7 @@ impl Vecs {
|
||||
self.thermo_cap_multiple
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
market_cap,
|
||||
&mining.rewards.subsidy.cumulative.usd.height,
|
||||
exit,
|
||||
@@ -93,7 +96,7 @@ impl Vecs {
|
||||
self.coindays_destroyed_supply_adj
|
||||
.height
|
||||
.compute_transform2(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
&all_activity.coindays_destroyed.sum._24h.height,
|
||||
supply_total_sats,
|
||||
|(i, cdd_24h, supply_sats, ..)| {
|
||||
@@ -111,7 +114,7 @@ impl Vecs {
|
||||
self.coinyears_destroyed_supply_adj
|
||||
.height
|
||||
.compute_transform2(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
&all_activity.coinyears_destroyed.height,
|
||||
supply_total_sats,
|
||||
|(i, cyd, supply_sats, ..)| {
|
||||
@@ -127,7 +130,7 @@ impl Vecs {
|
||||
|
||||
// Supply-Adjusted Dormancy = dormancy / circulating_supply_btc
|
||||
self.dormancy.supply_adj.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
&all_activity.dormancy._24h.height,
|
||||
supply_total_sats,
|
||||
|(i, dormancy, supply_sats, ..)| {
|
||||
@@ -144,7 +147,7 @@ impl Vecs {
|
||||
// Stock-to-Flow: supply / annual_issuance
|
||||
// annual_issuance ≈ subsidy_per_block × 52560 (blocks/year)
|
||||
self.stock_to_flow.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
supply_total_sats,
|
||||
&mining.rewards.subsidy.block.sats,
|
||||
|(i, supply_sats, subsidy_sats, ..)| {
|
||||
@@ -163,7 +166,7 @@ impl Vecs {
|
||||
|
||||
// Dormancy Flow: supply_btc / dormancy
|
||||
self.dormancy.flow.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
supply_total_sats,
|
||||
&all_activity.dormancy._24h.height,
|
||||
|(i, supply_sats, dormancy, ..)| {
|
||||
@@ -180,7 +183,7 @@ impl Vecs {
|
||||
|
||||
// Seller Exhaustion Constant: % supply_in_profit × 30d_volatility
|
||||
self.seller_exhaustion.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
starting_lengths.height,
|
||||
&all_metrics.supply.in_profit.sats.height,
|
||||
&market.volatility._1m.height,
|
||||
supply_total_sats,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{BasisPoints16, Indexes, Sats, StoredU64, Version};
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{BasisPoints16, Sats, StoredU64, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec};
|
||||
|
||||
use crate::{distribution, internal::PercentPerBlock};
|
||||
@@ -7,9 +8,10 @@ use crate::{distribution, internal::PercentPerBlock};
|
||||
pub(super) fn compute(
|
||||
gini: &mut PercentPerBlock<BasisPoints16>,
|
||||
distribution: &distribution::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
indexer: &Indexer,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let starting_height = indexer.safe_lengths().height;
|
||||
let amount_range = &distribution.utxo_cohorts.amount_range;
|
||||
|
||||
let supply_vecs: Vec<&_> = amount_range
|
||||
@@ -36,11 +38,7 @@ pub(super) fn compute(
|
||||
.height
|
||||
.validate_computed_version_or_reset(source_version)?;
|
||||
|
||||
let min_len = gini
|
||||
.bps
|
||||
.height
|
||||
.len()
|
||||
.min(starting_indexes.height.to_usize());
|
||||
let min_len = gini.bps.height.len().min(starting_height.to_usize());
|
||||
|
||||
gini.bps.height.truncate_if_needed_at(min_len)?;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, Height, Indexes, StoredI8, Version};
|
||||
use brk_types::{Cents, Height, StoredI8, Version};
|
||||
use vecdb::{AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -47,60 +48,61 @@ impl RarityMeterInner {
|
||||
&mut self,
|
||||
models: &[&RatioPerBlockPercentiles],
|
||||
spot: &impl ReadableVec<Height, Cents>,
|
||||
starting_indexes: &Indexes,
|
||||
indexer: &Indexer,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let starting_height = indexer.safe_lengths().height;
|
||||
let gather = |f: fn(&RatioPerBlockPercentiles) -> &_| -> Vec<_> {
|
||||
models.iter().map(|m| f(m)).collect()
|
||||
};
|
||||
|
||||
// Lower percentiles: max across all models (tightest lower bound)
|
||||
self.pct0_5.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct0_5.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct1.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct1.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct2.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct2.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct5.cents.height.compute_max_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct5.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Upper percentiles: min across all models (tightest upper bound)
|
||||
self.pct95.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct95.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct98.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct98.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct99.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct99.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
self.pct99_5.cents.height.compute_min_of_others(
|
||||
starting_indexes.height,
|
||||
starting_height,
|
||||
&gather(|m| &m.pct99_5.price.cents.height),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.compute_index(spot, starting_indexes, exit)?;
|
||||
self.compute_index(spot, indexer, exit)?;
|
||||
|
||||
self.compute_score(models, spot, starting_indexes, exit)?;
|
||||
self.compute_score(models, spot, indexer, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -108,9 +110,10 @@ impl RarityMeterInner {
|
||||
fn compute_index(
|
||||
&mut self,
|
||||
spot: &impl ReadableVec<Height, Cents>,
|
||||
starting_indexes: &Indexes,
|
||||
indexer: &Indexer,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let starting_height = indexer.safe_lengths().height;
|
||||
let bands = [
|
||||
&self.pct0_5.cents.height,
|
||||
&self.pct1.cents.height,
|
||||
@@ -128,9 +131,7 @@ impl RarityMeterInner {
|
||||
self.index
|
||||
.height
|
||||
.validate_computed_version_or_reset(dep_version)?;
|
||||
self.index
|
||||
.height
|
||||
.truncate_if_needed(starting_indexes.height)?;
|
||||
self.index.height.truncate_if_needed(starting_height)?;
|
||||
|
||||
self.index.height.repeat_until_complete(exit, |vec| {
|
||||
let skip = vec.len();
|
||||
@@ -186,9 +187,10 @@ impl RarityMeterInner {
|
||||
&mut self,
|
||||
models: &[&RatioPerBlockPercentiles],
|
||||
spot: &impl ReadableVec<Height, Cents>,
|
||||
starting_indexes: &Indexes,
|
||||
indexer: &Indexer,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let starting_height = indexer.safe_lengths().height;
|
||||
let dep_version: Version = models
|
||||
.iter()
|
||||
.map(|p| {
|
||||
@@ -207,9 +209,7 @@ impl RarityMeterInner {
|
||||
self.score
|
||||
.height
|
||||
.validate_computed_version_or_reset(dep_version)?;
|
||||
self.score
|
||||
.height
|
||||
.truncate_if_needed(starting_indexes.height)?;
|
||||
self.score.height.truncate_if_needed(starting_height)?;
|
||||
|
||||
self.score.height.repeat_until_complete(exit, |vec| {
|
||||
let skip = vec.len();
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
mod inner;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Indexes, Version};
|
||||
use brk_types::Version;
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{distribution, indexes, prices};
|
||||
@@ -34,9 +35,9 @@ impl RarityMeter {
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
distribution: &distribution::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let realized = &distribution.utxo_cohorts.all.metrics.realized;
|
||||
@@ -55,7 +56,7 @@ impl RarityMeter {
|
||||
<h_realized.capitalized.price.percentiles,
|
||||
],
|
||||
spot,
|
||||
starting_indexes,
|
||||
indexer,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -66,7 +67,7 @@ impl RarityMeter {
|
||||
&sth_realized.capitalized.price.percentiles,
|
||||
],
|
||||
spot,
|
||||
starting_indexes,
|
||||
indexer,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -79,7 +80,7 @@ impl RarityMeter {
|
||||
<h_realized.capitalized.price.percentiles,
|
||||
],
|
||||
spot,
|
||||
starting_indexes,
|
||||
indexer,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user