diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index 2c858a70c..147ac2085 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -5645,6 +5645,7 @@ pub struct MetricsTree_Distribution_UtxoCohorts { pub lt_amount: MetricsTree_Distribution_UtxoCohorts_LtAmount, pub type_: MetricsTree_Distribution_UtxoCohorts_Type, pub profitability: MetricsTree_Distribution_UtxoCohorts_Profitability, + pub matured: MetricsTree_Distribution_UtxoCohorts_Matured, } impl MetricsTree_Distribution_UtxoCohorts { @@ -5663,6 +5664,7 @@ impl MetricsTree_Distribution_UtxoCohorts { lt_amount: MetricsTree_Distribution_UtxoCohorts_LtAmount::new(client.clone(), format!("{base_path}_lt_amount")), type_: MetricsTree_Distribution_UtxoCohorts_Type::new(client.clone(), format!("{base_path}_type_")), profitability: MetricsTree_Distribution_UtxoCohorts_Profitability::new(client.clone(), format!("{base_path}_profitability")), + matured: MetricsTree_Distribution_UtxoCohorts_Matured::new(client.clone(), format!("{base_path}_matured")), } } } @@ -6341,6 +6343,59 @@ impl MetricsTree_Distribution_UtxoCohorts_Profitability_Loss { } } +/// Metrics tree node. +pub struct MetricsTree_Distribution_UtxoCohorts_Matured { + pub up_to_1h: BtcCentsSatsUsdPattern, + pub _1h_to_1d: BtcCentsSatsUsdPattern, + pub _1d_to_1w: BtcCentsSatsUsdPattern, + pub _1w_to_1m: BtcCentsSatsUsdPattern, + pub _1m_to_2m: BtcCentsSatsUsdPattern, + pub _2m_to_3m: BtcCentsSatsUsdPattern, + pub _3m_to_4m: BtcCentsSatsUsdPattern, + pub _4m_to_5m: BtcCentsSatsUsdPattern, + pub _5m_to_6m: BtcCentsSatsUsdPattern, + pub _6m_to_1y: BtcCentsSatsUsdPattern, + pub _1y_to_2y: BtcCentsSatsUsdPattern, + pub _2y_to_3y: BtcCentsSatsUsdPattern, + pub _3y_to_4y: BtcCentsSatsUsdPattern, + pub _4y_to_5y: BtcCentsSatsUsdPattern, + pub _5y_to_6y: BtcCentsSatsUsdPattern, + pub _6y_to_7y: BtcCentsSatsUsdPattern, + pub _7y_to_8y: BtcCentsSatsUsdPattern, + pub _8y_to_10y: BtcCentsSatsUsdPattern, + pub _10y_to_12y: BtcCentsSatsUsdPattern, + pub _12y_to_15y: BtcCentsSatsUsdPattern, + pub from_15y: BtcCentsSatsUsdPattern, +} + +impl MetricsTree_Distribution_UtxoCohorts_Matured { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + up_to_1h: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_under_1h_old_matured".to_string()), + _1h_to_1d: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_1h_to_1d_old_matured".to_string()), + _1d_to_1w: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_1d_to_1w_old_matured".to_string()), + _1w_to_1m: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_1w_to_1m_old_matured".to_string()), + _1m_to_2m: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_1m_to_2m_old_matured".to_string()), + _2m_to_3m: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_2m_to_3m_old_matured".to_string()), + _3m_to_4m: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_3m_to_4m_old_matured".to_string()), + _4m_to_5m: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_4m_to_5m_old_matured".to_string()), + _5m_to_6m: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_5m_to_6m_old_matured".to_string()), + _6m_to_1y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_6m_to_1y_old_matured".to_string()), + _1y_to_2y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_1y_to_2y_old_matured".to_string()), + _2y_to_3y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_2y_to_3y_old_matured".to_string()), + _3y_to_4y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_3y_to_4y_old_matured".to_string()), + _4y_to_5y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_4y_to_5y_old_matured".to_string()), + _5y_to_6y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_5y_to_6y_old_matured".to_string()), + _6y_to_7y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_6y_to_7y_old_matured".to_string()), + _7y_to_8y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_7y_to_8y_old_matured".to_string()), + _8y_to_10y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_8y_to_10y_old_matured".to_string()), + _10y_to_12y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_10y_to_12y_old_matured".to_string()), + _12y_to_15y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_12y_to_15y_old_matured".to_string()), + from_15y: BtcCentsSatsUsdPattern::new(client.clone(), "utxo_over_15y_old_matured".to_string()), + } + } +} + /// Metrics tree node. pub struct MetricsTree_Distribution_AddressCohorts { pub ge_amount: MetricsTree_Distribution_AddressCohorts_GeAmount, diff --git a/crates/brk_cohort/src/by_age_range.rs b/crates/brk_cohort/src/by_age_range.rs index 1b25e9475..c467b4503 100644 --- a/crates/brk_cohort/src/by_age_range.rs +++ b/crates/brk_cohort/src/by_age_range.rs @@ -200,6 +200,33 @@ impl ByAgeRange { } } + pub fn from_array(arr: [T; 21]) -> Self { + let [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20] = arr; + Self { + up_to_1h: a0, + _1h_to_1d: a1, + _1d_to_1w: a2, + _1w_to_1m: a3, + _1m_to_2m: a4, + _2m_to_3m: a5, + _3m_to_4m: a6, + _4m_to_5m: a7, + _5m_to_6m: a8, + _6m_to_1y: a9, + _1y_to_2y: a10, + _2y_to_3y: a11, + _3y_to_4y: a12, + _4y_to_5y: a13, + _5y_to_6y: a14, + _6y_to_7y: a15, + _7y_to_8y: a16, + _8y_to_10y: a17, + _10y_to_12y: a18, + _12y_to_15y: a19, + from_15y: a20, + } + } + pub fn new(mut create: F) -> Self where F: FnMut(Filter, &'static str) -> T, diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs index a735d3dda..507fbccdc 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs @@ -6,22 +6,28 @@ use brk_cohort::{ }; use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Dollars, Height, Indexes, Version}; +use brk_types::{Dollars, Height, Indexes, Sats, Version}; use rayon::prelude::*; -use vecdb::{AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode}; +use vecdb::{AnyStoredVec, Database, Exit, ReadOnlyClone, ReadableVec, Rw, StorageMode, WritableVec}; -use crate::{blocks, distribution::DynCohortVecs, indexes, prices}; - -use crate::distribution::metrics::{ - AllCohortMetrics, BasicCohortMetrics, CohortMetricsBase, CoreCohortMetrics, - ExtendedAdjustedCohortMetrics, ExtendedCohortMetrics, ImportConfig, MinimalCohortMetrics, - ProfitabilityMetrics, SupplyMetrics, +use crate::{ + blocks, + distribution::{ + DynCohortVecs, + metrics::{ + AllCohortMetrics, BasicCohortMetrics, CohortMetricsBase, CoreCohortMetrics, + ExtendedAdjustedCohortMetrics, ExtendedCohortMetrics, ImportConfig, + MinimalCohortMetrics, ProfitabilityMetrics, SupplyMetrics, + }, + state::UTXOCohortState, + }, + indexes, + internal::ValueFromHeight, + prices, }; use super::{percentiles::PercentileCache, vecs::UTXOCohortVecs}; -use crate::distribution::state::UTXOCohortState; - const VERSION: Version = Version::new(0); /// All UTXO cohorts organized by filter type. @@ -40,6 +46,7 @@ pub struct UTXOCohorts { pub lt_amount: ByLowerThanAmount>>, pub type_: BySpendableType>>, pub profitability: ProfitabilityMetrics, + pub matured: ByAgeRange>, #[traversable(skip)] pub(super) percentile_cache: PercentileCache, /// Cached partition_point positions for tick_tock boundary searches. @@ -218,6 +225,10 @@ impl UTXOCohorts { let lt_amount = ByLowerThanAmount::try_new(&minimal_no_state)?; let ge_amount = ByGreatEqualAmount::try_new(&minimal_no_state)?; + let matured = ByAgeRange::try_new(&|_f: Filter, name: &'static str| -> Result { + ValueFromHeight::forced_import(db, &format!("utxo_{name}_matured"), v, indexes) + })?; + Ok(Self { all, sth, @@ -232,11 +243,24 @@ impl UTXOCohorts { lt_amount, ge_amount, profitability, + matured, percentile_cache: PercentileCache::default(), tick_tock_cached_positions: [0; 20], }) } + /// Push maturation sats to the matured vecs for the given height. + pub(crate) fn push_maturation( + &mut self, + height: Height, + matured: &ByAgeRange, + ) -> Result<()> { + for (v, &sats) in self.matured.iter_mut().zip(matured.iter()) { + v.sats.height.truncate_push(height, sats)?; + } + Ok(()) + } + pub(crate) fn par_iter_separate_mut( &mut self, ) -> impl ParallelIterator { @@ -383,6 +407,11 @@ impl UTXOCohorts { .try_for_each(|v| v.compute_rest_part1(blocks, prices, starting_indexes, exit))?; } + // Compute matured cents from sats × price + self.matured + .par_iter_mut() + .try_for_each(|v| v.compute(prices, starting_indexes.height, exit))?; + Ok(()) } @@ -596,6 +625,11 @@ impl UTXOCohorts { vecs.extend(v.metrics.collect_all_vecs_mut()); } vecs.extend(self.profitability.collect_all_vecs_mut()); + for v in self.matured.iter_mut() { + let base = &mut v.base; + vecs.push(&mut base.sats.height); + vecs.push(&mut base.cents.height); + } vecs.into_par_iter() } @@ -609,6 +643,7 @@ impl UTXOCohorts { pub(crate) fn min_separate_stateful_height_len(&self) -> Height { self.iter_separate() .map(|v| Height::from(v.min_stateful_height_len())) + .chain(self.matured.iter().map(|v| Height::from(v.min_stateful_len()))) .min() .unwrap_or_default() .min(Height::from(self.profitability.min_stateful_height_len())) diff --git a/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs b/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs index 2f6e76ed3..6c805773e 100644 --- a/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs +++ b/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs @@ -1,5 +1,5 @@ -use brk_cohort::AGE_BOUNDARIES; -use brk_types::{CostBasisSnapshot, ONE_HOUR_IN_SEC, Timestamp}; +use brk_cohort::{AGE_BOUNDARIES, ByAgeRange}; +use brk_types::{CostBasisSnapshot, ONE_HOUR_IN_SEC, Sats, Timestamp}; use vecdb::{Rw, unlikely}; use crate::distribution::state::BlockState; @@ -15,13 +15,16 @@ impl UTXOCohorts { /// Uses cached positions per boundary to avoid binary search. /// Since timestamps are monotonic, positions only advance forward. /// Complexity: O(k * c) where k = 20 boundaries, c = ~1 (forward scan steps). + /// + /// Returns how many sats matured INTO each cohort from the younger adjacent one. + /// `up_to_1h` is always zero since nothing ages into the youngest cohort. pub(crate) fn tick_tock_next_block( &mut self, chain_state: &[BlockState], timestamp: Timestamp, - ) { + ) -> ByAgeRange { if chain_state.is_empty() { - return; + return ByAgeRange::default(); } let prev_timestamp = chain_state.last().unwrap().timestamp; @@ -29,9 +32,11 @@ impl UTXOCohorts { // Skip if no time has passed if elapsed == 0 { - return; + return ByAgeRange::default(); } + let mut matured = [Sats::ZERO; 21]; + // Get age_range cohort states (indexed 0..21) // Cohort i covers hours [BOUNDARIES[i-1], BOUNDARIES[i]) // Cohort 0 covers [0, 1) hours @@ -87,7 +92,10 @@ impl UTXOCohorts { if let Some(state) = age_cohorts[boundary_idx + 1].as_mut() { state.increment_snapshot(&snapshot); } + matured[boundary_idx + 1] += block_state.supply.value; } } + + ByAgeRange::from_array(matured) } } diff --git a/crates/brk_computer/src/distribution/compute/block_loop.rs b/crates/brk_computer/src/distribution/compute/block_loop.rs index b7460c03c..91083a9f3 100644 --- a/crates/brk_computer/src/distribution/compute/block_loop.rs +++ b/crates/brk_computer/src/distribution/compute/block_loop.rs @@ -268,11 +268,8 @@ pub(crate) fn process_blocks( }; // Process outputs, inputs, and tick-tock in parallel via rayon::join - let (_, oi_result) = rayon::join( - || { - vecs.utxo_cohorts - .tick_tock_next_block(chain_state, timestamp); - }, + let (matured, oi_result) = rayon::join( + || vecs.utxo_cohorts.tick_tock_next_block(chain_state, timestamp), || -> Result<_> { let (outputs_result, inputs_result) = rayon::join( || { @@ -355,6 +352,9 @@ pub(crate) fn process_blocks( timestamp, }); + // Record maturation (sats crossing age boundaries) + vecs.utxo_cohorts.push_maturation(height, &matured)?; + // Build set of addresses that received this block (for detecting "both" in sent) // Reuse pre-allocated hashsets: clear preserves capacity, avoiding reallocation received_addresses.values_mut().for_each(|set| set.clear()); diff --git a/crates/brk_computer/src/internal/from_height/by_unit/mod.rs b/crates/brk_computer/src/internal/from_height/by_unit/mod.rs index d1f9a23f1..8a69f338e 100644 --- a/crates/brk_computer/src/internal/from_height/by_unit/mod.rs +++ b/crates/brk_computer/src/internal/from_height/by_unit/mod.rs @@ -4,7 +4,7 @@ mod rolling_sum; use brk_error::Result; use brk_traversable::Traversable; use brk_types::{Bitcoin, Cents, Dollars, Sats, Version}; -use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode}; +use vecdb::{AnyVec, Database, ReadableCloneableVec, Rw, StorageMode}; use crate::{ indexes, @@ -57,6 +57,10 @@ impl ByUnit { usd, }) } + + pub(crate) fn min_stateful_len(&self) -> usize { + self.sats.height.len() + } } impl Windows { diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 8a45bb913..778d8f014 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -4941,6 +4941,7 @@ function create_24hPattern(client, acc) { * @property {MetricsTree_Distribution_UtxoCohorts_LtAmount} ltAmount * @property {MetricsTree_Distribution_UtxoCohorts_Type} type * @property {MetricsTree_Distribution_UtxoCohorts_Profitability} profitability + * @property {MetricsTree_Distribution_UtxoCohorts_Matured} matured */ /** @@ -5253,6 +5254,31 @@ function create_24hPattern(client, acc) { * @property {RealizedSupplyPattern} _90pct */ +/** + * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_Matured + * @property {BtcCentsSatsUsdPattern} upTo1h + * @property {BtcCentsSatsUsdPattern} _1hTo1d + * @property {BtcCentsSatsUsdPattern} _1dTo1w + * @property {BtcCentsSatsUsdPattern} _1wTo1m + * @property {BtcCentsSatsUsdPattern} _1mTo2m + * @property {BtcCentsSatsUsdPattern} _2mTo3m + * @property {BtcCentsSatsUsdPattern} _3mTo4m + * @property {BtcCentsSatsUsdPattern} _4mTo5m + * @property {BtcCentsSatsUsdPattern} _5mTo6m + * @property {BtcCentsSatsUsdPattern} _6mTo1y + * @property {BtcCentsSatsUsdPattern} _1yTo2y + * @property {BtcCentsSatsUsdPattern} _2yTo3y + * @property {BtcCentsSatsUsdPattern} _3yTo4y + * @property {BtcCentsSatsUsdPattern} _4yTo5y + * @property {BtcCentsSatsUsdPattern} _5yTo6y + * @property {BtcCentsSatsUsdPattern} _6yTo7y + * @property {BtcCentsSatsUsdPattern} _7yTo8y + * @property {BtcCentsSatsUsdPattern} _8yTo10y + * @property {BtcCentsSatsUsdPattern} _10yTo12y + * @property {BtcCentsSatsUsdPattern} _12yTo15y + * @property {BtcCentsSatsUsdPattern} from15y + */ + /** * @typedef {Object} MetricsTree_Distribution_AddressCohorts * @property {MetricsTree_Distribution_AddressCohorts_GeAmount} geAmount @@ -7514,6 +7540,29 @@ class BrkClient extends BrkClientBase { _90pct: createRealizedSupplyPattern(this, 'loss_ge_90pct'), }, }, + matured: { + upTo1h: createBtcCentsSatsUsdPattern(this, 'utxo_under_1h_old_matured'), + _1hTo1d: createBtcCentsSatsUsdPattern(this, 'utxo_1h_to_1d_old_matured'), + _1dTo1w: createBtcCentsSatsUsdPattern(this, 'utxo_1d_to_1w_old_matured'), + _1wTo1m: createBtcCentsSatsUsdPattern(this, 'utxo_1w_to_1m_old_matured'), + _1mTo2m: createBtcCentsSatsUsdPattern(this, 'utxo_1m_to_2m_old_matured'), + _2mTo3m: createBtcCentsSatsUsdPattern(this, 'utxo_2m_to_3m_old_matured'), + _3mTo4m: createBtcCentsSatsUsdPattern(this, 'utxo_3m_to_4m_old_matured'), + _4mTo5m: createBtcCentsSatsUsdPattern(this, 'utxo_4m_to_5m_old_matured'), + _5mTo6m: createBtcCentsSatsUsdPattern(this, 'utxo_5m_to_6m_old_matured'), + _6mTo1y: createBtcCentsSatsUsdPattern(this, 'utxo_6m_to_1y_old_matured'), + _1yTo2y: createBtcCentsSatsUsdPattern(this, 'utxo_1y_to_2y_old_matured'), + _2yTo3y: createBtcCentsSatsUsdPattern(this, 'utxo_2y_to_3y_old_matured'), + _3yTo4y: createBtcCentsSatsUsdPattern(this, 'utxo_3y_to_4y_old_matured'), + _4yTo5y: createBtcCentsSatsUsdPattern(this, 'utxo_4y_to_5y_old_matured'), + _5yTo6y: createBtcCentsSatsUsdPattern(this, 'utxo_5y_to_6y_old_matured'), + _6yTo7y: createBtcCentsSatsUsdPattern(this, 'utxo_6y_to_7y_old_matured'), + _7yTo8y: createBtcCentsSatsUsdPattern(this, 'utxo_7y_to_8y_old_matured'), + _8yTo10y: createBtcCentsSatsUsdPattern(this, 'utxo_8y_to_10y_old_matured'), + _10yTo12y: createBtcCentsSatsUsdPattern(this, 'utxo_10y_to_12y_old_matured'), + _12yTo15y: createBtcCentsSatsUsdPattern(this, 'utxo_12y_to_15y_old_matured'), + from15y: createBtcCentsSatsUsdPattern(this, 'utxo_over_15y_old_matured'), + }, }, addressCohorts: { geAmount: { diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 4a963c803..88ed8a084 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -4648,6 +4648,32 @@ class MetricsTree_Distribution_UtxoCohorts_Profitability: self.profit: MetricsTree_Distribution_UtxoCohorts_Profitability_Profit = MetricsTree_Distribution_UtxoCohorts_Profitability_Profit(client) self.loss: MetricsTree_Distribution_UtxoCohorts_Profitability_Loss = MetricsTree_Distribution_UtxoCohorts_Profitability_Loss(client) +class MetricsTree_Distribution_UtxoCohorts_Matured: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self.up_to_1h: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_under_1h_old_matured') + self._1h_to_1d: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_1h_to_1d_old_matured') + self._1d_to_1w: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_1d_to_1w_old_matured') + self._1w_to_1m: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_1w_to_1m_old_matured') + self._1m_to_2m: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_1m_to_2m_old_matured') + self._2m_to_3m: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_2m_to_3m_old_matured') + self._3m_to_4m: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_3m_to_4m_old_matured') + self._4m_to_5m: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_4m_to_5m_old_matured') + self._5m_to_6m: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_5m_to_6m_old_matured') + self._6m_to_1y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_6m_to_1y_old_matured') + self._1y_to_2y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_1y_to_2y_old_matured') + self._2y_to_3y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_2y_to_3y_old_matured') + self._3y_to_4y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_3y_to_4y_old_matured') + self._4y_to_5y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_4y_to_5y_old_matured') + self._5y_to_6y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_5y_to_6y_old_matured') + self._6y_to_7y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_6y_to_7y_old_matured') + self._7y_to_8y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_7y_to_8y_old_matured') + self._8y_to_10y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_8y_to_10y_old_matured') + self._10y_to_12y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_10y_to_12y_old_matured') + self._12y_to_15y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_12y_to_15y_old_matured') + self.from_15y: BtcCentsSatsUsdPattern = BtcCentsSatsUsdPattern(client, 'utxo_over_15y_old_matured') + class MetricsTree_Distribution_UtxoCohorts: """Metrics tree node.""" @@ -4665,6 +4691,7 @@ class MetricsTree_Distribution_UtxoCohorts: self.lt_amount: MetricsTree_Distribution_UtxoCohorts_LtAmount = MetricsTree_Distribution_UtxoCohorts_LtAmount(client) self.type_: MetricsTree_Distribution_UtxoCohorts_Type = MetricsTree_Distribution_UtxoCohorts_Type(client) self.profitability: MetricsTree_Distribution_UtxoCohorts_Profitability = MetricsTree_Distribution_UtxoCohorts_Profitability(client) + self.matured: MetricsTree_Distribution_UtxoCohorts_Matured = MetricsTree_Distribution_UtxoCohorts_Matured(client) class MetricsTree_Distribution_AddressCohorts_GeAmount: """Metrics tree node."""