global: snapshot

This commit is contained in:
nym21
2026-03-11 16:11:20 +01:00
parent 984122f394
commit 71dd7e9852
36 changed files with 752 additions and 681 deletions

View File

@@ -6,8 +6,8 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use brk_cohort::{ use brk_cohort::{
AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, EPOCH_NAMES, GE_AMOUNT_NAMES, LT_AMOUNT_NAMES, AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, EPOCH_NAMES, OVER_AMOUNT_NAMES, UNDER_AMOUNT_NAMES,
MAX_AGE_NAMES, MIN_AGE_NAMES, SPENDABLE_TYPE_NAMES, TERM_NAMES, CLASS_NAMES, UNDER_AGE_NAMES, OVER_AGE_NAMES, SPENDABLE_TYPE_NAMES, TERM_NAMES, CLASS_NAMES,
}; };
use brk_types::{Index, PoolSlug, pools}; use brk_types::{Index, PoolSlug, pools};
use serde::Serialize; use serde::Serialize;
@@ -58,11 +58,11 @@ impl CohortConstants {
("CLASS_NAMES", to_value(&CLASS_NAMES)), ("CLASS_NAMES", to_value(&CLASS_NAMES)),
("SPENDABLE_TYPE_NAMES", to_value(&SPENDABLE_TYPE_NAMES)), ("SPENDABLE_TYPE_NAMES", to_value(&SPENDABLE_TYPE_NAMES)),
("AGE_RANGE_NAMES", to_value(&AGE_RANGE_NAMES)), ("AGE_RANGE_NAMES", to_value(&AGE_RANGE_NAMES)),
("MAX_AGE_NAMES", to_value(&MAX_AGE_NAMES)), ("UNDER_AGE_NAMES", to_value(&UNDER_AGE_NAMES)),
("MIN_AGE_NAMES", to_value(&MIN_AGE_NAMES)), ("OVER_AGE_NAMES", to_value(&OVER_AGE_NAMES)),
("AMOUNT_RANGE_NAMES", to_value(&AMOUNT_RANGE_NAMES)), ("AMOUNT_RANGE_NAMES", to_value(&AMOUNT_RANGE_NAMES)),
("GE_AMOUNT_NAMES", to_value(&GE_AMOUNT_NAMES)), ("OVER_AMOUNT_NAMES", to_value(&OVER_AMOUNT_NAMES)),
("LT_AMOUNT_NAMES", to_value(&LT_AMOUNT_NAMES)), ("UNDER_AMOUNT_NAMES", to_value(&UNDER_AMOUNT_NAMES)),
] ]
} }
} }

View File

@@ -40,7 +40,7 @@ fn main() -> brk_client::Result<()> {
.metrics() .metrics()
.blocks .blocks
.count .count
.block_count .total
.sum .sum
._24h ._24h
.by .by

View File

@@ -2422,7 +2422,7 @@ pub struct OutputsRealizedSupplyUnrealizedPattern {
pub outputs: UnspentPattern, pub outputs: UnspentPattern,
pub realized: CapLossMvrvNuplPriceProfitSoprPattern, pub realized: CapLossMvrvNuplPriceProfitSoprPattern,
pub supply: HalvedInTotalPattern, pub supply: HalvedInTotalPattern,
pub unrealized: LossProfitPattern2, pub unrealized: LossProfitPattern,
} }
impl OutputsRealizedSupplyUnrealizedPattern { impl OutputsRealizedSupplyUnrealizedPattern {
@@ -2432,7 +2432,7 @@ impl OutputsRealizedSupplyUnrealizedPattern {
outputs: UnspentPattern::new(client.clone(), _m(&acc, "utxo_count")), outputs: UnspentPattern::new(client.clone(), _m(&acc, "utxo_count")),
realized: CapLossMvrvNuplPriceProfitSoprPattern::new(client.clone(), acc.clone()), realized: CapLossMvrvNuplPriceProfitSoprPattern::new(client.clone(), acc.clone()),
supply: HalvedInTotalPattern::new(client.clone(), _m(&acc, "supply")), supply: HalvedInTotalPattern::new(client.clone(), _m(&acc, "supply")),
unrealized: LossProfitPattern2::new(client.clone(), _m(&acc, "unrealized")), unrealized: LossProfitPattern::new(client.clone(), _m(&acc, "unrealized")),
} }
} }
} }
@@ -3024,12 +3024,12 @@ impl InPattern {
} }
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct LossProfitPattern2 { pub struct LossProfitPattern {
pub loss: RawSumPattern2, pub loss: RawSumPattern2,
pub profit: RawSumPattern2, pub profit: RawSumPattern2,
} }
impl LossProfitPattern2 { impl LossProfitPattern {
/// Create a new pattern node with accumulated metric name. /// Create a new pattern node with accumulated metric name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
@@ -5742,7 +5742,7 @@ impl MetricsTree_Market_Dca_Period_CostBasis {
pub struct MetricsTree_Market_Dca_Class { pub struct MetricsTree_Market_Dca_Class {
pub stack: MetricsTree_Market_Dca_Class_Stack, pub stack: MetricsTree_Market_Dca_Class_Stack,
pub cost_basis: MetricsTree_Market_Dca_Class_CostBasis, pub cost_basis: MetricsTree_Market_Dca_Class_CostBasis,
pub r#return: MetricsTree_Market_Dca_Class_R#return, pub r#return: MetricsTree_Market_Dca_Class_Return,
} }
impl MetricsTree_Market_Dca_Class { impl MetricsTree_Market_Dca_Class {
@@ -5750,7 +5750,7 @@ impl MetricsTree_Market_Dca_Class {
Self { Self {
stack: MetricsTree_Market_Dca_Class_Stack::new(client.clone(), format!("{base_path}_stack")), stack: MetricsTree_Market_Dca_Class_Stack::new(client.clone(), format!("{base_path}_stack")),
cost_basis: MetricsTree_Market_Dca_Class_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")), cost_basis: MetricsTree_Market_Dca_Class_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")),
r#return: MetricsTree_Market_Dca_Class_R#return::new(client.clone(), format!("{base_path}_r#return")), r#return: MetricsTree_Market_Dca_Class_Return::new(client.clone(), format!("{base_path}_return")),
} }
} }
} }
@@ -5826,7 +5826,7 @@ impl MetricsTree_Market_Dca_Class_CostBasis {
} }
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Market_Dca_Class_R#return { pub struct MetricsTree_Market_Dca_Class_Return {
pub from_2015: BpsPercentRatioPattern, pub from_2015: BpsPercentRatioPattern,
pub from_2016: BpsPercentRatioPattern, pub from_2016: BpsPercentRatioPattern,
pub from_2017: BpsPercentRatioPattern, pub from_2017: BpsPercentRatioPattern,
@@ -5841,7 +5841,7 @@ pub struct MetricsTree_Market_Dca_Class_R#return {
pub from_2026: BpsPercentRatioPattern, pub from_2026: BpsPercentRatioPattern,
} }
impl MetricsTree_Market_Dca_Class_R#return { impl MetricsTree_Market_Dca_Class_Return {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
from_2015: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2015".to_string()), from_2015: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2015".to_string()),
@@ -6725,13 +6725,13 @@ pub struct MetricsTree_Distribution_Cohorts_Utxo {
pub sth: MetricsTree_Distribution_Cohorts_Utxo_Sth, pub sth: MetricsTree_Distribution_Cohorts_Utxo_Sth,
pub lth: MetricsTree_Distribution_Cohorts_Utxo_Lth, pub lth: MetricsTree_Distribution_Cohorts_Utxo_Lth,
pub age_range: MetricsTree_Distribution_Cohorts_Utxo_AgeRange, pub age_range: MetricsTree_Distribution_Cohorts_Utxo_AgeRange,
pub max_age: MetricsTree_Distribution_Cohorts_Utxo_MaxAge, pub under_age: MetricsTree_Distribution_Cohorts_Utxo_UnderAge,
pub min_age: MetricsTree_Distribution_Cohorts_Utxo_MinAge, pub over_age: MetricsTree_Distribution_Cohorts_Utxo_OverAge,
pub epoch: MetricsTree_Distribution_Cohorts_Utxo_Epoch, pub epoch: MetricsTree_Distribution_Cohorts_Utxo_Epoch,
pub class: MetricsTree_Distribution_Cohorts_Utxo_Class, pub class: MetricsTree_Distribution_Cohorts_Utxo_Class,
pub ge_amount: MetricsTree_Distribution_Cohorts_Utxo_GeAmount, pub over_amount: MetricsTree_Distribution_Cohorts_Utxo_OverAmount,
pub amount_range: MetricsTree_Distribution_Cohorts_Utxo_AmountRange, pub amount_range: MetricsTree_Distribution_Cohorts_Utxo_AmountRange,
pub lt_amount: MetricsTree_Distribution_Cohorts_Utxo_LtAmount, pub under_amount: MetricsTree_Distribution_Cohorts_Utxo_UnderAmount,
pub r#type: MetricsTree_Distribution_Cohorts_Utxo_Type, pub r#type: MetricsTree_Distribution_Cohorts_Utxo_Type,
pub profitability: MetricsTree_Distribution_Cohorts_Utxo_Profitability, pub profitability: MetricsTree_Distribution_Cohorts_Utxo_Profitability,
pub matured: MetricsTree_Distribution_Cohorts_Utxo_Matured, pub matured: MetricsTree_Distribution_Cohorts_Utxo_Matured,
@@ -6744,13 +6744,13 @@ impl MetricsTree_Distribution_Cohorts_Utxo {
sth: MetricsTree_Distribution_Cohorts_Utxo_Sth::new(client.clone(), format!("{base_path}_sth")), sth: MetricsTree_Distribution_Cohorts_Utxo_Sth::new(client.clone(), format!("{base_path}_sth")),
lth: MetricsTree_Distribution_Cohorts_Utxo_Lth::new(client.clone(), format!("{base_path}_lth")), lth: MetricsTree_Distribution_Cohorts_Utxo_Lth::new(client.clone(), format!("{base_path}_lth")),
age_range: MetricsTree_Distribution_Cohorts_Utxo_AgeRange::new(client.clone(), format!("{base_path}_age_range")), age_range: MetricsTree_Distribution_Cohorts_Utxo_AgeRange::new(client.clone(), format!("{base_path}_age_range")),
max_age: MetricsTree_Distribution_Cohorts_Utxo_MaxAge::new(client.clone(), format!("{base_path}_max_age")), under_age: MetricsTree_Distribution_Cohorts_Utxo_UnderAge::new(client.clone(), format!("{base_path}_under_age")),
min_age: MetricsTree_Distribution_Cohorts_Utxo_MinAge::new(client.clone(), format!("{base_path}_min_age")), over_age: MetricsTree_Distribution_Cohorts_Utxo_OverAge::new(client.clone(), format!("{base_path}_over_age")),
epoch: MetricsTree_Distribution_Cohorts_Utxo_Epoch::new(client.clone(), format!("{base_path}_epoch")), epoch: MetricsTree_Distribution_Cohorts_Utxo_Epoch::new(client.clone(), format!("{base_path}_epoch")),
class: MetricsTree_Distribution_Cohorts_Utxo_Class::new(client.clone(), format!("{base_path}_class")), class: MetricsTree_Distribution_Cohorts_Utxo_Class::new(client.clone(), format!("{base_path}_class")),
ge_amount: MetricsTree_Distribution_Cohorts_Utxo_GeAmount::new(client.clone(), format!("{base_path}_ge_amount")), over_amount: MetricsTree_Distribution_Cohorts_Utxo_OverAmount::new(client.clone(), format!("{base_path}_over_amount")),
amount_range: MetricsTree_Distribution_Cohorts_Utxo_AmountRange::new(client.clone(), format!("{base_path}_amount_range")), amount_range: MetricsTree_Distribution_Cohorts_Utxo_AmountRange::new(client.clone(), format!("{base_path}_amount_range")),
lt_amount: MetricsTree_Distribution_Cohorts_Utxo_LtAmount::new(client.clone(), format!("{base_path}_lt_amount")), under_amount: MetricsTree_Distribution_Cohorts_Utxo_UnderAmount::new(client.clone(), format!("{base_path}_under_amount")),
r#type: MetricsTree_Distribution_Cohorts_Utxo_Type::new(client.clone(), format!("{base_path}_type")), r#type: MetricsTree_Distribution_Cohorts_Utxo_Type::new(client.clone(), format!("{base_path}_type")),
profitability: MetricsTree_Distribution_Cohorts_Utxo_Profitability::new(client.clone(), format!("{base_path}_profitability")), profitability: MetricsTree_Distribution_Cohorts_Utxo_Profitability::new(client.clone(), format!("{base_path}_profitability")),
matured: MetricsTree_Distribution_Cohorts_Utxo_Matured::new(client.clone(), format!("{base_path}_matured")), matured: MetricsTree_Distribution_Cohorts_Utxo_Matured::new(client.clone(), format!("{base_path}_matured")),
@@ -7066,7 +7066,7 @@ impl MetricsTree_Distribution_Cohorts_Utxo_AgeRange {
} }
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Utxo_MaxAge { pub struct MetricsTree_Distribution_Cohorts_Utxo_UnderAge {
pub _1w: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _1w: ActivityOutputsRealizedSupplyUnrealizedPattern2,
pub _1m: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _1m: ActivityOutputsRealizedSupplyUnrealizedPattern2,
pub _2m: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _2m: ActivityOutputsRealizedSupplyUnrealizedPattern2,
@@ -7087,7 +7087,7 @@ pub struct MetricsTree_Distribution_Cohorts_Utxo_MaxAge {
pub _15y: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _15y: ActivityOutputsRealizedSupplyUnrealizedPattern2,
} }
impl MetricsTree_Distribution_Cohorts_Utxo_MaxAge { impl MetricsTree_Distribution_Cohorts_Utxo_UnderAge {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
_1w: ActivityOutputsRealizedSupplyUnrealizedPattern2::new(client.clone(), "utxos_under_1w_old".to_string()), _1w: ActivityOutputsRealizedSupplyUnrealizedPattern2::new(client.clone(), "utxos_under_1w_old".to_string()),
@@ -7113,7 +7113,7 @@ impl MetricsTree_Distribution_Cohorts_Utxo_MaxAge {
} }
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Utxo_MinAge { pub struct MetricsTree_Distribution_Cohorts_Utxo_OverAge {
pub _1d: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _1d: ActivityOutputsRealizedSupplyUnrealizedPattern2,
pub _1w: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _1w: ActivityOutputsRealizedSupplyUnrealizedPattern2,
pub _1m: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _1m: ActivityOutputsRealizedSupplyUnrealizedPattern2,
@@ -7134,7 +7134,7 @@ pub struct MetricsTree_Distribution_Cohorts_Utxo_MinAge {
pub _12y: ActivityOutputsRealizedSupplyUnrealizedPattern2, pub _12y: ActivityOutputsRealizedSupplyUnrealizedPattern2,
} }
impl MetricsTree_Distribution_Cohorts_Utxo_MinAge { impl MetricsTree_Distribution_Cohorts_Utxo_OverAge {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
_1d: ActivityOutputsRealizedSupplyUnrealizedPattern2::new(client.clone(), "utxos_over_1d_old".to_string()), _1d: ActivityOutputsRealizedSupplyUnrealizedPattern2::new(client.clone(), "utxos_over_1d_old".to_string()),
@@ -7228,7 +7228,7 @@ impl MetricsTree_Distribution_Cohorts_Utxo_Class {
} }
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Utxo_GeAmount { pub struct MetricsTree_Distribution_Cohorts_Utxo_OverAmount {
pub _1sat: OutputsRealizedSupplyPattern, pub _1sat: OutputsRealizedSupplyPattern,
pub _10sats: OutputsRealizedSupplyPattern, pub _10sats: OutputsRealizedSupplyPattern,
pub _100sats: OutputsRealizedSupplyPattern, pub _100sats: OutputsRealizedSupplyPattern,
@@ -7244,7 +7244,7 @@ pub struct MetricsTree_Distribution_Cohorts_Utxo_GeAmount {
pub _10k_btc: OutputsRealizedSupplyPattern, pub _10k_btc: OutputsRealizedSupplyPattern,
} }
impl MetricsTree_Distribution_Cohorts_Utxo_GeAmount { impl MetricsTree_Distribution_Cohorts_Utxo_OverAmount {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
_1sat: OutputsRealizedSupplyPattern::new(client.clone(), "utxos_over_1sat".to_string()), _1sat: OutputsRealizedSupplyPattern::new(client.clone(), "utxos_over_1sat".to_string()),
@@ -7306,7 +7306,7 @@ impl MetricsTree_Distribution_Cohorts_Utxo_AmountRange {
} }
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Utxo_LtAmount { pub struct MetricsTree_Distribution_Cohorts_Utxo_UnderAmount {
pub _10sats: OutputsRealizedSupplyPattern, pub _10sats: OutputsRealizedSupplyPattern,
pub _100sats: OutputsRealizedSupplyPattern, pub _100sats: OutputsRealizedSupplyPattern,
pub _1k_sats: OutputsRealizedSupplyPattern, pub _1k_sats: OutputsRealizedSupplyPattern,
@@ -7322,7 +7322,7 @@ pub struct MetricsTree_Distribution_Cohorts_Utxo_LtAmount {
pub _100k_btc: OutputsRealizedSupplyPattern, pub _100k_btc: OutputsRealizedSupplyPattern,
} }
impl MetricsTree_Distribution_Cohorts_Utxo_LtAmount { impl MetricsTree_Distribution_Cohorts_Utxo_UnderAmount {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
_10sats: OutputsRealizedSupplyPattern::new(client.clone(), "utxos_under_10sats".to_string()), _10sats: OutputsRealizedSupplyPattern::new(client.clone(), "utxos_under_10sats".to_string()),
@@ -7394,61 +7394,61 @@ impl MetricsTree_Distribution_Cohorts_Utxo_Profitability {
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Utxo_Profitability_Range { pub struct MetricsTree_Distribution_Cohorts_Utxo_Profitability_Range {
pub profit_over_1000: RealizedSupplyPattern, pub over_1000pct_in_profit: RealizedSupplyPattern,
pub profit_500_to_1000: RealizedSupplyPattern, pub _500pct_to_1000pct_in_profit: RealizedSupplyPattern,
pub profit_300_to_500: RealizedSupplyPattern, pub _300pct_to_500pct_in_profit: RealizedSupplyPattern,
pub profit_200_to_300: RealizedSupplyPattern, pub _200pct_to_300pct_in_profit: RealizedSupplyPattern,
pub profit_100_to_200: RealizedSupplyPattern, pub _100pct_to_200pct_in_profit: RealizedSupplyPattern,
pub profit_90_to_100: RealizedSupplyPattern, pub _90pct_to_100pct_in_profit: RealizedSupplyPattern,
pub profit_80_to_90: RealizedSupplyPattern, pub _80pct_to_90pct_in_profit: RealizedSupplyPattern,
pub profit_70_to_80: RealizedSupplyPattern, pub _70pct_to_80pct_in_profit: RealizedSupplyPattern,
pub profit_60_to_70: RealizedSupplyPattern, pub _60pct_to_70pct_in_profit: RealizedSupplyPattern,
pub profit_50_to_60: RealizedSupplyPattern, pub _50pct_to_60pct_in_profit: RealizedSupplyPattern,
pub profit_40_to_50: RealizedSupplyPattern, pub _40pct_to_50pct_in_profit: RealizedSupplyPattern,
pub profit_30_to_40: RealizedSupplyPattern, pub _30pct_to_40pct_in_profit: RealizedSupplyPattern,
pub profit_20_to_30: RealizedSupplyPattern, pub _20pct_to_30pct_in_profit: RealizedSupplyPattern,
pub profit_10_to_20: RealizedSupplyPattern, pub _10pct_to_20pct_in_profit: RealizedSupplyPattern,
pub profit_0_to_10: RealizedSupplyPattern, pub _0pct_to_10pct_in_profit: RealizedSupplyPattern,
pub loss_0_to_10: RealizedSupplyPattern, pub _0pct_to_10pct_in_loss: RealizedSupplyPattern,
pub loss_10_to_20: RealizedSupplyPattern, pub _10pct_to_20pct_in_loss: RealizedSupplyPattern,
pub loss_20_to_30: RealizedSupplyPattern, pub _20pct_to_30pct_in_loss: RealizedSupplyPattern,
pub loss_30_to_40: RealizedSupplyPattern, pub _30pct_to_40pct_in_loss: RealizedSupplyPattern,
pub loss_40_to_50: RealizedSupplyPattern, pub _40pct_to_50pct_in_loss: RealizedSupplyPattern,
pub loss_50_to_60: RealizedSupplyPattern, pub _50pct_to_60pct_in_loss: RealizedSupplyPattern,
pub loss_60_to_70: RealizedSupplyPattern, pub _60pct_to_70pct_in_loss: RealizedSupplyPattern,
pub loss_70_to_80: RealizedSupplyPattern, pub _70pct_to_80pct_in_loss: RealizedSupplyPattern,
pub loss_80_to_90: RealizedSupplyPattern, pub _80pct_to_90pct_in_loss: RealizedSupplyPattern,
pub loss_90_to_100: RealizedSupplyPattern, pub _90pct_to_100pct_in_loss: RealizedSupplyPattern,
} }
impl MetricsTree_Distribution_Cohorts_Utxo_Profitability_Range { impl MetricsTree_Distribution_Cohorts_Utxo_Profitability_Range {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
profit_over_1000: RealizedSupplyPattern::new(client.clone(), "utxos_over_1000pct_up".to_string()), over_1000pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_over_1000pct_in_profit".to_string()),
profit_500_to_1000: RealizedSupplyPattern::new(client.clone(), "utxos_500pct_to_1000pct_up".to_string()), _500pct_to_1000pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_500pct_to_1000pct_in_profit".to_string()),
profit_300_to_500: RealizedSupplyPattern::new(client.clone(), "utxos_300pct_to_500pct_up".to_string()), _300pct_to_500pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_300pct_to_500pct_in_profit".to_string()),
profit_200_to_300: RealizedSupplyPattern::new(client.clone(), "utxos_200pct_to_300pct_up".to_string()), _200pct_to_300pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_200pct_to_300pct_in_profit".to_string()),
profit_100_to_200: RealizedSupplyPattern::new(client.clone(), "utxos_100pct_to_200pct_up".to_string()), _100pct_to_200pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_100pct_to_200pct_in_profit".to_string()),
profit_90_to_100: RealizedSupplyPattern::new(client.clone(), "utxos_90pct_to_100pct_up".to_string()), _90pct_to_100pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_90pct_to_100pct_in_profit".to_string()),
profit_80_to_90: RealizedSupplyPattern::new(client.clone(), "utxos_80pct_to_90pct_up".to_string()), _80pct_to_90pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_80pct_to_90pct_in_profit".to_string()),
profit_70_to_80: RealizedSupplyPattern::new(client.clone(), "utxos_70pct_to_80pct_up".to_string()), _70pct_to_80pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_70pct_to_80pct_in_profit".to_string()),
profit_60_to_70: RealizedSupplyPattern::new(client.clone(), "utxos_60pct_to_70pct_up".to_string()), _60pct_to_70pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_60pct_to_70pct_in_profit".to_string()),
profit_50_to_60: RealizedSupplyPattern::new(client.clone(), "utxos_50pct_to_60pct_up".to_string()), _50pct_to_60pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_50pct_to_60pct_in_profit".to_string()),
profit_40_to_50: RealizedSupplyPattern::new(client.clone(), "utxos_40pct_to_50pct_up".to_string()), _40pct_to_50pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_40pct_to_50pct_in_profit".to_string()),
profit_30_to_40: RealizedSupplyPattern::new(client.clone(), "utxos_30pct_to_40pct_up".to_string()), _30pct_to_40pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_30pct_to_40pct_in_profit".to_string()),
profit_20_to_30: RealizedSupplyPattern::new(client.clone(), "utxos_20pct_to_30pct_up".to_string()), _20pct_to_30pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_20pct_to_30pct_in_profit".to_string()),
profit_10_to_20: RealizedSupplyPattern::new(client.clone(), "utxos_10pct_to_20pct_up".to_string()), _10pct_to_20pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_10pct_to_20pct_in_profit".to_string()),
profit_0_to_10: RealizedSupplyPattern::new(client.clone(), "utxos_0pct_to_10pct_up".to_string()), _0pct_to_10pct_in_profit: RealizedSupplyPattern::new(client.clone(), "utxos_0pct_to_10pct_in_profit".to_string()),
loss_0_to_10: RealizedSupplyPattern::new(client.clone(), "utxos_0pct_to_10pct_down".to_string()), _0pct_to_10pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_0pct_to_10pct_in_loss".to_string()),
loss_10_to_20: RealizedSupplyPattern::new(client.clone(), "utxos_10pct_to_20pct_down".to_string()), _10pct_to_20pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_10pct_to_20pct_in_loss".to_string()),
loss_20_to_30: RealizedSupplyPattern::new(client.clone(), "utxos_20pct_to_30pct_down".to_string()), _20pct_to_30pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_20pct_to_30pct_in_loss".to_string()),
loss_30_to_40: RealizedSupplyPattern::new(client.clone(), "utxos_30pct_to_40pct_down".to_string()), _30pct_to_40pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_30pct_to_40pct_in_loss".to_string()),
loss_40_to_50: RealizedSupplyPattern::new(client.clone(), "utxos_40pct_to_50pct_down".to_string()), _40pct_to_50pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_40pct_to_50pct_in_loss".to_string()),
loss_50_to_60: RealizedSupplyPattern::new(client.clone(), "utxos_50pct_to_60pct_down".to_string()), _50pct_to_60pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_50pct_to_60pct_in_loss".to_string()),
loss_60_to_70: RealizedSupplyPattern::new(client.clone(), "utxos_60pct_to_70pct_down".to_string()), _60pct_to_70pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_60pct_to_70pct_in_loss".to_string()),
loss_70_to_80: RealizedSupplyPattern::new(client.clone(), "utxos_70pct_to_80pct_down".to_string()), _70pct_to_80pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_70pct_to_80pct_in_loss".to_string()),
loss_80_to_90: RealizedSupplyPattern::new(client.clone(), "utxos_80pct_to_90pct_down".to_string()), _80pct_to_90pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_80pct_to_90pct_in_loss".to_string()),
loss_90_to_100: RealizedSupplyPattern::new(client.clone(), "utxos_90pct_to_100pct_down".to_string()), _90pct_to_100pct_in_loss: RealizedSupplyPattern::new(client.clone(), "utxos_90pct_to_100pct_in_loss".to_string()),
} }
} }
} }
@@ -7469,27 +7469,25 @@ pub struct MetricsTree_Distribution_Cohorts_Utxo_Profitability_Profit {
pub _200pct: RealizedSupplyPattern, pub _200pct: RealizedSupplyPattern,
pub _300pct: RealizedSupplyPattern, pub _300pct: RealizedSupplyPattern,
pub _500pct: RealizedSupplyPattern, pub _500pct: RealizedSupplyPattern,
pub _1000pct: RealizedSupplyPattern,
} }
impl MetricsTree_Distribution_Cohorts_Utxo_Profitability_Profit { impl MetricsTree_Distribution_Cohorts_Utxo_Profitability_Profit {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
breakeven: RealizedSupplyPattern::new(client.clone(), "profit_ge_breakeven".to_string()), breakeven: RealizedSupplyPattern::new(client.clone(), "utxos_in_profit".to_string()),
_10pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_10pct".to_string()), _10pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_10pct_in_profit".to_string()),
_20pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_20pct".to_string()), _20pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_20pct_in_profit".to_string()),
_30pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_30pct".to_string()), _30pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_30pct_in_profit".to_string()),
_40pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_40pct".to_string()), _40pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_40pct_in_profit".to_string()),
_50pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_50pct".to_string()), _50pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_50pct_in_profit".to_string()),
_60pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_60pct".to_string()), _60pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_60pct_in_profit".to_string()),
_70pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_70pct".to_string()), _70pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_70pct_in_profit".to_string()),
_80pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_80pct".to_string()), _80pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_80pct_in_profit".to_string()),
_90pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_90pct".to_string()), _90pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_90pct_in_profit".to_string()),
_100pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_100pct".to_string()), _100pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_100pct_in_profit".to_string()),
_200pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_200pct".to_string()), _200pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_200pct_in_profit".to_string()),
_300pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_300pct".to_string()), _300pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_300pct_in_profit".to_string()),
_500pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_500pct".to_string()), _500pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_500pct_in_profit".to_string()),
_1000pct: RealizedSupplyPattern::new(client.clone(), "profit_ge_1000pct".to_string()),
} }
} }
} }
@@ -7505,22 +7503,20 @@ pub struct MetricsTree_Distribution_Cohorts_Utxo_Profitability_Loss {
pub _60pct: RealizedSupplyPattern, pub _60pct: RealizedSupplyPattern,
pub _70pct: RealizedSupplyPattern, pub _70pct: RealizedSupplyPattern,
pub _80pct: RealizedSupplyPattern, pub _80pct: RealizedSupplyPattern,
pub _90pct: RealizedSupplyPattern,
} }
impl MetricsTree_Distribution_Cohorts_Utxo_Profitability_Loss { impl MetricsTree_Distribution_Cohorts_Utxo_Profitability_Loss {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
breakeven: RealizedSupplyPattern::new(client.clone(), "loss_ge_breakeven".to_string()), breakeven: RealizedSupplyPattern::new(client.clone(), "utxos_in_loss".to_string()),
_10pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_10pct".to_string()), _10pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_10pct_in_loss".to_string()),
_20pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_20pct".to_string()), _20pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_20pct_in_loss".to_string()),
_30pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_30pct".to_string()), _30pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_30pct_in_loss".to_string()),
_40pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_40pct".to_string()), _40pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_40pct_in_loss".to_string()),
_50pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_50pct".to_string()), _50pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_50pct_in_loss".to_string()),
_60pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_60pct".to_string()), _60pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_60pct_in_loss".to_string()),
_70pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_70pct".to_string()), _70pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_70pct_in_loss".to_string()),
_80pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_80pct".to_string()), _80pct: RealizedSupplyPattern::new(client.clone(), "utxos_over_80pct_in_loss".to_string()),
_90pct: RealizedSupplyPattern::new(client.clone(), "loss_ge_90pct".to_string()),
} }
} }
} }
@@ -7580,23 +7576,23 @@ impl MetricsTree_Distribution_Cohorts_Utxo_Matured {
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Address { pub struct MetricsTree_Distribution_Cohorts_Address {
pub ge_amount: MetricsTree_Distribution_Cohorts_Address_GeAmount, pub over_amount: MetricsTree_Distribution_Cohorts_Address_OverAmount,
pub amount_range: MetricsTree_Distribution_Cohorts_Address_AmountRange, pub amount_range: MetricsTree_Distribution_Cohorts_Address_AmountRange,
pub lt_amount: MetricsTree_Distribution_Cohorts_Address_LtAmount, pub under_amount: MetricsTree_Distribution_Cohorts_Address_UnderAmount,
} }
impl MetricsTree_Distribution_Cohorts_Address { impl MetricsTree_Distribution_Cohorts_Address {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
ge_amount: MetricsTree_Distribution_Cohorts_Address_GeAmount::new(client.clone(), format!("{base_path}_ge_amount")), over_amount: MetricsTree_Distribution_Cohorts_Address_OverAmount::new(client.clone(), format!("{base_path}_over_amount")),
amount_range: MetricsTree_Distribution_Cohorts_Address_AmountRange::new(client.clone(), format!("{base_path}_amount_range")), amount_range: MetricsTree_Distribution_Cohorts_Address_AmountRange::new(client.clone(), format!("{base_path}_amount_range")),
lt_amount: MetricsTree_Distribution_Cohorts_Address_LtAmount::new(client.clone(), format!("{base_path}_lt_amount")), under_amount: MetricsTree_Distribution_Cohorts_Address_UnderAmount::new(client.clone(), format!("{base_path}_under_amount")),
} }
} }
} }
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Address_GeAmount { pub struct MetricsTree_Distribution_Cohorts_Address_OverAmount {
pub _1sat: AddrOutputsRealizedSupplyPattern, pub _1sat: AddrOutputsRealizedSupplyPattern,
pub _10sats: AddrOutputsRealizedSupplyPattern, pub _10sats: AddrOutputsRealizedSupplyPattern,
pub _100sats: AddrOutputsRealizedSupplyPattern, pub _100sats: AddrOutputsRealizedSupplyPattern,
@@ -7612,7 +7608,7 @@ pub struct MetricsTree_Distribution_Cohorts_Address_GeAmount {
pub _10k_btc: AddrOutputsRealizedSupplyPattern, pub _10k_btc: AddrOutputsRealizedSupplyPattern,
} }
impl MetricsTree_Distribution_Cohorts_Address_GeAmount { impl MetricsTree_Distribution_Cohorts_Address_OverAmount {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
_1sat: AddrOutputsRealizedSupplyPattern::new(client.clone(), "addrs_over_1sat".to_string()), _1sat: AddrOutputsRealizedSupplyPattern::new(client.clone(), "addrs_over_1sat".to_string()),
@@ -7674,7 +7670,7 @@ impl MetricsTree_Distribution_Cohorts_Address_AmountRange {
} }
/// Metrics tree node. /// Metrics tree node.
pub struct MetricsTree_Distribution_Cohorts_Address_LtAmount { pub struct MetricsTree_Distribution_Cohorts_Address_UnderAmount {
pub _10sats: AddrOutputsRealizedSupplyPattern, pub _10sats: AddrOutputsRealizedSupplyPattern,
pub _100sats: AddrOutputsRealizedSupplyPattern, pub _100sats: AddrOutputsRealizedSupplyPattern,
pub _1k_sats: AddrOutputsRealizedSupplyPattern, pub _1k_sats: AddrOutputsRealizedSupplyPattern,
@@ -7690,7 +7686,7 @@ pub struct MetricsTree_Distribution_Cohorts_Address_LtAmount {
pub _100k_btc: AddrOutputsRealizedSupplyPattern, pub _100k_btc: AddrOutputsRealizedSupplyPattern,
} }
impl MetricsTree_Distribution_Cohorts_Address_LtAmount { impl MetricsTree_Distribution_Cohorts_Address_UnderAmount {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
_10sats: AddrOutputsRealizedSupplyPattern::new(client.clone(), "addrs_under_10sats".to_string()), _10sats: AddrOutputsRealizedSupplyPattern::new(client.clone(), "addrs_under_10sats".to_string()),
@@ -8106,6 +8102,24 @@ impl BrkClient {
self.base.get_json(&format!("/api/metric/{metric}/{}/latest", index.name())) self.base.get_json(&format!("/api/metric/{metric}/{}/latest", index.name()))
} }
/// Get metric data length
///
/// Returns the total number of data points for a metric at the given index.
///
/// Endpoint: `GET /api/metric/{metric}/{index}/len`
pub fn get_metric_len(&self, metric: Metric, index: Index) -> Result<f64> {
self.base.get_json(&format!("/api/metric/{metric}/{}/len", index.name()))
}
/// Get metric version
///
/// Returns the current version of a metric. Changes when the metric data is updated.
///
/// Endpoint: `GET /api/metric/{metric}/{index}/version`
pub fn get_metric_version(&self, metric: Metric, index: Index) -> Result<Version> {
self.base.get_json(&format!("/api/metric/{metric}/{}/version", index.name()))
}
/// Metrics catalog /// Metrics catalog
/// ///
/// Returns the complete hierarchical catalog of available metrics organized as a tree structure. Metrics are grouped by categories and subcategories. /// Returns the complete hierarchical catalog of available metrics organized as a tree structure. Metrics are grouped by categories and subcategories.

View File

@@ -3,13 +3,13 @@ use rayon::prelude::*;
use crate::Filter; use crate::Filter;
use super::{ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount}; use super::{AmountRange, OverAmount, UnderAmount};
#[derive(Default, Clone, Traversable)] #[derive(Default, Clone, Traversable)]
pub struct AddressGroups<T> { pub struct AddressGroups<T> {
pub ge_amount: ByGreatEqualAmount<T>, pub over_amount: OverAmount<T>,
pub amount_range: ByAmountRange<T>, pub amount_range: AmountRange<T>,
pub lt_amount: ByLowerThanAmount<T>, pub under_amount: UnderAmount<T>,
} }
impl<T> AddressGroups<T> { impl<T> AddressGroups<T> {
@@ -18,9 +18,9 @@ impl<T> AddressGroups<T> {
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,
{ {
Self { Self {
ge_amount: ByGreatEqualAmount::new(&mut create), over_amount: OverAmount::new(&mut create),
amount_range: ByAmountRange::new(&mut create), amount_range: AmountRange::new(&mut create),
lt_amount: ByLowerThanAmount::new(&mut create), under_amount: UnderAmount::new(&mut create),
} }
} }
@@ -29,34 +29,34 @@ impl<T> AddressGroups<T> {
F: Fn(Filter, &'static str) -> Result<T, E>, F: Fn(Filter, &'static str) -> Result<T, E>,
{ {
Ok(Self { Ok(Self {
ge_amount: ByGreatEqualAmount::try_new(create)?, over_amount: OverAmount::try_new(create)?,
amount_range: ByAmountRange::try_new(create)?, amount_range: AmountRange::try_new(create)?,
lt_amount: ByLowerThanAmount::try_new(create)?, under_amount: UnderAmount::try_new(create)?,
}) })
} }
pub fn iter(&self) -> impl Iterator<Item = &T> { pub fn iter(&self) -> impl Iterator<Item = &T> {
self.ge_amount self.over_amount
.iter() .iter()
.chain(self.amount_range.iter()) .chain(self.amount_range.iter())
.chain(self.lt_amount.iter()) .chain(self.under_amount.iter())
} }
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> { pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.ge_amount self.over_amount
.iter_mut() .iter_mut()
.chain(self.amount_range.iter_mut()) .chain(self.amount_range.iter_mut())
.chain(self.lt_amount.iter_mut()) .chain(self.under_amount.iter_mut())
} }
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut T> pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut T>
where where
T: Send + Sync, T: Send + Sync,
{ {
self.ge_amount self.over_amount
.par_iter_mut() .par_iter_mut()
.chain(self.amount_range.par_iter_mut()) .chain(self.amount_range.par_iter_mut())
.chain(self.lt_amount.par_iter_mut()) .chain(self.under_amount.par_iter_mut())
} }
pub fn iter_separate(&self) -> impl Iterator<Item = &T> { pub fn iter_separate(&self) -> impl Iterator<Item = &T> {
@@ -75,7 +75,7 @@ impl<T> AddressGroups<T> {
} }
pub fn iter_overlapping_mut(&mut self) -> impl Iterator<Item = &mut T> { pub fn iter_overlapping_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.lt_amount.iter_mut().chain(self.ge_amount.iter_mut()) self.under_amount.iter_mut().chain(self.over_amount.iter_mut())
} }
} }

View File

@@ -38,7 +38,7 @@ pub const AGE_BOUNDARIES: [usize; 20] = [
]; ];
/// Age range bounds (end = usize::MAX means unbounded) /// Age range bounds (end = usize::MAX means unbounded)
pub const AGE_RANGE_BOUNDS: ByAgeRange<Range<usize>> = ByAgeRange { pub const AGE_RANGE_BOUNDS: AgeRange<Range<usize>> = AgeRange {
up_to_1h: 0..HOURS_1H, up_to_1h: 0..HOURS_1H,
_1h_to_1d: HOURS_1H..HOURS_1D, _1h_to_1d: HOURS_1H..HOURS_1D,
_1d_to_1w: HOURS_1D..HOURS_1W, _1d_to_1w: HOURS_1D..HOURS_1W,
@@ -63,7 +63,7 @@ pub const AGE_RANGE_BOUNDS: ByAgeRange<Range<usize>> = ByAgeRange {
}; };
/// Age range filters /// Age range filters
pub const AGE_RANGE_FILTERS: ByAgeRange<Filter> = ByAgeRange { pub const AGE_RANGE_FILTERS: AgeRange<Filter> = AgeRange {
up_to_1h: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS.up_to_1h)), up_to_1h: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS.up_to_1h)),
_1h_to_1d: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1h_to_1d)), _1h_to_1d: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1h_to_1d)),
_1d_to_1w: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1d_to_1w)), _1d_to_1w: Filter::Time(TimeFilter::Range(AGE_RANGE_BOUNDS._1d_to_1w)),
@@ -88,7 +88,7 @@ pub const AGE_RANGE_FILTERS: ByAgeRange<Filter> = ByAgeRange {
}; };
/// Age range names /// Age range names
pub const AGE_RANGE_NAMES: ByAgeRange<CohortName> = ByAgeRange { pub const AGE_RANGE_NAMES: AgeRange<CohortName> = AgeRange {
up_to_1h: CohortName::new("under_1h_old", "<1h", "Under 1 Hour Old"), up_to_1h: CohortName::new("under_1h_old", "<1h", "Under 1 Hour Old"),
_1h_to_1d: CohortName::new("1h_to_1d_old", "1h-1d", "1 Hour to 1 Day Old"), _1h_to_1d: CohortName::new("1h_to_1d_old", "1h-1d", "1 Hour to 1 Day Old"),
_1d_to_1w: CohortName::new("1d_to_1w_old", "1d-1w", "1 Day to 1 Week Old"), _1d_to_1w: CohortName::new("1d_to_1w_old", "1d-1w", "1 Day to 1 Week Old"),
@@ -112,14 +112,14 @@ pub const AGE_RANGE_NAMES: ByAgeRange<CohortName> = ByAgeRange {
from_15y: CohortName::new("over_15y_old", "15y+", "15+ Years Old"), from_15y: CohortName::new("over_15y_old", "15y+", "15+ Years Old"),
}; };
impl ByAgeRange<CohortName> { impl AgeRange<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&AGE_RANGE_NAMES &AGE_RANGE_NAMES
} }
} }
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByAgeRange<T> { pub struct AgeRange<T> {
pub up_to_1h: T, pub up_to_1h: T,
pub _1h_to_1d: T, pub _1h_to_1d: T,
pub _1d_to_1w: T, pub _1d_to_1w: T,
@@ -143,7 +143,7 @@ pub struct ByAgeRange<T> {
pub from_15y: T, pub from_15y: T,
} }
impl<T> ByAgeRange<T> { impl<T> AgeRange<T> {
/// Get mutable reference by Age. O(1). /// Get mutable reference by Age. O(1).
#[inline] #[inline]
pub fn get_mut(&mut self, age: Age) -> &mut T { pub fn get_mut(&mut self, age: Age) -> &mut T {

View File

@@ -13,7 +13,7 @@ pub struct AmountBucket(u8);
impl AmountBucket { impl AmountBucket {
/// Returns (self, other) if buckets differ, None if same. /// Returns (self, other) if buckets differ, None if same.
/// Use with `ByAmountRange::get_mut_by_bucket` to avoid recomputing. /// Use with `AmountRange::get_mut_by_bucket` to avoid recomputing.
#[inline(always)] #[inline(always)]
pub fn transition_to(self, other: Self) -> Option<(Self, Self)> { pub fn transition_to(self, other: Self) -> Option<(Self, Self)> {
if self != other { if self != other {
@@ -59,7 +59,7 @@ pub fn amounts_in_different_buckets(a: Sats, b: Sats) -> bool {
} }
/// Amount range bounds /// Amount range bounds
pub const AMOUNT_RANGE_BOUNDS: ByAmountRange<Range<Sats>> = ByAmountRange { pub const AMOUNT_RANGE_BOUNDS: AmountRange<Range<Sats>> = AmountRange {
_0sats: Sats::ZERO..Sats::_1, _0sats: Sats::ZERO..Sats::_1,
_1sat_to_10sats: Sats::_1..Sats::_10, _1sat_to_10sats: Sats::_1..Sats::_10,
_10sats_to_100sats: Sats::_10..Sats::_100, _10sats_to_100sats: Sats::_10..Sats::_100,
@@ -78,7 +78,7 @@ pub const AMOUNT_RANGE_BOUNDS: ByAmountRange<Range<Sats>> = ByAmountRange {
}; };
/// Amount range names /// Amount range names
pub const AMOUNT_RANGE_NAMES: ByAmountRange<CohortName> = ByAmountRange { pub const AMOUNT_RANGE_NAMES: AmountRange<CohortName> = AmountRange {
_0sats: CohortName::new("with_0sats", "0 sats", "0 Sats"), _0sats: CohortName::new("with_0sats", "0 sats", "0 Sats"),
_1sat_to_10sats: CohortName::new("above_1sat_under_10sats", "1-10 sats", "1-10 Sats"), _1sat_to_10sats: CohortName::new("above_1sat_under_10sats", "1-10 sats", "1-10 Sats"),
_10sats_to_100sats: CohortName::new("above_10sats_under_100sats", "10-100 sats", "10-100 Sats"), _10sats_to_100sats: CohortName::new("above_10sats_under_100sats", "10-100 sats", "10-100 Sats"),
@@ -121,7 +121,7 @@ pub const AMOUNT_RANGE_NAMES: ByAmountRange<CohortName> = ByAmountRange {
}; };
/// Amount range filters /// Amount range filters
pub const AMOUNT_RANGE_FILTERS: ByAmountRange<Filter> = ByAmountRange { pub const AMOUNT_RANGE_FILTERS: AmountRange<Filter> = AmountRange {
_0sats: Filter::Amount(AmountFilter::Range(AMOUNT_RANGE_BOUNDS._0sats)), _0sats: Filter::Amount(AmountFilter::Range(AMOUNT_RANGE_BOUNDS._0sats)),
_1sat_to_10sats: Filter::Amount(AmountFilter::Range(AMOUNT_RANGE_BOUNDS._1sat_to_10sats)), _1sat_to_10sats: Filter::Amount(AmountFilter::Range(AMOUNT_RANGE_BOUNDS._1sat_to_10sats)),
_10sats_to_100sats: Filter::Amount(AmountFilter::Range(AMOUNT_RANGE_BOUNDS._10sats_to_100sats)), _10sats_to_100sats: Filter::Amount(AmountFilter::Range(AMOUNT_RANGE_BOUNDS._10sats_to_100sats)),
@@ -152,7 +152,7 @@ pub const AMOUNT_RANGE_FILTERS: ByAmountRange<Filter> = ByAmountRange {
}; };
#[derive(Debug, Default, Clone, Traversable, Serialize)] #[derive(Debug, Default, Clone, Traversable, Serialize)]
pub struct ByAmountRange<T> { pub struct AmountRange<T> {
pub _0sats: T, pub _0sats: T,
pub _1sat_to_10sats: T, pub _1sat_to_10sats: T,
pub _10sats_to_100sats: T, pub _10sats_to_100sats: T,
@@ -170,13 +170,13 @@ pub struct ByAmountRange<T> {
pub _100k_btc_or_more: T, pub _100k_btc_or_more: T,
} }
impl ByAmountRange<CohortName> { impl AmountRange<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&AMOUNT_RANGE_NAMES &AMOUNT_RANGE_NAMES
} }
} }
impl<T> ByAmountRange<T> { impl<T> AmountRange<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,
@@ -385,7 +385,7 @@ impl<T> ByAmountRange<T> {
} }
} }
impl<T> Add for ByAmountRange<T> impl<T> Add for AmountRange<T>
where where
T: Add<Output = T>, T: Add<Output = T>,
{ {
@@ -411,7 +411,7 @@ where
} }
} }
impl<T> AddAssign for ByAmountRange<T> impl<T> AddAssign for AmountRange<T>
where where
T: AddAssign, T: AddAssign,
{ {

View File

@@ -2,15 +2,15 @@ use std::ops::{Add, AddAssign};
use brk_types::OutputType; use brk_types::OutputType;
use super::{BySpendableType, ByUnspendableType}; use super::{SpendableType, UnspendableType};
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
pub struct GroupedByType<T> { pub struct ByType<T> {
pub spendable: BySpendableType<T>, pub spendable: SpendableType<T>,
pub unspendable: ByUnspendableType<T>, pub unspendable: UnspendableType<T>,
} }
impl<T> GroupedByType<T> { impl<T> ByType<T> {
pub fn get(&self, output_type: OutputType) -> &T { pub fn get(&self, output_type: OutputType) -> &T {
match output_type { match output_type {
OutputType::P2PK65 => &self.spendable.p2pk65, OutputType::P2PK65 => &self.spendable.p2pk65,
@@ -46,7 +46,7 @@ impl<T> GroupedByType<T> {
} }
} }
impl<T> Add for GroupedByType<T> impl<T> Add for ByType<T>
where where
T: Add<Output = T>, T: Add<Output = T>,
{ {
@@ -59,7 +59,7 @@ where
} }
} }
impl<T> AddAssign for GroupedByType<T> impl<T> AddAssign for ByType<T>
where where
T: AddAssign, T: AddAssign,
{ {

View File

@@ -1,37 +0,0 @@
#[derive(Default, Clone)]
pub struct GroupedByValue<T> {
pub up_to_1cent: T,
pub from_1c_to_10c: T,
pub from_10c_to_1d: T,
pub from_1d_to_10d: T,
pub from_10usd_to_100usd: T,
pub from_100usd_to_1_000usd: T,
pub from_1_000usd_to_10_000usd: T,
pub from_10_000usd_to_100_000usd: T,
pub from_100_000usd_to_1_000_000usd: T,
pub from_1_000_000usd_to_10_000_000usd: T,
pub from_10_000_000usd_to_100_000_000usd: T,
pub from_100_000_000usd_to_1_000_000_000usd: T,
pub from_1_000_000_000usd: T,
// ...
}
impl<T> GroupedByValue<T> {
pub fn as_mut_vec(&mut self) -> Vec<&mut T> {
vec![
&mut self.up_to_1cent,
&mut self.from_1c_to_10c,
&mut self.from_10c_to_1d,
&mut self.from_1d_to_10d,
&mut self.from_10usd_to_100usd,
&mut self.from_100usd_to_1_000usd,
&mut self.from_1_000usd_to_10_000usd,
&mut self.from_10_000usd_to_100_000usd,
&mut self.from_100_000usd_to_1_000_000usd,
&mut self.from_1_000_000usd_to_10_000_000usd,
&mut self.from_10_000_000usd_to_100_000_000usd,
&mut self.from_100_000_000usd_to_1_000_000_000usd,
&mut self.from_1_000_000_000usd,
]
}
}

View File

@@ -6,7 +6,7 @@ use serde::Serialize;
use super::{CohortName, Filter}; use super::{CohortName, Filter};
/// Class values /// Class values
pub const CLASS_VALUES: ByClass<Year> = ByClass { pub const CLASS_VALUES: Class<Year> = Class {
_2009: Year::new(2009), _2009: Year::new(2009),
_2010: Year::new(2010), _2010: Year::new(2010),
_2011: Year::new(2011), _2011: Year::new(2011),
@@ -28,7 +28,7 @@ pub const CLASS_VALUES: ByClass<Year> = ByClass {
}; };
/// Class filters /// Class filters
pub const CLASS_FILTERS: ByClass<Filter> = ByClass { pub const CLASS_FILTERS: Class<Filter> = Class {
_2009: Filter::Class(CLASS_VALUES._2009), _2009: Filter::Class(CLASS_VALUES._2009),
_2010: Filter::Class(CLASS_VALUES._2010), _2010: Filter::Class(CLASS_VALUES._2010),
_2011: Filter::Class(CLASS_VALUES._2011), _2011: Filter::Class(CLASS_VALUES._2011),
@@ -50,7 +50,7 @@ pub const CLASS_FILTERS: ByClass<Filter> = ByClass {
}; };
/// Class names /// Class names
pub const CLASS_NAMES: ByClass<CohortName> = ByClass { pub const CLASS_NAMES: Class<CohortName> = Class {
_2009: CohortName::new("class_2009", "2009", "Class 2009"), _2009: CohortName::new("class_2009", "2009", "Class 2009"),
_2010: CohortName::new("class_2010", "2010", "Class 2010"), _2010: CohortName::new("class_2010", "2010", "Class 2010"),
_2011: CohortName::new("class_2011", "2011", "Class 2011"), _2011: CohortName::new("class_2011", "2011", "Class 2011"),
@@ -72,7 +72,7 @@ pub const CLASS_NAMES: ByClass<CohortName> = ByClass {
}; };
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByClass<T> { pub struct Class<T> {
pub _2009: T, pub _2009: T,
pub _2010: T, pub _2010: T,
pub _2011: T, pub _2011: T,
@@ -93,13 +93,13 @@ pub struct ByClass<T> {
pub _2026: T, pub _2026: T,
} }
impl ByClass<CohortName> { impl Class<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&CLASS_NAMES &CLASS_NAMES
} }
} }
impl<T> ByClass<T> { impl<T> Class<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,

View File

@@ -89,7 +89,7 @@ impl Filter {
} }
/// Whether to compute adjusted metrics (adjusted SOPR, adjusted value created/destroyed) /// Whether to compute adjusted metrics (adjusted SOPR, adjusted value created/destroyed)
/// For UTXO context: true for All, STH, and max_age (LowerThan) /// For UTXO context: true for All, STH, and under_age (LowerThan)
/// For Address context: always false /// For Address context: always false
/// Note: LTH doesn't need adjusted (everything >= 5 months is already > 1 hour) /// Note: LTH doesn't need adjusted (everything >= 5 months is already > 1 hour)
/// Note: age ranges don't need adjusted (0-1h data lives in its own cohort) /// Note: age ranges don't need adjusted (0-1h data lives in its own cohort)

View File

@@ -2,56 +2,56 @@
mod address; mod address;
mod amount_filter; mod amount_filter;
mod age_range;
mod amount_range;
mod by_address_type; mod by_address_type;
mod by_age_range;
mod by_amount_range;
mod by_any_address; mod by_any_address;
mod by_epoch; mod by_epoch;
mod by_ge_amount;
mod by_loss;
mod by_lt_amount;
mod by_max_age;
mod by_min_age;
mod by_profitability_range;
mod by_profit;
mod by_spendable_type;
mod by_term; mod by_term;
mod by_type; mod by_type;
mod by_unspendable_type; mod class;
mod by_class;
mod cohort_context; mod cohort_context;
mod cohort_name; mod cohort_name;
mod filter; mod filter;
mod filtered; mod filtered;
mod loss;
mod over_age;
mod over_amount;
mod profit;
mod profitability_range;
mod spendable_type;
mod state_level; mod state_level;
mod time_filter; mod time_filter;
mod under_age;
mod under_amount;
mod unspendable_type;
mod utxo; mod utxo;
pub use brk_types::{Age, Term}; pub use brk_types::{Age, Term};
pub use address::*; pub use address::*;
pub use amount_filter::*; pub use amount_filter::*;
pub use age_range::*;
pub use amount_range::*;
pub use by_address_type::*; pub use by_address_type::*;
pub use by_age_range::*;
pub use by_amount_range::*;
pub use by_any_address::*; pub use by_any_address::*;
pub use by_epoch::*; pub use by_epoch::*;
pub use by_ge_amount::*;
pub use by_loss::*;
pub use by_lt_amount::*;
pub use by_max_age::*;
pub use by_min_age::*;
pub use by_profitability_range::*;
pub use by_profit::*;
pub use by_spendable_type::*;
pub use by_term::*; pub use by_term::*;
pub use by_type::*; pub use by_type::*;
pub use by_unspendable_type::*; pub use class::*;
pub use by_class::*;
pub use cohort_context::*; pub use cohort_context::*;
pub use cohort_name::*; pub use cohort_name::*;
pub use filter::*; pub use filter::*;
pub use filtered::*; pub use filtered::*;
pub use loss::*;
pub use over_age::*;
pub use over_amount::*;
pub use profit::*;
pub use profitability_range::*;
pub use spendable_type::*;
pub use state_level::*; pub use state_level::*;
pub use time_filter::*; pub use time_filter::*;
pub use under_age::*;
pub use under_amount::*;
pub use unspendable_type::*;
pub use utxo::*; pub use utxo::*;

View File

@@ -5,7 +5,7 @@ use serde::Serialize;
use super::CohortName; use super::CohortName;
/// "At least X% loss" threshold names (10 thresholds). /// "At least X% loss" threshold names (10 thresholds).
pub const LOSS_NAMES: ByLoss<CohortName> = ByLoss { pub const LOSS_NAMES: Loss<CohortName> = Loss {
breakeven: CohortName::new("utxos_in_loss", "<0%", "In Loss (Below Breakeven)"), breakeven: CohortName::new("utxos_in_loss", "<0%", "In Loss (Below Breakeven)"),
_10pct: CohortName::new("utxos_over_10pct_in_loss", "≥10%L", "10%+ Loss"), _10pct: CohortName::new("utxos_over_10pct_in_loss", "≥10%L", "10%+ Loss"),
_20pct: CohortName::new("utxos_over_20pct_in_loss", "≥20%L", "20%+ Loss"), _20pct: CohortName::new("utxos_over_20pct_in_loss", "≥20%L", "20%+ Loss"),
@@ -15,13 +15,12 @@ pub const LOSS_NAMES: ByLoss<CohortName> = ByLoss {
_60pct: CohortName::new("utxos_over_60pct_in_loss", "≥60%L", "60%+ Loss"), _60pct: CohortName::new("utxos_over_60pct_in_loss", "≥60%L", "60%+ Loss"),
_70pct: CohortName::new("utxos_over_70pct_in_loss", "≥70%L", "70%+ Loss"), _70pct: CohortName::new("utxos_over_70pct_in_loss", "≥70%L", "70%+ Loss"),
_80pct: CohortName::new("utxos_over_80pct_in_loss", "≥80%L", "80%+ Loss"), _80pct: CohortName::new("utxos_over_80pct_in_loss", "≥80%L", "80%+ Loss"),
_90pct: CohortName::new("utxos_over_90pct_in_loss", "≥90%L", "90%+ Loss"),
}; };
/// Number of loss thresholds. /// Number of loss thresholds.
pub const LOSS_COUNT: usize = 10; pub const LOSS_COUNT: usize = 9;
impl ByLoss<CohortName> { impl Loss<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&LOSS_NAMES &LOSS_NAMES
} }
@@ -31,7 +30,7 @@ impl ByLoss<CohortName> {
/// ///
/// Each is a suffix sum over the profitability ranges, from most loss-making up. /// Each is a suffix sum over the profitability ranges, from most loss-making up.
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByLoss<T> { pub struct Loss<T> {
pub breakeven: T, pub breakeven: T,
pub _10pct: T, pub _10pct: T,
pub _20pct: T, pub _20pct: T,
@@ -41,10 +40,9 @@ pub struct ByLoss<T> {
pub _60pct: T, pub _60pct: T,
pub _70pct: T, pub _70pct: T,
pub _80pct: T, pub _80pct: T,
pub _90pct: T,
} }
impl<T> ByLoss<T> { impl<T> Loss<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(&'static str) -> T, F: FnMut(&'static str) -> T,
@@ -60,7 +58,6 @@ impl<T> ByLoss<T> {
_60pct: create(n._60pct.id), _60pct: create(n._60pct.id),
_70pct: create(n._70pct.id), _70pct: create(n._70pct.id),
_80pct: create(n._80pct.id), _80pct: create(n._80pct.id),
_90pct: create(n._90pct.id),
} }
} }
@@ -79,7 +76,6 @@ impl<T> ByLoss<T> {
_60pct: create(n._60pct.id)?, _60pct: create(n._60pct.id)?,
_70pct: create(n._70pct.id)?, _70pct: create(n._70pct.id)?,
_80pct: create(n._80pct.id)?, _80pct: create(n._80pct.id)?,
_90pct: create(n._90pct.id)?,
}) })
} }
@@ -94,7 +90,6 @@ impl<T> ByLoss<T> {
&self._60pct, &self._60pct,
&self._70pct, &self._70pct,
&self._80pct, &self._80pct,
&self._90pct,
] ]
.into_iter() .into_iter()
} }
@@ -110,7 +105,6 @@ impl<T> ByLoss<T> {
&mut self._60pct, &mut self._60pct,
&mut self._70pct, &mut self._70pct,
&mut self._80pct, &mut self._80pct,
&mut self._90pct,
] ]
.into_iter() .into_iter()
} }
@@ -129,7 +123,6 @@ impl<T> ByLoss<T> {
&mut self._60pct, &mut self._60pct,
&mut self._70pct, &mut self._70pct,
&mut self._80pct, &mut self._80pct,
&mut self._90pct,
] ]
.into_par_iter() .into_par_iter()
} }
@@ -146,7 +139,6 @@ impl<T> ByLoss<T> {
&mut self._60pct, &mut self._60pct,
&mut self._70pct, &mut self._70pct,
&mut self._80pct, &mut self._80pct,
&mut self._90pct,
] ]
} }
} }

View File

@@ -8,8 +8,8 @@ use super::{
HOURS_10Y, HOURS_12Y, TimeFilter, HOURS_10Y, HOURS_12Y, TimeFilter,
}; };
/// Min age thresholds in hours /// Over-age thresholds in hours
pub const MIN_AGE_HOURS: ByMinAge<usize> = ByMinAge { pub const OVER_AGE_HOURS: OverAge<usize> = OverAge {
_1d: HOURS_1D, _1d: HOURS_1D,
_1w: HOURS_1W, _1w: HOURS_1W,
_1m: HOURS_1M, _1m: HOURS_1M,
@@ -30,30 +30,30 @@ pub const MIN_AGE_HOURS: ByMinAge<usize> = ByMinAge {
_12y: HOURS_12Y, _12y: HOURS_12Y,
}; };
/// Min age filters (GreaterOrEqual threshold in hours) /// Over-age filters (GreaterOrEqual threshold in hours)
pub const MIN_AGE_FILTERS: ByMinAge<Filter> = ByMinAge { pub const OVER_AGE_FILTERS: OverAge<Filter> = OverAge {
_1d: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1d)), _1d: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._1d)),
_1w: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1w)), _1w: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._1w)),
_1m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1m)), _1m: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._1m)),
_2m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._2m)), _2m: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._2m)),
_3m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._3m)), _3m: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._3m)),
_4m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._4m)), _4m: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._4m)),
_5m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._5m)), _5m: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._5m)),
_6m: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._6m)), _6m: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._6m)),
_1y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._1y)), _1y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._1y)),
_2y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._2y)), _2y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._2y)),
_3y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._3y)), _3y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._3y)),
_4y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._4y)), _4y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._4y)),
_5y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._5y)), _5y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._5y)),
_6y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._6y)), _6y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._6y)),
_7y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._7y)), _7y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._7y)),
_8y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._8y)), _8y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._8y)),
_10y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._10y)), _10y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._10y)),
_12y: Filter::Time(TimeFilter::GreaterOrEqual(MIN_AGE_HOURS._12y)), _12y: Filter::Time(TimeFilter::GreaterOrEqual(OVER_AGE_HOURS._12y)),
}; };
/// Min age names /// Over-age names
pub const MIN_AGE_NAMES: ByMinAge<CohortName> = ByMinAge { pub const OVER_AGE_NAMES: OverAge<CohortName> = OverAge {
_1d: CohortName::new("over_1d_old", "1d+", "Over 1 Day Old"), _1d: CohortName::new("over_1d_old", "1d+", "Over 1 Day Old"),
_1w: CohortName::new("over_1w_old", "1w+", "Over 1 Week Old"), _1w: CohortName::new("over_1w_old", "1w+", "Over 1 Week Old"),
_1m: CohortName::new("over_1m_old", "1m+", "Over 1 Month Old"), _1m: CohortName::new("over_1m_old", "1m+", "Over 1 Month Old"),
@@ -75,7 +75,7 @@ pub const MIN_AGE_NAMES: ByMinAge<CohortName> = ByMinAge {
}; };
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByMinAge<T> { pub struct OverAge<T> {
pub _1d: T, pub _1d: T,
pub _1w: T, pub _1w: T,
pub _1m: T, pub _1m: T,
@@ -96,19 +96,19 @@ pub struct ByMinAge<T> {
pub _12y: T, pub _12y: T,
} }
impl ByMinAge<CohortName> { impl OverAge<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&MIN_AGE_NAMES &OVER_AGE_NAMES
} }
} }
impl<T> ByMinAge<T> { impl<T> OverAge<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,
{ {
let f = MIN_AGE_FILTERS; let f = OVER_AGE_FILTERS;
let n = MIN_AGE_NAMES; let n = OVER_AGE_NAMES;
Self { Self {
_1d: create(f._1d.clone(), n._1d.id), _1d: create(f._1d.clone(), n._1d.id),
_1w: create(f._1w.clone(), n._1w.id), _1w: create(f._1w.clone(), n._1w.id),
@@ -135,8 +135,8 @@ impl<T> ByMinAge<T> {
where where
F: FnMut(Filter, &'static str) -> Result<T, E>, F: FnMut(Filter, &'static str) -> Result<T, E>,
{ {
let f = MIN_AGE_FILTERS; let f = OVER_AGE_FILTERS;
let n = MIN_AGE_NAMES; let n = OVER_AGE_NAMES;
Ok(Self { Ok(Self {
_1d: create(f._1d.clone(), n._1d.id)?, _1d: create(f._1d.clone(), n._1d.id)?,
_1w: create(f._1w.clone(), n._1w.id)?, _1w: create(f._1w.clone(), n._1w.id)?,

View File

@@ -5,8 +5,8 @@ use serde::Serialize;
use super::{AmountFilter, CohortName, Filter}; use super::{AmountFilter, CohortName, Filter};
/// Greater-or-equal amount thresholds /// Over-amount thresholds
pub const GE_AMOUNT_THRESHOLDS: ByGreatEqualAmount<Sats> = ByGreatEqualAmount { pub const OVER_AMOUNT_THRESHOLDS: OverAmount<Sats> = OverAmount {
_1sat: Sats::_1, _1sat: Sats::_1,
_10sats: Sats::_10, _10sats: Sats::_10,
_100sats: Sats::_100, _100sats: Sats::_100,
@@ -22,8 +22,8 @@ pub const GE_AMOUNT_THRESHOLDS: ByGreatEqualAmount<Sats> = ByGreatEqualAmount {
_10k_btc: Sats::_10K_BTC, _10k_btc: Sats::_10K_BTC,
}; };
/// Greater-or-equal amount names /// Over-amount names
pub const GE_AMOUNT_NAMES: ByGreatEqualAmount<CohortName> = ByGreatEqualAmount { pub const OVER_AMOUNT_NAMES: OverAmount<CohortName> = OverAmount {
_1sat: CohortName::new("over_1sat", "1+ sats", "Over 1 Sat"), _1sat: CohortName::new("over_1sat", "1+ sats", "Over 1 Sat"),
_10sats: CohortName::new("over_10sats", "10+ sats", "Over 10 Sats"), _10sats: CohortName::new("over_10sats", "10+ sats", "Over 10 Sats"),
_100sats: CohortName::new("over_100sats", "100+ sats", "Over 100 Sats"), _100sats: CohortName::new("over_100sats", "100+ sats", "Over 100 Sats"),
@@ -39,27 +39,27 @@ pub const GE_AMOUNT_NAMES: ByGreatEqualAmount<CohortName> = ByGreatEqualAmount {
_10k_btc: CohortName::new("over_10k_btc", "10k+ BTC", "Over 10K BTC"), _10k_btc: CohortName::new("over_10k_btc", "10k+ BTC", "Over 10K BTC"),
}; };
/// Greater-or-equal amount filters /// Over-amount filters
pub const GE_AMOUNT_FILTERS: ByGreatEqualAmount<Filter> = ByGreatEqualAmount { pub const OVER_AMOUNT_FILTERS: OverAmount<Filter> = OverAmount {
_1sat: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._1sat)), _1sat: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1sat)),
_10sats: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._10sats)), _10sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10sats)),
_100sats: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._100sats)), _100sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._100sats)),
_1k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._1k_sats)), _1k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1k_sats)),
_10k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._10k_sats)), _10k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10k_sats)),
_100k_sats: Filter::Amount(AmountFilter::GreaterOrEqual( _100k_sats: Filter::Amount(AmountFilter::GreaterOrEqual(
GE_AMOUNT_THRESHOLDS._100k_sats, OVER_AMOUNT_THRESHOLDS._100k_sats,
)), )),
_1m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._1m_sats)), _1m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1m_sats)),
_10m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._10m_sats)), _10m_sats: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10m_sats)),
_1btc: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._1btc)), _1btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1btc)),
_10btc: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._10btc)), _10btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10btc)),
_100btc: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._100btc)), _100btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._100btc)),
_1k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._1k_btc)), _1k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._1k_btc)),
_10k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(GE_AMOUNT_THRESHOLDS._10k_btc)), _10k_btc: Filter::Amount(AmountFilter::GreaterOrEqual(OVER_AMOUNT_THRESHOLDS._10k_btc)),
}; };
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByGreatEqualAmount<T> { pub struct OverAmount<T> {
pub _1sat: T, pub _1sat: T,
pub _10sats: T, pub _10sats: T,
pub _100sats: T, pub _100sats: T,
@@ -75,19 +75,19 @@ pub struct ByGreatEqualAmount<T> {
pub _10k_btc: T, pub _10k_btc: T,
} }
impl ByGreatEqualAmount<CohortName> { impl OverAmount<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&GE_AMOUNT_NAMES &OVER_AMOUNT_NAMES
} }
} }
impl<T> ByGreatEqualAmount<T> { impl<T> OverAmount<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,
{ {
let f = GE_AMOUNT_FILTERS; let f = OVER_AMOUNT_FILTERS;
let n = GE_AMOUNT_NAMES; let n = OVER_AMOUNT_NAMES;
Self { Self {
_1sat: create(f._1sat.clone(), n._1sat.id), _1sat: create(f._1sat.clone(), n._1sat.id),
_10sats: create(f._10sats.clone(), n._10sats.id), _10sats: create(f._10sats.clone(), n._10sats.id),
@@ -109,8 +109,8 @@ impl<T> ByGreatEqualAmount<T> {
where where
F: FnMut(Filter, &'static str) -> Result<T, E>, F: FnMut(Filter, &'static str) -> Result<T, E>,
{ {
let f = GE_AMOUNT_FILTERS; let f = OVER_AMOUNT_FILTERS;
let n = GE_AMOUNT_NAMES; let n = OVER_AMOUNT_NAMES;
Ok(Self { Ok(Self {
_1sat: create(f._1sat.clone(), n._1sat.id)?, _1sat: create(f._1sat.clone(), n._1sat.id)?,
_10sats: create(f._10sats.clone(), n._10sats.id)?, _10sats: create(f._10sats.clone(), n._10sats.id)?,

View File

@@ -5,7 +5,7 @@ use serde::Serialize;
use super::CohortName; use super::CohortName;
/// "At least X% profit" threshold names (15 thresholds). /// "At least X% profit" threshold names (15 thresholds).
pub const PROFIT_NAMES: ByProfit<CohortName> = ByProfit { pub const PROFIT_NAMES: Profit<CohortName> = Profit {
breakeven: CohortName::new("utxos_in_profit", "≥0%", "In Profit (Breakeven+)"), breakeven: CohortName::new("utxos_in_profit", "≥0%", "In Profit (Breakeven+)"),
_10pct: CohortName::new("utxos_over_10pct_in_profit", "≥10%", "10%+ Profit"), _10pct: CohortName::new("utxos_over_10pct_in_profit", "≥10%", "10%+ Profit"),
_20pct: CohortName::new("utxos_over_20pct_in_profit", "≥20%", "20%+ Profit"), _20pct: CohortName::new("utxos_over_20pct_in_profit", "≥20%", "20%+ Profit"),
@@ -20,13 +20,12 @@ pub const PROFIT_NAMES: ByProfit<CohortName> = ByProfit {
_200pct: CohortName::new("utxos_over_200pct_in_profit", "≥200%", "200%+ Profit"), _200pct: CohortName::new("utxos_over_200pct_in_profit", "≥200%", "200%+ Profit"),
_300pct: CohortName::new("utxos_over_300pct_in_profit", "≥300%", "300%+ Profit"), _300pct: CohortName::new("utxos_over_300pct_in_profit", "≥300%", "300%+ Profit"),
_500pct: CohortName::new("utxos_over_500pct_in_profit", "≥500%", "500%+ Profit"), _500pct: CohortName::new("utxos_over_500pct_in_profit", "≥500%", "500%+ Profit"),
_1000pct: CohortName::new("utxos_over_1000pct_in_profit", "≥1000%", "1000%+ Profit"),
}; };
/// Number of profit thresholds. /// Number of profit thresholds.
pub const PROFIT_COUNT: usize = 15; pub const PROFIT_COUNT: usize = 14;
impl ByProfit<CohortName> { impl Profit<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&PROFIT_NAMES &PROFIT_NAMES
} }
@@ -36,7 +35,7 @@ impl ByProfit<CohortName> {
/// ///
/// Each is a prefix sum over the profitability ranges, from most profitable down. /// Each is a prefix sum over the profitability ranges, from most profitable down.
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByProfit<T> { pub struct Profit<T> {
pub breakeven: T, pub breakeven: T,
pub _10pct: T, pub _10pct: T,
pub _20pct: T, pub _20pct: T,
@@ -51,10 +50,9 @@ pub struct ByProfit<T> {
pub _200pct: T, pub _200pct: T,
pub _300pct: T, pub _300pct: T,
pub _500pct: T, pub _500pct: T,
pub _1000pct: T,
} }
impl<T> ByProfit<T> { impl<T> Profit<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(&'static str) -> T, F: FnMut(&'static str) -> T,
@@ -75,7 +73,6 @@ impl<T> ByProfit<T> {
_200pct: create(n._200pct.id), _200pct: create(n._200pct.id),
_300pct: create(n._300pct.id), _300pct: create(n._300pct.id),
_500pct: create(n._500pct.id), _500pct: create(n._500pct.id),
_1000pct: create(n._1000pct.id),
} }
} }
@@ -99,7 +96,6 @@ impl<T> ByProfit<T> {
_200pct: create(n._200pct.id)?, _200pct: create(n._200pct.id)?,
_300pct: create(n._300pct.id)?, _300pct: create(n._300pct.id)?,
_500pct: create(n._500pct.id)?, _500pct: create(n._500pct.id)?,
_1000pct: create(n._1000pct.id)?,
}) })
} }
@@ -119,7 +115,6 @@ impl<T> ByProfit<T> {
&self._200pct, &self._200pct,
&self._300pct, &self._300pct,
&self._500pct, &self._500pct,
&self._1000pct,
] ]
.into_iter() .into_iter()
} }
@@ -140,7 +135,6 @@ impl<T> ByProfit<T> {
&mut self._200pct, &mut self._200pct,
&mut self._300pct, &mut self._300pct,
&mut self._500pct, &mut self._500pct,
&mut self._1000pct,
] ]
.into_iter() .into_iter()
} }
@@ -164,7 +158,6 @@ impl<T> ByProfit<T> {
&mut self._200pct, &mut self._200pct,
&mut self._300pct, &mut self._300pct,
&mut self._500pct, &mut self._500pct,
&mut self._1000pct,
] ]
.into_par_iter() .into_par_iter()
} }
@@ -186,7 +179,6 @@ impl<T> ByProfit<T> {
&mut self._200pct, &mut self._200pct,
&mut self._300pct, &mut self._300pct,
&mut self._500pct, &mut self._500pct,
&mut self._1000pct,
] ]
} }
} }

View File

@@ -82,7 +82,7 @@ pub fn compute_profitability_boundaries(spot: Cents) -> [Cents; PROFITABILITY_BO
} }
/// Profitability range names (25 ranges, from most profitable to most in loss) /// Profitability range names (25 ranges, from most profitable to most in loss)
pub const PROFITABILITY_RANGE_NAMES: ByProfitabilityRange<CohortName> = ByProfitabilityRange { pub const PROFITABILITY_RANGE_NAMES: ProfitabilityRange<CohortName> = ProfitabilityRange {
over_1000pct_in_profit: CohortName::new("utxos_over_1000pct_in_profit", ">1000%", "Over 1000% Profit"), over_1000pct_in_profit: CohortName::new("utxos_over_1000pct_in_profit", ">1000%", "Over 1000% Profit"),
_500pct_to_1000pct_in_profit: CohortName::new("utxos_500pct_to_1000pct_in_profit", "500-1000%", "500-1000% Profit"), _500pct_to_1000pct_in_profit: CohortName::new("utxos_500pct_to_1000pct_in_profit", "500-1000%", "500-1000% Profit"),
_300pct_to_500pct_in_profit: CohortName::new("utxos_300pct_to_500pct_in_profit", "300-500%", "300-500% Profit"), _300pct_to_500pct_in_profit: CohortName::new("utxos_300pct_to_500pct_in_profit", "300-500%", "300-500% Profit"),
@@ -110,7 +110,7 @@ pub const PROFITABILITY_RANGE_NAMES: ByProfitabilityRange<CohortName> = ByProfit
_90pct_to_100pct_in_loss: CohortName::new("utxos_90pct_to_100pct_in_loss", "90-100%L", "90-100% Loss"), _90pct_to_100pct_in_loss: CohortName::new("utxos_90pct_to_100pct_in_loss", "90-100%L", "90-100% Loss"),
}; };
impl ByProfitabilityRange<CohortName> { impl ProfitabilityRange<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&PROFITABILITY_RANGE_NAMES &PROFITABILITY_RANGE_NAMES
} }
@@ -121,7 +121,7 @@ impl ByProfitabilityRange<CohortName> {
/// During the k-way merge (ascending price order), the cursor starts at bucket 0 /// During the k-way merge (ascending price order), the cursor starts at bucket 0
/// (over_1000pct_in_profit, lowest cost basis) and advances as price crosses each boundary. /// (over_1000pct_in_profit, lowest cost basis) and advances as price crosses each boundary.
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByProfitabilityRange<T> { pub struct ProfitabilityRange<T> {
pub over_1000pct_in_profit: T, pub over_1000pct_in_profit: T,
pub _500pct_to_1000pct_in_profit: T, pub _500pct_to_1000pct_in_profit: T,
pub _300pct_to_500pct_in_profit: T, pub _300pct_to_500pct_in_profit: T,
@@ -152,7 +152,7 @@ pub struct ByProfitabilityRange<T> {
/// Number of profitability range buckets. /// Number of profitability range buckets.
pub const PROFITABILITY_RANGE_COUNT: usize = 25; pub const PROFITABILITY_RANGE_COUNT: usize = 25;
impl<T> ByProfitabilityRange<T> { impl<T> ProfitabilityRange<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(&'static str) -> T, F: FnMut(&'static str) -> T,

View File

@@ -8,7 +8,7 @@ use serde::Serialize;
use super::{CohortName, Filter}; use super::{CohortName, Filter};
/// Spendable type values /// Spendable type values
pub const SPENDABLE_TYPE_VALUES: BySpendableType<OutputType> = BySpendableType { pub const SPENDABLE_TYPE_VALUES: SpendableType<OutputType> = SpendableType {
p2pk65: OutputType::P2PK65, p2pk65: OutputType::P2PK65,
p2pk33: OutputType::P2PK33, p2pk33: OutputType::P2PK33,
p2pkh: OutputType::P2PKH, p2pkh: OutputType::P2PKH,
@@ -23,7 +23,7 @@ pub const SPENDABLE_TYPE_VALUES: BySpendableType<OutputType> = BySpendableType {
}; };
/// Spendable type filters /// Spendable type filters
pub const SPENDABLE_TYPE_FILTERS: BySpendableType<Filter> = BySpendableType { pub const SPENDABLE_TYPE_FILTERS: SpendableType<Filter> = SpendableType {
p2pk65: Filter::Type(SPENDABLE_TYPE_VALUES.p2pk65), p2pk65: Filter::Type(SPENDABLE_TYPE_VALUES.p2pk65),
p2pk33: Filter::Type(SPENDABLE_TYPE_VALUES.p2pk33), p2pk33: Filter::Type(SPENDABLE_TYPE_VALUES.p2pk33),
p2pkh: Filter::Type(SPENDABLE_TYPE_VALUES.p2pkh), p2pkh: Filter::Type(SPENDABLE_TYPE_VALUES.p2pkh),
@@ -38,7 +38,7 @@ pub const SPENDABLE_TYPE_FILTERS: BySpendableType<Filter> = BySpendableType {
}; };
/// Spendable type names /// Spendable type names
pub const SPENDABLE_TYPE_NAMES: BySpendableType<CohortName> = BySpendableType { pub const SPENDABLE_TYPE_NAMES: SpendableType<CohortName> = SpendableType {
p2pk65: CohortName::new("p2pk65", "P2PK65", "Pay to Public Key (65 bytes)"), p2pk65: CohortName::new("p2pk65", "P2PK65", "Pay to Public Key (65 bytes)"),
p2pk33: CohortName::new("p2pk33", "P2PK33", "Pay to Public Key (33 bytes)"), p2pk33: CohortName::new("p2pk33", "P2PK33", "Pay to Public Key (33 bytes)"),
p2pkh: CohortName::new("p2pkh", "P2PKH", "Pay to Public Key Hash"), p2pkh: CohortName::new("p2pkh", "P2PKH", "Pay to Public Key Hash"),
@@ -53,7 +53,7 @@ pub const SPENDABLE_TYPE_NAMES: BySpendableType<CohortName> = BySpendableType {
}; };
#[derive(Default, Clone, Debug, Traversable, Serialize)] #[derive(Default, Clone, Debug, Traversable, Serialize)]
pub struct BySpendableType<T> { pub struct SpendableType<T> {
pub p2pk65: T, pub p2pk65: T,
pub p2pk33: T, pub p2pk33: T,
pub p2pkh: T, pub p2pkh: T,
@@ -67,13 +67,13 @@ pub struct BySpendableType<T> {
pub empty: T, pub empty: T,
} }
impl BySpendableType<CohortName> { impl SpendableType<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&SPENDABLE_TYPE_NAMES &SPENDABLE_TYPE_NAMES
} }
} }
impl<T> BySpendableType<T> { impl<T> SpendableType<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,
@@ -222,7 +222,7 @@ impl<T> BySpendableType<T> {
} }
} }
impl<T> Add for BySpendableType<T> impl<T> Add for SpendableType<T>
where where
T: Add<Output = T>, T: Add<Output = T>,
{ {
@@ -244,7 +244,7 @@ where
} }
} }
impl<T> AddAssign for BySpendableType<T> impl<T> AddAssign for SpendableType<T>
where where
T: AddAssign, T: AddAssign,
{ {

View File

@@ -8,8 +8,8 @@ use super::{
HOURS_12Y, HOURS_15Y, TimeFilter, HOURS_12Y, HOURS_15Y, TimeFilter,
}; };
/// Max age thresholds in hours /// Under-age thresholds in hours
pub const MAX_AGE_HOURS: ByMaxAge<usize> = ByMaxAge { pub const UNDER_AGE_HOURS: UnderAge<usize> = UnderAge {
_1w: HOURS_1W, _1w: HOURS_1W,
_1m: HOURS_1M, _1m: HOURS_1M,
_2m: HOURS_2M, _2m: HOURS_2M,
@@ -30,30 +30,30 @@ pub const MAX_AGE_HOURS: ByMaxAge<usize> = ByMaxAge {
_15y: HOURS_15Y, _15y: HOURS_15Y,
}; };
/// Max age filters (LowerThan threshold in hours) /// Under-age filters (LowerThan threshold in hours)
pub const MAX_AGE_FILTERS: ByMaxAge<Filter> = ByMaxAge { pub const UNDER_AGE_FILTERS: UnderAge<Filter> = UnderAge {
_1w: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._1w)), _1w: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._1w)),
_1m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._1m)), _1m: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._1m)),
_2m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._2m)), _2m: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._2m)),
_3m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._3m)), _3m: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._3m)),
_4m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._4m)), _4m: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._4m)),
_5m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._5m)), _5m: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._5m)),
_6m: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._6m)), _6m: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._6m)),
_1y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._1y)), _1y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._1y)),
_2y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._2y)), _2y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._2y)),
_3y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._3y)), _3y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._3y)),
_4y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._4y)), _4y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._4y)),
_5y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._5y)), _5y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._5y)),
_6y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._6y)), _6y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._6y)),
_7y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._7y)), _7y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._7y)),
_8y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._8y)), _8y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._8y)),
_10y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._10y)), _10y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._10y)),
_12y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._12y)), _12y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._12y)),
_15y: Filter::Time(TimeFilter::LowerThan(MAX_AGE_HOURS._15y)), _15y: Filter::Time(TimeFilter::LowerThan(UNDER_AGE_HOURS._15y)),
}; };
/// Max age names /// Under-age names
pub const MAX_AGE_NAMES: ByMaxAge<CohortName> = ByMaxAge { pub const UNDER_AGE_NAMES: UnderAge<CohortName> = UnderAge {
_1w: CohortName::new("under_1w_old", "<1w", "Under 1 Week Old"), _1w: CohortName::new("under_1w_old", "<1w", "Under 1 Week Old"),
_1m: CohortName::new("under_1m_old", "<1m", "Under 1 Month Old"), _1m: CohortName::new("under_1m_old", "<1m", "Under 1 Month Old"),
_2m: CohortName::new("under_2m_old", "<2m", "Under 2 Months Old"), _2m: CohortName::new("under_2m_old", "<2m", "Under 2 Months Old"),
@@ -75,7 +75,7 @@ pub const MAX_AGE_NAMES: ByMaxAge<CohortName> = ByMaxAge {
}; };
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByMaxAge<T> { pub struct UnderAge<T> {
pub _1w: T, pub _1w: T,
pub _1m: T, pub _1m: T,
pub _2m: T, pub _2m: T,
@@ -96,19 +96,19 @@ pub struct ByMaxAge<T> {
pub _15y: T, pub _15y: T,
} }
impl ByMaxAge<CohortName> { impl UnderAge<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&MAX_AGE_NAMES &UNDER_AGE_NAMES
} }
} }
impl<T> ByMaxAge<T> { impl<T> UnderAge<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,
{ {
let f = MAX_AGE_FILTERS; let f = UNDER_AGE_FILTERS;
let n = MAX_AGE_NAMES; let n = UNDER_AGE_NAMES;
Self { Self {
_1w: create(f._1w.clone(), n._1w.id), _1w: create(f._1w.clone(), n._1w.id),
_1m: create(f._1m.clone(), n._1m.id), _1m: create(f._1m.clone(), n._1m.id),
@@ -135,8 +135,8 @@ impl<T> ByMaxAge<T> {
where where
F: FnMut(Filter, &'static str) -> Result<T, E>, F: FnMut(Filter, &'static str) -> Result<T, E>,
{ {
let f = MAX_AGE_FILTERS; let f = UNDER_AGE_FILTERS;
let n = MAX_AGE_NAMES; let n = UNDER_AGE_NAMES;
Ok(Self { Ok(Self {
_1w: create(f._1w.clone(), n._1w.id)?, _1w: create(f._1w.clone(), n._1w.id)?,
_1m: create(f._1m.clone(), n._1m.id)?, _1m: create(f._1m.clone(), n._1m.id)?,

View File

@@ -5,8 +5,8 @@ use serde::Serialize;
use super::{AmountFilter, CohortName, Filter}; use super::{AmountFilter, CohortName, Filter};
/// Lower-than amount thresholds /// Under-amount thresholds
pub const LT_AMOUNT_THRESHOLDS: ByLowerThanAmount<Sats> = ByLowerThanAmount { pub const UNDER_AMOUNT_THRESHOLDS: UnderAmount<Sats> = UnderAmount {
_10sats: Sats::_10, _10sats: Sats::_10,
_100sats: Sats::_100, _100sats: Sats::_100,
_1k_sats: Sats::_1K, _1k_sats: Sats::_1K,
@@ -22,8 +22,8 @@ pub const LT_AMOUNT_THRESHOLDS: ByLowerThanAmount<Sats> = ByLowerThanAmount {
_100k_btc: Sats::_100K_BTC, _100k_btc: Sats::_100K_BTC,
}; };
/// Lower-than amount names /// Under-amount names
pub const LT_AMOUNT_NAMES: ByLowerThanAmount<CohortName> = ByLowerThanAmount { pub const UNDER_AMOUNT_NAMES: UnderAmount<CohortName> = UnderAmount {
_10sats: CohortName::new("under_10sats", "<10 sats", "Under 10 Sats"), _10sats: CohortName::new("under_10sats", "<10 sats", "Under 10 Sats"),
_100sats: CohortName::new("under_100sats", "<100 sats", "Under 100 Sats"), _100sats: CohortName::new("under_100sats", "<100 sats", "Under 100 Sats"),
_1k_sats: CohortName::new("under_1k_sats", "<1k sats", "Under 1K Sats"), _1k_sats: CohortName::new("under_1k_sats", "<1k sats", "Under 1K Sats"),
@@ -39,25 +39,25 @@ pub const LT_AMOUNT_NAMES: ByLowerThanAmount<CohortName> = ByLowerThanAmount {
_100k_btc: CohortName::new("under_100k_btc", "<100k BTC", "Under 100K BTC"), _100k_btc: CohortName::new("under_100k_btc", "<100k BTC", "Under 100K BTC"),
}; };
/// Lower-than amount filters /// Under-amount filters
pub const LT_AMOUNT_FILTERS: ByLowerThanAmount<Filter> = ByLowerThanAmount { pub const UNDER_AMOUNT_FILTERS: UnderAmount<Filter> = UnderAmount {
_10sats: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._10sats)), _10sats: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._10sats)),
_100sats: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._100sats)), _100sats: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._100sats)),
_1k_sats: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._1k_sats)), _1k_sats: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._1k_sats)),
_10k_sats: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._10k_sats)), _10k_sats: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._10k_sats)),
_100k_sats: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._100k_sats)), _100k_sats: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._100k_sats)),
_1m_sats: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._1m_sats)), _1m_sats: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._1m_sats)),
_10m_sats: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._10m_sats)), _10m_sats: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._10m_sats)),
_1btc: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._1btc)), _1btc: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._1btc)),
_10btc: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._10btc)), _10btc: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._10btc)),
_100btc: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._100btc)), _100btc: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._100btc)),
_1k_btc: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._1k_btc)), _1k_btc: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._1k_btc)),
_10k_btc: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._10k_btc)), _10k_btc: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._10k_btc)),
_100k_btc: Filter::Amount(AmountFilter::LowerThan(LT_AMOUNT_THRESHOLDS._100k_btc)), _100k_btc: Filter::Amount(AmountFilter::LowerThan(UNDER_AMOUNT_THRESHOLDS._100k_btc)),
}; };
#[derive(Default, Clone, Traversable, Serialize)] #[derive(Default, Clone, Traversable, Serialize)]
pub struct ByLowerThanAmount<T> { pub struct UnderAmount<T> {
pub _10sats: T, pub _10sats: T,
pub _100sats: T, pub _100sats: T,
pub _1k_sats: T, pub _1k_sats: T,
@@ -73,19 +73,19 @@ pub struct ByLowerThanAmount<T> {
pub _100k_btc: T, pub _100k_btc: T,
} }
impl ByLowerThanAmount<CohortName> { impl UnderAmount<CohortName> {
pub const fn names() -> &'static Self { pub const fn names() -> &'static Self {
&LT_AMOUNT_NAMES &UNDER_AMOUNT_NAMES
} }
} }
impl<T> ByLowerThanAmount<T> { impl<T> UnderAmount<T> {
pub fn new<F>(mut create: F) -> Self pub fn new<F>(mut create: F) -> Self
where where
F: FnMut(Filter, &'static str) -> T, F: FnMut(Filter, &'static str) -> T,
{ {
let f = LT_AMOUNT_FILTERS; let f = UNDER_AMOUNT_FILTERS;
let n = LT_AMOUNT_NAMES; let n = UNDER_AMOUNT_NAMES;
Self { Self {
_10sats: create(f._10sats.clone(), n._10sats.id), _10sats: create(f._10sats.clone(), n._10sats.id),
_100sats: create(f._100sats.clone(), n._100sats.id), _100sats: create(f._100sats.clone(), n._100sats.id),
@@ -107,8 +107,8 @@ impl<T> ByLowerThanAmount<T> {
where where
F: FnMut(Filter, &'static str) -> Result<T, E>, F: FnMut(Filter, &'static str) -> Result<T, E>,
{ {
let f = LT_AMOUNT_FILTERS; let f = UNDER_AMOUNT_FILTERS;
let n = LT_AMOUNT_NAMES; let n = UNDER_AMOUNT_NAMES;
Ok(Self { Ok(Self {
_10sats: create(f._10sats.clone(), n._10sats.id)?, _10sats: create(f._10sats.clone(), n._10sats.id)?,
_100sats: create(f._100sats.clone(), n._100sats.id)?, _100sats: create(f._100sats.clone(), n._100sats.id)?,

View File

@@ -3,17 +3,17 @@ use std::ops::{Add, AddAssign};
use brk_traversable::Traversable; use brk_traversable::Traversable;
#[derive(Default, Clone, Debug, Traversable)] #[derive(Default, Clone, Debug, Traversable)]
pub struct ByUnspendableType<T> { pub struct UnspendableType<T> {
pub opreturn: T, pub opreturn: T,
} }
impl<T> ByUnspendableType<T> { impl<T> UnspendableType<T> {
pub fn as_vec(&self) -> [&T; 1] { pub fn as_vec(&self) -> [&T; 1] {
[&self.opreturn] [&self.opreturn]
} }
} }
impl<T> Add for ByUnspendableType<T> impl<T> Add for UnspendableType<T>
where where
T: Add<Output = T>, T: Add<Output = T>,
{ {
@@ -25,7 +25,7 @@ where
} }
} }
impl<T> AddAssign for ByUnspendableType<T> impl<T> AddAssign for UnspendableType<T>
where where
T: AddAssign, T: AddAssign,
{ {

View File

@@ -2,23 +2,23 @@ use brk_traversable::Traversable;
use rayon::prelude::*; use rayon::prelude::*;
use crate::{ use crate::{
ByAgeRange, ByAmountRange, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, ByMaxAge, ByMinAge, AgeRange, AmountRange, ByEpoch, OverAmount, UnderAmount, UnderAge, OverAge,
ByClass, BySpendableType, ByTerm, Filter, Class, SpendableType, ByTerm, Filter,
}; };
#[derive(Default, Clone, Traversable)] #[derive(Default, Clone, Traversable)]
pub struct UTXOGroups<T> { pub struct UTXOGroups<T> {
pub all: T, pub all: T,
pub age_range: ByAgeRange<T>, pub age_range: AgeRange<T>,
pub epoch: ByEpoch<T>, pub epoch: ByEpoch<T>,
pub class: ByClass<T>, pub class: Class<T>,
pub min_age: ByMinAge<T>, pub over_age: OverAge<T>,
pub ge_amount: ByGreatEqualAmount<T>, pub over_amount: OverAmount<T>,
pub amount_range: ByAmountRange<T>, pub amount_range: AmountRange<T>,
pub term: ByTerm<T>, pub term: ByTerm<T>,
pub type_: BySpendableType<T>, pub type_: SpendableType<T>,
pub max_age: ByMaxAge<T>, pub under_age: UnderAge<T>,
pub lt_amount: ByLowerThanAmount<T>, pub under_amount: UnderAmount<T>,
} }
impl<T> UTXOGroups<T> { impl<T> UTXOGroups<T> {
@@ -28,16 +28,16 @@ impl<T> UTXOGroups<T> {
{ {
Self { Self {
all: create(Filter::All, ""), all: create(Filter::All, ""),
age_range: ByAgeRange::new(&mut create), age_range: AgeRange::new(&mut create),
epoch: ByEpoch::new(&mut create), epoch: ByEpoch::new(&mut create),
class: ByClass::new(&mut create), class: Class::new(&mut create),
min_age: ByMinAge::new(&mut create), over_age: OverAge::new(&mut create),
ge_amount: ByGreatEqualAmount::new(&mut create), over_amount: OverAmount::new(&mut create),
amount_range: ByAmountRange::new(&mut create), amount_range: AmountRange::new(&mut create),
term: ByTerm::new(&mut create), term: ByTerm::new(&mut create),
type_: BySpendableType::new(&mut create), type_: SpendableType::new(&mut create),
max_age: ByMaxAge::new(&mut create), under_age: UnderAge::new(&mut create),
lt_amount: ByLowerThanAmount::new(&mut create), under_amount: UnderAmount::new(&mut create),
} }
} }
@@ -45,14 +45,14 @@ impl<T> UTXOGroups<T> {
[&self.all] [&self.all]
.into_iter() .into_iter()
.chain(self.term.iter()) .chain(self.term.iter())
.chain(self.max_age.iter()) .chain(self.under_age.iter())
.chain(self.min_age.iter()) .chain(self.over_age.iter())
.chain(self.ge_amount.iter()) .chain(self.over_amount.iter())
.chain(self.age_range.iter()) .chain(self.age_range.iter())
.chain(self.epoch.iter()) .chain(self.epoch.iter())
.chain(self.class.iter()) .chain(self.class.iter())
.chain(self.amount_range.iter()) .chain(self.amount_range.iter())
.chain(self.lt_amount.iter()) .chain(self.under_amount.iter())
.chain(self.type_.iter()) .chain(self.type_.iter())
} }
@@ -60,14 +60,14 @@ impl<T> UTXOGroups<T> {
[&mut self.all] [&mut self.all]
.into_iter() .into_iter()
.chain(self.term.iter_mut()) .chain(self.term.iter_mut())
.chain(self.max_age.iter_mut()) .chain(self.under_age.iter_mut())
.chain(self.min_age.iter_mut()) .chain(self.over_age.iter_mut())
.chain(self.ge_amount.iter_mut()) .chain(self.over_amount.iter_mut())
.chain(self.age_range.iter_mut()) .chain(self.age_range.iter_mut())
.chain(self.epoch.iter_mut()) .chain(self.epoch.iter_mut())
.chain(self.class.iter_mut()) .chain(self.class.iter_mut())
.chain(self.amount_range.iter_mut()) .chain(self.amount_range.iter_mut())
.chain(self.lt_amount.iter_mut()) .chain(self.under_amount.iter_mut())
.chain(self.type_.iter_mut()) .chain(self.type_.iter_mut())
} }
@@ -78,14 +78,14 @@ impl<T> UTXOGroups<T> {
[&mut self.all] [&mut self.all]
.into_par_iter() .into_par_iter()
.chain(self.term.par_iter_mut()) .chain(self.term.par_iter_mut())
.chain(self.max_age.par_iter_mut()) .chain(self.under_age.par_iter_mut())
.chain(self.min_age.par_iter_mut()) .chain(self.over_age.par_iter_mut())
.chain(self.ge_amount.par_iter_mut()) .chain(self.over_amount.par_iter_mut())
.chain(self.age_range.par_iter_mut()) .chain(self.age_range.par_iter_mut())
.chain(self.epoch.par_iter_mut()) .chain(self.epoch.par_iter_mut())
.chain(self.class.par_iter_mut()) .chain(self.class.par_iter_mut())
.chain(self.amount_range.par_iter_mut()) .chain(self.amount_range.par_iter_mut())
.chain(self.lt_amount.par_iter_mut()) .chain(self.under_amount.par_iter_mut())
.chain(self.type_.par_iter_mut()) .chain(self.type_.par_iter_mut())
} }
@@ -123,10 +123,10 @@ impl<T> UTXOGroups<T> {
[&mut self.all] [&mut self.all]
.into_iter() .into_iter()
.chain(self.term.iter_mut()) .chain(self.term.iter_mut())
.chain(self.max_age.iter_mut()) .chain(self.under_age.iter_mut())
.chain(self.min_age.iter_mut()) .chain(self.over_age.iter_mut())
.chain(self.lt_amount.iter_mut()) .chain(self.under_amount.iter_mut())
.chain(self.ge_amount.iter_mut()) .chain(self.over_amount.iter_mut())
} }
/// Iterator over aggregate cohorts (all, sth, lth) that compute values from sub-cohorts. /// Iterator over aggregate cohorts (all, sth, lth) that compute values from sub-cohorts.

View File

@@ -1,7 +1,7 @@
use std::path::Path; use std::path::Path;
use brk_cohort::{ use brk_cohort::{
AddressGroups, ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount, Filter, Filtered, AddressGroups, AmountRange, OverAmount, UnderAmount, Filter, Filtered,
}; };
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
@@ -41,9 +41,9 @@ impl AddressCohorts {
let none = |f: Filter, name: &'static str| create(f, name, false); let none = |f: Filter, name: &'static str| create(f, name, false);
Ok(Self(AddressGroups { Ok(Self(AddressGroups {
amount_range: ByAmountRange::try_new(&full)?, amount_range: AmountRange::try_new(&full)?,
lt_amount: ByLowerThanAmount::try_new(&none)?, under_amount: UnderAmount::try_new(&none)?,
ge_amount: ByGreatEqualAmount::try_new(&none)?, over_amount: OverAmount::try_new(&none)?,
})) }))
} }
@@ -56,9 +56,9 @@ impl AddressCohorts {
let pairs: Vec<_> = self let pairs: Vec<_> = self
.0 .0
.ge_amount .over_amount
.iter_mut() .iter_mut()
.chain(self.0.lt_amount.iter_mut()) .chain(self.0.under_amount.iter_mut())
.map(|vecs| { .map(|vecs| {
let filter = vecs.filter().clone(); let filter = vecs.filter().clone();
( (

View File

@@ -1,8 +1,8 @@
use std::path::Path; use std::path::Path;
use brk_cohort::{ use brk_cohort::{
ByAgeRange, ByAmountRange, ByClass, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, ByMaxAge, AgeRange, AmountRange, Class, ByEpoch, OverAmount, UnderAmount, UnderAge,
ByMinAge, BySpendableType, CohortContext, Filter, Filtered, Term, OverAge, SpendableType, CohortContext, Filter, Filtered, Term,
}; };
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
@@ -39,18 +39,18 @@ pub struct UTXOCohorts<M: StorageMode = Rw> {
pub all: UTXOCohortVecs<AllCohortMetrics<M>>, pub all: UTXOCohortVecs<AllCohortMetrics<M>>,
pub sth: UTXOCohortVecs<ExtendedAdjustedCohortMetrics<M>>, pub sth: UTXOCohortVecs<ExtendedAdjustedCohortMetrics<M>>,
pub lth: UTXOCohortVecs<ExtendedCohortMetrics<M>>, pub lth: UTXOCohortVecs<ExtendedCohortMetrics<M>>,
pub age_range: ByAgeRange<UTXOCohortVecs<BasicCohortMetrics<M>>>, pub age_range: AgeRange<UTXOCohortVecs<BasicCohortMetrics<M>>>,
pub max_age: ByMaxAge<UTXOCohortVecs<CoreCohortMetrics<M>>>, pub under_age: UnderAge<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub min_age: ByMinAge<UTXOCohortVecs<CoreCohortMetrics<M>>>, pub over_age: OverAge<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub epoch: ByEpoch<UTXOCohortVecs<CoreCohortMetrics<M>>>, pub epoch: ByEpoch<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub class: ByClass<UTXOCohortVecs<CoreCohortMetrics<M>>>, pub class: Class<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub ge_amount: ByGreatEqualAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>, pub over_amount: OverAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub amount_range: ByAmountRange<UTXOCohortVecs<MinimalCohortMetrics<M>>>, pub amount_range: AmountRange<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub lt_amount: ByLowerThanAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>, pub under_amount: UnderAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
#[traversable(rename = "type")] #[traversable(rename = "type")]
pub type_: BySpendableType<UTXOCohortVecs<TypeCohortMetrics<M>>>, pub type_: SpendableType<UTXOCohortVecs<TypeCohortMetrics<M>>>,
pub profitability: ProfitabilityMetrics<M>, pub profitability: ProfitabilityMetrics<M>,
pub matured: ByAgeRange<AmountPerBlock<M>>, pub matured: AgeRange<AmountPerBlock<M>>,
#[traversable(skip)] #[traversable(skip)]
pub(super) fenwick: CostBasisFenwick, pub(super) fenwick: CostBasisFenwick,
/// Cached partition_point positions for tick_tock boundary searches. /// Cached partition_point positions for tick_tock boundary searches.
@@ -104,7 +104,7 @@ impl UTXOCohorts<Rw> {
)) ))
}; };
let age_range = ByAgeRange::try_new(&basic_separate)?; let age_range = AgeRange::try_new(&basic_separate)?;
let core_separate = let core_separate =
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<CoreCohortMetrics>> { |f: Filter, name: &'static str| -> Result<UTXOCohortVecs<CoreCohortMetrics>> {
@@ -124,7 +124,7 @@ impl UTXOCohorts<Rw> {
}; };
let epoch = ByEpoch::try_new(&core_separate)?; let epoch = ByEpoch::try_new(&core_separate)?;
let class = ByClass::try_new(&core_separate)?; let class = Class::try_new(&core_separate)?;
// Helper for separate cohorts with MinimalCohortMetrics + MinimalRealizedState // Helper for separate cohorts with MinimalCohortMetrics + MinimalRealizedState
let minimal_separate = let minimal_separate =
@@ -144,7 +144,7 @@ impl UTXOCohorts<Rw> {
)) ))
}; };
let amount_range = ByAmountRange::try_new(&minimal_separate)?; let amount_range = AmountRange::try_new(&minimal_separate)?;
let type_separate = let type_separate =
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<TypeCohortMetrics>> { |f: Filter, name: &'static str| -> Result<UTXOCohortVecs<TypeCohortMetrics>> {
@@ -163,7 +163,7 @@ impl UTXOCohorts<Rw> {
)) ))
}; };
let type_ = BySpendableType::try_new(&type_separate)?; let type_ = SpendableType::try_new(&type_separate)?;
// Phase 3: Import "all" cohort with pre-imported supply. // Phase 3: Import "all" cohort with pre-imported supply.
let all = UTXOCohortVecs::new( let all = UTXOCohortVecs::new(
@@ -221,11 +221,11 @@ impl UTXOCohorts<Rw> {
)) ))
}; };
// max_age: CoreCohortMetrics (no state, aggregates from age_range) // under_age: CoreCohortMetrics (no state, aggregates from age_range)
let max_age = ByMaxAge::try_new(&core_no_state)?; let under_age = UnderAge::try_new(&core_no_state)?;
// min_age: CoreCohortMetrics (no state, aggregates from age_range) // over_age: CoreCohortMetrics (no state, aggregates from age_range)
let min_age = ByMinAge::try_new(&core_no_state)?; let over_age = OverAge::try_new(&core_no_state)?;
let minimal_no_state = let minimal_no_state =
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<MinimalCohortMetrics>> { |f: Filter, name: &'static str| -> Result<UTXOCohortVecs<MinimalCohortMetrics>> {
@@ -243,10 +243,10 @@ impl UTXOCohorts<Rw> {
)) ))
}; };
let lt_amount = ByLowerThanAmount::try_new(&minimal_no_state)?; let under_amount = UnderAmount::try_new(&minimal_no_state)?;
let ge_amount = ByGreatEqualAmount::try_new(&minimal_no_state)?; let over_amount = OverAmount::try_new(&minimal_no_state)?;
let matured = ByAgeRange::try_new(&|_f: Filter, let matured = AgeRange::try_new(&|_f: Filter,
name: &'static str| name: &'static str|
-> Result<AmountPerBlock> { -> Result<AmountPerBlock> {
AmountPerBlock::forced_import(db, &format!("utxo_{name}_matured"), v, indexes) AmountPerBlock::forced_import(db, &format!("utxo_{name}_matured"), v, indexes)
@@ -259,12 +259,12 @@ impl UTXOCohorts<Rw> {
epoch, epoch,
class, class,
type_, type_,
max_age, under_age,
min_age, over_age,
age_range, age_range,
amount_range, amount_range,
lt_amount, under_amount,
ge_amount, over_amount,
profitability, profitability,
matured, matured,
fenwick: CostBasisFenwick::new(), fenwick: CostBasisFenwick::new(),
@@ -325,7 +325,7 @@ impl UTXOCohorts<Rw> {
pub(crate) fn push_maturation( pub(crate) fn push_maturation(
&mut self, &mut self,
height: Height, height: Height,
matured: &ByAgeRange<Sats>, matured: &AgeRange<Sats>,
) -> Result<()> { ) -> Result<()> {
for (v, &sats) in self.matured.iter_mut().zip(matured.iter()) { for (v, &sats) in self.matured.iter_mut().zip(matured.iter()) {
v.sats.height.truncate_push(height, sats)?; v.sats.height.truncate_push(height, sats)?;
@@ -398,11 +398,11 @@ impl UTXOCohorts<Rw> {
sth, sth,
lth, lth,
age_range, age_range,
max_age, under_age,
min_age, over_age,
ge_amount, over_amount,
amount_range, amount_range,
lt_amount, under_amount,
.. ..
} = self; } = self;
@@ -424,21 +424,21 @@ impl UTXOCohorts<Rw> {
lth.metrics.compute_base_from_others(si, &sources, exit) lth.metrics.compute_base_from_others(si, &sources, exit)
}), }),
Box::new(|| { Box::new(|| {
min_age.par_iter_mut().try_for_each(|vecs| { over_age.par_iter_mut().try_for_each(|vecs| {
let sources = filter_sources_from(ar.iter(), Some(&vecs.metrics.filter)); let sources = filter_sources_from(ar.iter(), Some(&vecs.metrics.filter));
vecs.metrics.compute_from_base_sources(si, &sources, exit) vecs.metrics.compute_from_base_sources(si, &sources, exit)
}) })
}), }),
Box::new(|| { Box::new(|| {
max_age.par_iter_mut().try_for_each(|vecs| { under_age.par_iter_mut().try_for_each(|vecs| {
let sources = filter_sources_from(ar.iter(), Some(&vecs.metrics.filter)); let sources = filter_sources_from(ar.iter(), Some(&vecs.metrics.filter));
vecs.metrics.compute_from_base_sources(si, &sources, exit) vecs.metrics.compute_from_base_sources(si, &sources, exit)
}) })
}), }),
Box::new(|| { Box::new(|| {
ge_amount over_amount
.par_iter_mut() .par_iter_mut()
.chain(lt_amount.par_iter_mut()) .chain(under_amount.par_iter_mut())
.try_for_each(|vecs| { .try_for_each(|vecs| {
let sources = let sources =
filter_minimal_sources_from(amr.iter(), Some(&vecs.metrics.filter)); filter_minimal_sources_from(amr.iter(), Some(&vecs.metrics.filter));
@@ -471,10 +471,10 @@ impl UTXOCohorts<Rw> {
all.push(&mut self.all); all.push(&mut self.all);
all.push(&mut self.sth); all.push(&mut self.sth);
all.push(&mut self.lth); all.push(&mut self.lth);
all.extend(self.max_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs)); all.extend(self.under_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
all.extend(self.min_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs)); all.extend(self.over_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
all.extend( all.extend(
self.ge_amount self.over_amount
.iter_mut() .iter_mut()
.map(|x| x as &mut dyn DynCohortVecs), .map(|x| x as &mut dyn DynCohortVecs),
); );
@@ -491,7 +491,7 @@ impl UTXOCohorts<Rw> {
.map(|x| x as &mut dyn DynCohortVecs), .map(|x| x as &mut dyn DynCohortVecs),
); );
all.extend( all.extend(
self.lt_amount self.under_amount
.iter_mut() .iter_mut()
.map(|x| x as &mut dyn DynCohortVecs), .map(|x| x as &mut dyn DynCohortVecs),
); );
@@ -563,11 +563,11 @@ impl UTXOCohorts<Rw> {
sth, sth,
lth, lth,
age_range, age_range,
max_age, under_age,
min_age, over_age,
ge_amount, over_amount,
amount_range, amount_range,
lt_amount, under_amount,
epoch, epoch,
class, class,
type_, type_,
@@ -610,19 +610,19 @@ impl UTXOCohorts<Rw> {
}) })
}), }),
Box::new(|| { Box::new(|| {
max_age.par_iter_mut().try_for_each(|v| { under_age.par_iter_mut().try_for_each(|v| {
v.metrics v.metrics
.compute_rest_part2(blocks, prices, starting_indexes, ss, exit) .compute_rest_part2(blocks, prices, starting_indexes, ss, exit)
}) })
}), }),
Box::new(|| { Box::new(|| {
min_age.par_iter_mut().try_for_each(|v| { over_age.par_iter_mut().try_for_each(|v| {
v.metrics v.metrics
.compute_rest_part2(blocks, prices, starting_indexes, ss, exit) .compute_rest_part2(blocks, prices, starting_indexes, ss, exit)
}) })
}), }),
Box::new(|| { Box::new(|| {
ge_amount over_amount
.par_iter_mut() .par_iter_mut()
.try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit)) .try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit))
}), }),
@@ -644,7 +644,7 @@ impl UTXOCohorts<Rw> {
.try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit)) .try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit))
}), }),
Box::new(|| { Box::new(|| {
lt_amount under_amount
.par_iter_mut() .par_iter_mut()
.try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit)) .try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit))
}), }),
@@ -674,13 +674,13 @@ impl UTXOCohorts<Rw> {
for v in self.age_range.iter_mut() { for v in self.age_range.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut()); vecs.extend(v.metrics.collect_all_vecs_mut());
} }
for v in self.max_age.iter_mut() { for v in self.under_age.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut()); vecs.extend(v.metrics.collect_all_vecs_mut());
} }
for v in self.min_age.iter_mut() { for v in self.over_age.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut()); vecs.extend(v.metrics.collect_all_vecs_mut());
} }
for v in self.ge_amount.iter_mut() { for v in self.over_amount.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut()); vecs.extend(v.metrics.collect_all_vecs_mut());
} }
for v in self.epoch.iter_mut() { for v in self.epoch.iter_mut() {
@@ -692,7 +692,7 @@ impl UTXOCohorts<Rw> {
for v in self.amount_range.iter_mut() { for v in self.amount_range.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut()); vecs.extend(v.metrics.collect_all_vecs_mut());
} }
for v in self.lt_amount.iter_mut() { for v in self.under_amount.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut()); vecs.extend(v.metrics.collect_all_vecs_mut());
} }
for v in self.type_.iter_mut() { for v in self.type_.iter_mut() {
@@ -764,10 +764,10 @@ impl UTXOCohorts<Rw> {
self.all.metrics.validate_computed_versions(base_version)?; self.all.metrics.validate_computed_versions(base_version)?;
self.sth.metrics.validate_computed_versions(base_version)?; self.sth.metrics.validate_computed_versions(base_version)?;
self.lth.metrics.validate_computed_versions(base_version)?; self.lth.metrics.validate_computed_versions(base_version)?;
for v in self.min_age.iter_mut() { for v in self.over_age.iter_mut() {
v.metrics.validate_computed_versions(base_version)?; v.metrics.validate_computed_versions(base_version)?;
} }
for v in self.max_age.iter_mut() { for v in self.under_age.iter_mut() {
v.metrics.validate_computed_versions(base_version)?; v.metrics.validate_computed_versions(base_version)?;
} }
Ok(()) Ok(())

View File

@@ -121,8 +121,8 @@ fn push_profitability(
bucket.truncate_push(height, Sats::from(sats), raw_usd_to_dollars(usd_raw))?; bucket.truncate_push(height, Sats::from(sats), raw_usd_to_dollars(usd_raw))?;
} }
// ByProfit: forward cumulative sum over ranges[0..15], pushed in reverse. // Profit: forward cumulative sum over ranges[0..15], pushed in reverse.
// profit[0] (breakeven) = sum(0..=14), ..., profit[14] (_1000pct) = ranges[0] // profit[0] (breakeven) = sum(0..=13), ..., profit[13] (_500pct) = ranges[0]
let profit_arr = metrics.profit.as_array_mut(); let profit_arr = metrics.profit.as_array_mut();
let mut cum_sats = 0u64; let mut cum_sats = 0u64;
let mut cum_usd = 0u128; let mut cum_usd = 0u128;
@@ -133,8 +133,8 @@ fn push_profitability(
.truncate_push(height, Sats::from(cum_sats), raw_usd_to_dollars(cum_usd))?; .truncate_push(height, Sats::from(cum_sats), raw_usd_to_dollars(cum_usd))?;
} }
// ByLoss: backward cumulative sum over ranges[15..25], pushed in reverse. // Loss: backward cumulative sum over ranges[15..25], pushed in reverse.
// loss[0] (breakeven) = sum(15..=24), ..., loss[9] (_90pct) = ranges[24] // loss[0] (breakeven) = sum(15..=24), ..., loss[8] (_80pct) = ranges[24]
let loss_arr = metrics.loss.as_array_mut(); let loss_arr = metrics.loss.as_array_mut();
let loss_count = loss_arr.len(); let loss_count = loss_arr.len();
cum_sats = 0; cum_sats = 0;

View File

@@ -1,4 +1,4 @@
use brk_cohort::{AGE_BOUNDARIES, ByAgeRange}; use brk_cohort::{AGE_BOUNDARIES, AgeRange};
use brk_types::{CostBasisSnapshot, ONE_HOUR_IN_SEC, Sats, Timestamp}; use brk_types::{CostBasisSnapshot, ONE_HOUR_IN_SEC, Sats, Timestamp};
use vecdb::{Rw, unlikely}; use vecdb::{Rw, unlikely};
@@ -22,9 +22,9 @@ impl UTXOCohorts<Rw> {
&mut self, &mut self,
chain_state: &[BlockState], chain_state: &[BlockState],
timestamp: Timestamp, timestamp: Timestamp,
) -> ByAgeRange<Sats> { ) -> AgeRange<Sats> {
if chain_state.is_empty() { if chain_state.is_empty() {
return ByAgeRange::default(); return AgeRange::default();
} }
let prev_timestamp = chain_state.last().unwrap().timestamp; let prev_timestamp = chain_state.last().unwrap().timestamp;
@@ -32,7 +32,7 @@ impl UTXOCohorts<Rw> {
// Skip if no time has passed // Skip if no time has passed
if elapsed == 0 { if elapsed == 0 {
return ByAgeRange::default(); return AgeRange::default();
} }
let mut matured = [Sats::ZERO; 21]; let mut matured = [Sats::ZERO; 21];
@@ -96,6 +96,6 @@ impl UTXOCohorts<Rw> {
} }
} }
ByAgeRange::from_array(matured) AgeRange::from_array(matured)
} }
} }

View File

@@ -62,7 +62,7 @@ impl CoreCohortMetrics {
vecs vecs
} }
/// Aggregate Core-tier fields from CohortMetricsBase sources (e.g. age_range → max_age/min_age). /// Aggregate Core-tier fields from CohortMetricsBase sources (e.g. age_range → under_age/over_age).
pub(crate) fn compute_from_base_sources<T: CohortMetricsBase>( pub(crate) fn compute_from_base_sources<T: CohortMetricsBase>(
&mut self, &mut self,
starting_indexes: &Indexes, starting_indexes: &Indexes,

View File

@@ -1,4 +1,4 @@
use brk_cohort::{ByLoss, ByProfit, ByProfitabilityRange}; use brk_cohort::{Loss, Profit, ProfitabilityRange};
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats, Version}; use brk_types::{Dollars, Height, Sats, Version};
@@ -66,9 +66,9 @@ impl ProfitabilityBucket {
/// All profitability metrics: 25 ranges + 15 profit thresholds + 10 loss thresholds. /// All profitability metrics: 25 ranges + 15 profit thresholds + 10 loss thresholds.
#[derive(Traversable)] #[derive(Traversable)]
pub struct ProfitabilityMetrics<M: StorageMode = Rw> { pub struct ProfitabilityMetrics<M: StorageMode = Rw> {
pub range: ByProfitabilityRange<ProfitabilityBucket<M>>, pub range: ProfitabilityRange<ProfitabilityBucket<M>>,
pub profit: ByProfit<ProfitabilityBucket<M>>, pub profit: Profit<ProfitabilityBucket<M>>,
pub loss: ByLoss<ProfitabilityBucket<M>>, pub loss: Loss<ProfitabilityBucket<M>>,
} }
impl<M: StorageMode> ProfitabilityMetrics<M> { impl<M: StorageMode> ProfitabilityMetrics<M> {
@@ -88,15 +88,15 @@ impl ProfitabilityMetrics {
version: Version, version: Version,
indexes: &indexes::Vecs, indexes: &indexes::Vecs,
) -> Result<Self> { ) -> Result<Self> {
let range = ByProfitabilityRange::try_new(|name| { let range = ProfitabilityRange::try_new(|name| {
ProfitabilityBucket::forced_import(db, name, version, indexes) ProfitabilityBucket::forced_import(db, name, version, indexes)
})?; })?;
let profit = ByProfit::try_new(|name| { let profit = Profit::try_new(|name| {
ProfitabilityBucket::forced_import(db, name, version, indexes) ProfitabilityBucket::forced_import(db, name, version, indexes)
})?; })?;
let loss = ByLoss::try_new(|name| { let loss = Loss::try_new(|name| {
ProfitabilityBucket::forced_import(db, name, version, indexes) ProfitabilityBucket::forced_import(db, name, version, indexes)
})?; })?;

View File

@@ -151,7 +151,7 @@ impl RealizedOps for MinimalRealizedState {
} }
/// Core realized state: extends Minimal with sent_in_profit/loss tracking. /// Core realized state: extends Minimal with sent_in_profit/loss tracking.
/// Used by CoreCohortMetrics cohorts (epoch, class, max_age, min_age — ~59 separate cohorts). /// Used by CoreCohortMetrics cohorts (epoch, class, under_age, over_age — ~59 separate cohorts).
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct CoreRealizedState { pub struct CoreRealizedState {
minimal: MinimalRealizedState, minimal: MinimalRealizedState,

View File

@@ -1,14 +1,14 @@
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use brk_cohort::{ByAmountRange, GroupedByType}; use brk_cohort::{AmountRange, ByType};
use brk_types::{OutputType, Sats, SupplyState}; use brk_types::{OutputType, Sats, SupplyState};
use vecdb::unlikely; use vecdb::unlikely;
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Transacted { pub struct Transacted {
pub spendable_supply: SupplyState, pub spendable_supply: SupplyState,
pub by_type: GroupedByType<SupplyState>, pub by_type: ByType<SupplyState>,
pub by_size_group: ByAmountRange<SupplyState>, pub by_size_group: AmountRange<SupplyState>,
} }
impl Transacted { impl Transacted {

View File

@@ -116,6 +116,24 @@ impl Query {
vec.last_json_value().ok_or(Error::NoData) vec.last_json_value().ok_or(Error::NoData)
} }
/// Returns the length (total data points) for a single metric.
pub fn len(&self, metric: &Metric, index: Index) -> Result<usize> {
let vec = self
.vecs()
.get(metric, index)
.ok_or_else(|| self.metric_not_found_error(metric))?;
Ok(vec.len())
}
/// Returns the version for a single metric.
pub fn version(&self, metric: &Metric, index: Index) -> Result<Version> {
let vec = self
.vecs()
.get(metric, index)
.ok_or_else(|| self.metric_not_found_error(metric))?;
Ok(vec.version())
}
/// Search for vecs matching the given metrics and index. /// Search for vecs matching the given metrics and index.
/// Returns error if no metrics requested or any requested metric is not found. /// Returns error if no metrics requested or any requested metric is not found.
pub fn search(&self, params: &MetricSelection) -> Result<Vec<&'static dyn AnyExportableVec>> { pub fn search(&self, params: &MetricSelection) -> Result<Vec<&'static dyn AnyExportableVec>> {
@@ -290,7 +308,7 @@ impl Query {
let indexes = index_to_vec.keys().copied().collect(); let indexes = index_to_vec.keys().copied().collect();
Some(MetricInfo { Some(MetricInfo {
indexes, indexes,
value_type, value_type: value_type.into(),
}) })
} }

View File

@@ -195,6 +195,50 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
.not_found(), .not_found(),
), ),
) )
.api_route(
"/api/metric/{metric}/{index}/len",
get_with(
async |uri: Uri,
headers: HeaderMap,
State(state): State<AppState>,
Path(path): Path<MetricWithIndex>| {
state
.cached_json(&headers, CacheStrategy::Height, &uri, move |q| {
q.len(&path.metric, path.index)
})
.await
},
|op| op
.id("get_metric_len")
.metrics_tag()
.summary("Get metric data length")
.description("Returns the total number of data points for a metric at the given index.")
.ok_response::<usize>()
.not_found(),
),
)
.api_route(
"/api/metric/{metric}/{index}/version",
get_with(
async |uri: Uri,
headers: HeaderMap,
State(state): State<AppState>,
Path(path): Path<MetricWithIndex>| {
state
.cached_json(&headers, CacheStrategy::Height, &uri, move |q| {
q.version(&path.metric, path.index)
})
.await
},
|op| op
.id("get_metric_version")
.metrics_tag()
.summary("Get metric version")
.description("Returns the current version of a metric. Changes when the metric data is updated.")
.ok_response::<brk_types::Version>()
.not_found(),
),
)
.api_route( .api_route(
"/api/metric/{metric}/{index}/data", "/api/metric/{metric}/{index}/data",
get_with( get_with(

View File

@@ -395,6 +395,7 @@ fn generate_field_traversals(infos: &[FieldInfo], merge: bool) -> proc_macro2::T
let field_name = info.name; let field_name = info.name;
let field_name_str = { let field_name_str = {
let s = field_name.to_string(); let s = field_name.to_string();
let s = s.strip_prefix("r#").unwrap_or(&s).to_string();
s.strip_prefix('_').map(String::from).unwrap_or(s) s.strip_prefix('_').map(String::from).unwrap_or(s)
}; };

View File

@@ -1,14 +1,16 @@
use std::borrow::Cow;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::Serialize; use serde::{Deserialize, Serialize};
use crate::Index; use crate::Index;
/// Metadata about a metric /// Metadata about a metric
#[derive(Debug, Serialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct MetricInfo { pub struct MetricInfo {
/// Available indexes /// Available indexes
pub indexes: Vec<Index>, pub indexes: Vec<Index>,
/// Value type (e.g. "f32", "u64", "Sats") /// Value type (e.g. "f32", "u64", "Sats")
#[serde(rename = "type")] #[serde(rename = "type")]
pub value_type: &'static str, pub value_type: Cow<'static, str>,
} }

View File

@@ -3270,7 +3270,7 @@ function createInRawSumPattern2(client, acc) {
* @property {UnspentPattern} outputs * @property {UnspentPattern} outputs
* @property {CapLossMvrvNuplPriceProfitSoprPattern} realized * @property {CapLossMvrvNuplPriceProfitSoprPattern} realized
* @property {HalvedInTotalPattern} supply * @property {HalvedInTotalPattern} supply
* @property {LossProfitPattern2} unrealized * @property {LossProfitPattern} unrealized
*/ */
/** /**
@@ -3284,7 +3284,7 @@ function createOutputsRealizedSupplyUnrealizedPattern(client, acc) {
outputs: createUnspentPattern(client, _m(acc, 'utxo_count')), outputs: createUnspentPattern(client, _m(acc, 'utxo_count')),
realized: createCapLossMvrvNuplPriceProfitSoprPattern(client, acc), realized: createCapLossMvrvNuplPriceProfitSoprPattern(client, acc),
supply: createHalvedInTotalPattern(client, _m(acc, 'supply')), supply: createHalvedInTotalPattern(client, _m(acc, 'supply')),
unrealized: createLossProfitPattern2(client, _m(acc, 'unrealized')), unrealized: createLossProfitPattern(client, _m(acc, 'unrealized')),
}; };
} }
@@ -3983,18 +3983,18 @@ function createInPattern(client, acc) {
} }
/** /**
* @typedef {Object} LossProfitPattern2 * @typedef {Object} LossProfitPattern
* @property {RawSumPattern2} loss * @property {RawSumPattern2} loss
* @property {RawSumPattern2} profit * @property {RawSumPattern2} profit
*/ */
/** /**
* Create a LossProfitPattern2 pattern node * Create a LossProfitPattern pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated metric name * @param {string} acc - Accumulated metric name
* @returns {LossProfitPattern2} * @returns {LossProfitPattern}
*/ */
function createLossProfitPattern2(client, acc) { function createLossProfitPattern(client, acc) {
return { return {
loss: createRawSumPattern2(client, _m(acc, 'loss')), loss: createRawSumPattern2(client, _m(acc, 'loss')),
profit: createRawSumPattern2(client, _m(acc, 'profit')), profit: createRawSumPattern2(client, _m(acc, 'profit')),
@@ -5390,7 +5390,7 @@ function createRawPattern2(client, acc) {
* @typedef {Object} MetricsTree_Market_Dca_Period * @typedef {Object} MetricsTree_Market_Dca_Period
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} stack * @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} stack
* @property {MetricsTree_Market_Dca_Period_CostBasis} costBasis * @property {MetricsTree_Market_Dca_Period_CostBasis} costBasis
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} r#return * @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} return
* @property {_10y2y3y4y5y6y8yPattern} cagr * @property {_10y2y3y4y5y6y8yPattern} cagr
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} lumpSumStack * @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} lumpSumStack
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} lumpSumReturn * @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} lumpSumReturn
@@ -5416,7 +5416,7 @@ function createRawPattern2(client, acc) {
* @typedef {Object} MetricsTree_Market_Dca_Class * @typedef {Object} MetricsTree_Market_Dca_Class
* @property {MetricsTree_Market_Dca_Class_Stack} stack * @property {MetricsTree_Market_Dca_Class_Stack} stack
* @property {MetricsTree_Market_Dca_Class_CostBasis} costBasis * @property {MetricsTree_Market_Dca_Class_CostBasis} costBasis
* @property {MetricsTree_Market_Dca_Class_R#return} r#return * @property {MetricsTree_Market_Dca_Class_Return} return
*/ */
/** /**
@@ -5452,7 +5452,7 @@ function createRawPattern2(client, acc) {
*/ */
/** /**
* @typedef {Object} MetricsTree_Market_Dca_Class_R#return * @typedef {Object} MetricsTree_Market_Dca_Class_Return
* @property {BpsPercentRatioPattern} from2015 * @property {BpsPercentRatioPattern} from2015
* @property {BpsPercentRatioPattern} from2016 * @property {BpsPercentRatioPattern} from2016
* @property {BpsPercentRatioPattern} from2017 * @property {BpsPercentRatioPattern} from2017
@@ -5865,13 +5865,13 @@ function createRawPattern2(client, acc) {
* @property {MetricsTree_Distribution_Cohorts_Utxo_Sth} sth * @property {MetricsTree_Distribution_Cohorts_Utxo_Sth} sth
* @property {MetricsTree_Distribution_Cohorts_Utxo_Lth} lth * @property {MetricsTree_Distribution_Cohorts_Utxo_Lth} lth
* @property {MetricsTree_Distribution_Cohorts_Utxo_AgeRange} ageRange * @property {MetricsTree_Distribution_Cohorts_Utxo_AgeRange} ageRange
* @property {MetricsTree_Distribution_Cohorts_Utxo_MaxAge} maxAge * @property {MetricsTree_Distribution_Cohorts_Utxo_UnderAge} underAge
* @property {MetricsTree_Distribution_Cohorts_Utxo_MinAge} minAge * @property {MetricsTree_Distribution_Cohorts_Utxo_OverAge} overAge
* @property {MetricsTree_Distribution_Cohorts_Utxo_Epoch} epoch * @property {MetricsTree_Distribution_Cohorts_Utxo_Epoch} epoch
* @property {MetricsTree_Distribution_Cohorts_Utxo_Class} class * @property {MetricsTree_Distribution_Cohorts_Utxo_Class} class
* @property {MetricsTree_Distribution_Cohorts_Utxo_GeAmount} geAmount * @property {MetricsTree_Distribution_Cohorts_Utxo_OverAmount} overAmount
* @property {MetricsTree_Distribution_Cohorts_Utxo_AmountRange} amountRange * @property {MetricsTree_Distribution_Cohorts_Utxo_AmountRange} amountRange
* @property {MetricsTree_Distribution_Cohorts_Utxo_LtAmount} ltAmount * @property {MetricsTree_Distribution_Cohorts_Utxo_UnderAmount} underAmount
* @property {MetricsTree_Distribution_Cohorts_Utxo_Type} type * @property {MetricsTree_Distribution_Cohorts_Utxo_Type} type
* @property {MetricsTree_Distribution_Cohorts_Utxo_Profitability} profitability * @property {MetricsTree_Distribution_Cohorts_Utxo_Profitability} profitability
* @property {MetricsTree_Distribution_Cohorts_Utxo_Matured} matured * @property {MetricsTree_Distribution_Cohorts_Utxo_Matured} matured
@@ -6012,7 +6012,7 @@ function createRawPattern2(client, acc) {
*/ */
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_MaxAge * @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_UnderAge
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1w * @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1w
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1m * @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1m
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _2m * @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _2m
@@ -6034,7 +6034,7 @@ function createRawPattern2(client, acc) {
*/ */
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_MinAge * @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_OverAge
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1d * @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1d
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1w * @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1w
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1m * @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1m
@@ -6087,7 +6087,7 @@ function createRawPattern2(client, acc) {
*/ */
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_GeAmount * @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_OverAmount
* @property {OutputsRealizedSupplyPattern} _1sat * @property {OutputsRealizedSupplyPattern} _1sat
* @property {OutputsRealizedSupplyPattern} _10sats * @property {OutputsRealizedSupplyPattern} _10sats
* @property {OutputsRealizedSupplyPattern} _100sats * @property {OutputsRealizedSupplyPattern} _100sats
@@ -6123,7 +6123,7 @@ function createRawPattern2(client, acc) {
*/ */
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_LtAmount * @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_UnderAmount
* @property {OutputsRealizedSupplyPattern} _10sats * @property {OutputsRealizedSupplyPattern} _10sats
* @property {OutputsRealizedSupplyPattern} _100sats * @property {OutputsRealizedSupplyPattern} _100sats
* @property {OutputsRealizedSupplyPattern} _1kSats * @property {OutputsRealizedSupplyPattern} _1kSats
@@ -6163,31 +6163,31 @@ function createRawPattern2(client, acc) {
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_Profitability_Range * @typedef {Object} MetricsTree_Distribution_Cohorts_Utxo_Profitability_Range
* @property {RealizedSupplyPattern} profitOver1000 * @property {RealizedSupplyPattern} over1000pctInProfit
* @property {RealizedSupplyPattern} profit500To1000 * @property {RealizedSupplyPattern} _500pctTo1000pctInProfit
* @property {RealizedSupplyPattern} profit300To500 * @property {RealizedSupplyPattern} _300pctTo500pctInProfit
* @property {RealizedSupplyPattern} profit200To300 * @property {RealizedSupplyPattern} _200pctTo300pctInProfit
* @property {RealizedSupplyPattern} profit100To200 * @property {RealizedSupplyPattern} _100pctTo200pctInProfit
* @property {RealizedSupplyPattern} profit90To100 * @property {RealizedSupplyPattern} _90pctTo100pctInProfit
* @property {RealizedSupplyPattern} profit80To90 * @property {RealizedSupplyPattern} _80pctTo90pctInProfit
* @property {RealizedSupplyPattern} profit70To80 * @property {RealizedSupplyPattern} _70pctTo80pctInProfit
* @property {RealizedSupplyPattern} profit60To70 * @property {RealizedSupplyPattern} _60pctTo70pctInProfit
* @property {RealizedSupplyPattern} profit50To60 * @property {RealizedSupplyPattern} _50pctTo60pctInProfit
* @property {RealizedSupplyPattern} profit40To50 * @property {RealizedSupplyPattern} _40pctTo50pctInProfit
* @property {RealizedSupplyPattern} profit30To40 * @property {RealizedSupplyPattern} _30pctTo40pctInProfit
* @property {RealizedSupplyPattern} profit20To30 * @property {RealizedSupplyPattern} _20pctTo30pctInProfit
* @property {RealizedSupplyPattern} profit10To20 * @property {RealizedSupplyPattern} _10pctTo20pctInProfit
* @property {RealizedSupplyPattern} profit0To10 * @property {RealizedSupplyPattern} _0pctTo10pctInProfit
* @property {RealizedSupplyPattern} loss0To10 * @property {RealizedSupplyPattern} _0pctTo10pctInLoss
* @property {RealizedSupplyPattern} loss10To20 * @property {RealizedSupplyPattern} _10pctTo20pctInLoss
* @property {RealizedSupplyPattern} loss20To30 * @property {RealizedSupplyPattern} _20pctTo30pctInLoss
* @property {RealizedSupplyPattern} loss30To40 * @property {RealizedSupplyPattern} _30pctTo40pctInLoss
* @property {RealizedSupplyPattern} loss40To50 * @property {RealizedSupplyPattern} _40pctTo50pctInLoss
* @property {RealizedSupplyPattern} loss50To60 * @property {RealizedSupplyPattern} _50pctTo60pctInLoss
* @property {RealizedSupplyPattern} loss60To70 * @property {RealizedSupplyPattern} _60pctTo70pctInLoss
* @property {RealizedSupplyPattern} loss70To80 * @property {RealizedSupplyPattern} _70pctTo80pctInLoss
* @property {RealizedSupplyPattern} loss80To90 * @property {RealizedSupplyPattern} _80pctTo90pctInLoss
* @property {RealizedSupplyPattern} loss90To100 * @property {RealizedSupplyPattern} _90pctTo100pctInLoss
*/ */
/** /**
@@ -6206,7 +6206,6 @@ function createRawPattern2(client, acc) {
* @property {RealizedSupplyPattern} _200pct * @property {RealizedSupplyPattern} _200pct
* @property {RealizedSupplyPattern} _300pct * @property {RealizedSupplyPattern} _300pct
* @property {RealizedSupplyPattern} _500pct * @property {RealizedSupplyPattern} _500pct
* @property {RealizedSupplyPattern} _1000pct
*/ */
/** /**
@@ -6220,7 +6219,6 @@ function createRawPattern2(client, acc) {
* @property {RealizedSupplyPattern} _60pct * @property {RealizedSupplyPattern} _60pct
* @property {RealizedSupplyPattern} _70pct * @property {RealizedSupplyPattern} _70pct
* @property {RealizedSupplyPattern} _80pct * @property {RealizedSupplyPattern} _80pct
* @property {RealizedSupplyPattern} _90pct
*/ */
/** /**
@@ -6250,13 +6248,13 @@ function createRawPattern2(client, acc) {
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Address * @typedef {Object} MetricsTree_Distribution_Cohorts_Address
* @property {MetricsTree_Distribution_Cohorts_Address_GeAmount} geAmount * @property {MetricsTree_Distribution_Cohorts_Address_OverAmount} overAmount
* @property {MetricsTree_Distribution_Cohorts_Address_AmountRange} amountRange * @property {MetricsTree_Distribution_Cohorts_Address_AmountRange} amountRange
* @property {MetricsTree_Distribution_Cohorts_Address_LtAmount} ltAmount * @property {MetricsTree_Distribution_Cohorts_Address_UnderAmount} underAmount
*/ */
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Address_GeAmount * @typedef {Object} MetricsTree_Distribution_Cohorts_Address_OverAmount
* @property {AddrOutputsRealizedSupplyPattern} _1sat * @property {AddrOutputsRealizedSupplyPattern} _1sat
* @property {AddrOutputsRealizedSupplyPattern} _10sats * @property {AddrOutputsRealizedSupplyPattern} _10sats
* @property {AddrOutputsRealizedSupplyPattern} _100sats * @property {AddrOutputsRealizedSupplyPattern} _100sats
@@ -6292,7 +6290,7 @@ function createRawPattern2(client, acc) {
*/ */
/** /**
* @typedef {Object} MetricsTree_Distribution_Cohorts_Address_LtAmount * @typedef {Object} MetricsTree_Distribution_Cohorts_Address_UnderAmount
* @property {AddrOutputsRealizedSupplyPattern} _10sats * @property {AddrOutputsRealizedSupplyPattern} _10sats
* @property {AddrOutputsRealizedSupplyPattern} _100sats * @property {AddrOutputsRealizedSupplyPattern} _100sats
* @property {AddrOutputsRealizedSupplyPattern} _1kSats * @property {AddrOutputsRealizedSupplyPattern} _1kSats
@@ -6847,7 +6845,7 @@ class BrkClient extends BrkClientBase {
} }
}); });
MAX_AGE_NAMES = /** @type {const} */ ({ UNDER_AGE_NAMES = /** @type {const} */ ({
"_1w": { "_1w": {
"id": "under_1w_old", "id": "under_1w_old",
"short": "<1w", "short": "<1w",
@@ -6940,7 +6938,7 @@ class BrkClient extends BrkClientBase {
} }
}); });
MIN_AGE_NAMES = /** @type {const} */ ({ OVER_AGE_NAMES = /** @type {const} */ ({
"_1d": { "_1d": {
"id": "over_1d_old", "id": "over_1d_old",
"short": "1d+", "short": "1d+",
@@ -7111,7 +7109,7 @@ class BrkClient extends BrkClientBase {
} }
}); });
GE_AMOUNT_NAMES = /** @type {const} */ ({ OVER_AMOUNT_NAMES = /** @type {const} */ ({
"_1sat": { "_1sat": {
"id": "over_1sat", "id": "over_1sat",
"short": "1+ sats", "short": "1+ sats",
@@ -7179,7 +7177,7 @@ class BrkClient extends BrkClientBase {
} }
}); });
LT_AMOUNT_NAMES = /** @type {const} */ ({ UNDER_AMOUNT_NAMES = /** @type {const} */ ({
"_10sats": { "_10sats": {
"id": "under_10sats", "id": "under_10sats",
"short": "<10 sats", "short": "<10 sats",
@@ -7943,7 +7941,7 @@ class BrkClient extends BrkClientBase {
_8y: createCentsSatsUsdPattern(this, 'dca_cost_basis_8y'), _8y: createCentsSatsUsdPattern(this, 'dca_cost_basis_8y'),
_10y: createCentsSatsUsdPattern(this, 'dca_cost_basis_10y'), _10y: createCentsSatsUsdPattern(this, 'dca_cost_basis_10y'),
}, },
r#return: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'dca_return'), return: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'dca_return'),
cagr: create_10y2y3y4y5y6y8yPattern(this, 'dca_cagr'), cagr: create_10y2y3y4y5y6y8yPattern(this, 'dca_cagr'),
lumpSumStack: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(this, 'lump_sum_stack'), lumpSumStack: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(this, 'lump_sum_stack'),
lumpSumReturn: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'lump_sum_return'), lumpSumReturn: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'lump_sum_return'),
@@ -7977,7 +7975,7 @@ class BrkClient extends BrkClientBase {
from2025: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2025'), from2025: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2025'),
from2026: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2026'), from2026: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2026'),
}, },
r#return: { return: {
from2015: createBpsPercentRatioPattern(this, 'dca_return_from_2015'), from2015: createBpsPercentRatioPattern(this, 'dca_return_from_2015'),
from2016: createBpsPercentRatioPattern(this, 'dca_return_from_2016'), from2016: createBpsPercentRatioPattern(this, 'dca_return_from_2016'),
from2017: createBpsPercentRatioPattern(this, 'dca_return_from_2017'), from2017: createBpsPercentRatioPattern(this, 'dca_return_from_2017'),
@@ -8410,7 +8408,7 @@ class BrkClient extends BrkClientBase {
_12yTo15y: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'utxos_12y_to_15y_old'), _12yTo15y: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'utxos_12y_to_15y_old'),
from15y: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'utxos_over_15y_old'), from15y: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'utxos_over_15y_old'),
}, },
maxAge: { underAge: {
_1w: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_1w_old'), _1w: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_1w_old'),
_1m: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_1m_old'), _1m: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_1m_old'),
_2m: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_2m_old'), _2m: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_2m_old'),
@@ -8430,7 +8428,7 @@ class BrkClient extends BrkClientBase {
_12y: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_12y_old'), _12y: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_12y_old'),
_15y: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_15y_old'), _15y: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_under_15y_old'),
}, },
minAge: { overAge: {
_1d: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_1d_old'), _1d: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_1d_old'),
_1w: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_1w_old'), _1w: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_1w_old'),
_1m: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_1m_old'), _1m: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_1m_old'),
@@ -8477,7 +8475,7 @@ class BrkClient extends BrkClientBase {
_2025: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'class_2025'), _2025: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'class_2025'),
_2026: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'class_2026'), _2026: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'class_2026'),
}, },
geAmount: { overAmount: {
_1sat: createOutputsRealizedSupplyPattern(this, 'utxos_over_1sat'), _1sat: createOutputsRealizedSupplyPattern(this, 'utxos_over_1sat'),
_10sats: createOutputsRealizedSupplyPattern(this, 'utxos_over_10sats'), _10sats: createOutputsRealizedSupplyPattern(this, 'utxos_over_10sats'),
_100sats: createOutputsRealizedSupplyPattern(this, 'utxos_over_100sats'), _100sats: createOutputsRealizedSupplyPattern(this, 'utxos_over_100sats'),
@@ -8509,7 +8507,7 @@ class BrkClient extends BrkClientBase {
_10kBtcTo100kBtc: createOutputsRealizedSupplyPattern(this, 'utxos_above_10k_btc_under_100k_btc'), _10kBtcTo100kBtc: createOutputsRealizedSupplyPattern(this, 'utxos_above_10k_btc_under_100k_btc'),
_100kBtcOrMore: createOutputsRealizedSupplyPattern(this, 'utxos_above_100k_btc'), _100kBtcOrMore: createOutputsRealizedSupplyPattern(this, 'utxos_above_100k_btc'),
}, },
ltAmount: { underAmount: {
_10sats: createOutputsRealizedSupplyPattern(this, 'utxos_under_10sats'), _10sats: createOutputsRealizedSupplyPattern(this, 'utxos_under_10sats'),
_100sats: createOutputsRealizedSupplyPattern(this, 'utxos_under_100sats'), _100sats: createOutputsRealizedSupplyPattern(this, 'utxos_under_100sats'),
_1kSats: createOutputsRealizedSupplyPattern(this, 'utxos_under_1k_sats'), _1kSats: createOutputsRealizedSupplyPattern(this, 'utxos_under_1k_sats'),
@@ -8539,60 +8537,58 @@ class BrkClient extends BrkClientBase {
}, },
profitability: { profitability: {
range: { range: {
profitOver1000: createRealizedSupplyPattern(this, 'utxos_over_1000pct_up'), over1000pctInProfit: createRealizedSupplyPattern(this, 'utxos_over_1000pct_in_profit'),
profit500To1000: createRealizedSupplyPattern(this, 'utxos_500pct_to_1000pct_up'), _500pctTo1000pctInProfit: createRealizedSupplyPattern(this, 'utxos_500pct_to_1000pct_in_profit'),
profit300To500: createRealizedSupplyPattern(this, 'utxos_300pct_to_500pct_up'), _300pctTo500pctInProfit: createRealizedSupplyPattern(this, 'utxos_300pct_to_500pct_in_profit'),
profit200To300: createRealizedSupplyPattern(this, 'utxos_200pct_to_300pct_up'), _200pctTo300pctInProfit: createRealizedSupplyPattern(this, 'utxos_200pct_to_300pct_in_profit'),
profit100To200: createRealizedSupplyPattern(this, 'utxos_100pct_to_200pct_up'), _100pctTo200pctInProfit: createRealizedSupplyPattern(this, 'utxos_100pct_to_200pct_in_profit'),
profit90To100: createRealizedSupplyPattern(this, 'utxos_90pct_to_100pct_up'), _90pctTo100pctInProfit: createRealizedSupplyPattern(this, 'utxos_90pct_to_100pct_in_profit'),
profit80To90: createRealizedSupplyPattern(this, 'utxos_80pct_to_90pct_up'), _80pctTo90pctInProfit: createRealizedSupplyPattern(this, 'utxos_80pct_to_90pct_in_profit'),
profit70To80: createRealizedSupplyPattern(this, 'utxos_70pct_to_80pct_up'), _70pctTo80pctInProfit: createRealizedSupplyPattern(this, 'utxos_70pct_to_80pct_in_profit'),
profit60To70: createRealizedSupplyPattern(this, 'utxos_60pct_to_70pct_up'), _60pctTo70pctInProfit: createRealizedSupplyPattern(this, 'utxos_60pct_to_70pct_in_profit'),
profit50To60: createRealizedSupplyPattern(this, 'utxos_50pct_to_60pct_up'), _50pctTo60pctInProfit: createRealizedSupplyPattern(this, 'utxos_50pct_to_60pct_in_profit'),
profit40To50: createRealizedSupplyPattern(this, 'utxos_40pct_to_50pct_up'), _40pctTo50pctInProfit: createRealizedSupplyPattern(this, 'utxos_40pct_to_50pct_in_profit'),
profit30To40: createRealizedSupplyPattern(this, 'utxos_30pct_to_40pct_up'), _30pctTo40pctInProfit: createRealizedSupplyPattern(this, 'utxos_30pct_to_40pct_in_profit'),
profit20To30: createRealizedSupplyPattern(this, 'utxos_20pct_to_30pct_up'), _20pctTo30pctInProfit: createRealizedSupplyPattern(this, 'utxos_20pct_to_30pct_in_profit'),
profit10To20: createRealizedSupplyPattern(this, 'utxos_10pct_to_20pct_up'), _10pctTo20pctInProfit: createRealizedSupplyPattern(this, 'utxos_10pct_to_20pct_in_profit'),
profit0To10: createRealizedSupplyPattern(this, 'utxos_0pct_to_10pct_up'), _0pctTo10pctInProfit: createRealizedSupplyPattern(this, 'utxos_0pct_to_10pct_in_profit'),
loss0To10: createRealizedSupplyPattern(this, 'utxos_0pct_to_10pct_down'), _0pctTo10pctInLoss: createRealizedSupplyPattern(this, 'utxos_0pct_to_10pct_in_loss'),
loss10To20: createRealizedSupplyPattern(this, 'utxos_10pct_to_20pct_down'), _10pctTo20pctInLoss: createRealizedSupplyPattern(this, 'utxos_10pct_to_20pct_in_loss'),
loss20To30: createRealizedSupplyPattern(this, 'utxos_20pct_to_30pct_down'), _20pctTo30pctInLoss: createRealizedSupplyPattern(this, 'utxos_20pct_to_30pct_in_loss'),
loss30To40: createRealizedSupplyPattern(this, 'utxos_30pct_to_40pct_down'), _30pctTo40pctInLoss: createRealizedSupplyPattern(this, 'utxos_30pct_to_40pct_in_loss'),
loss40To50: createRealizedSupplyPattern(this, 'utxos_40pct_to_50pct_down'), _40pctTo50pctInLoss: createRealizedSupplyPattern(this, 'utxos_40pct_to_50pct_in_loss'),
loss50To60: createRealizedSupplyPattern(this, 'utxos_50pct_to_60pct_down'), _50pctTo60pctInLoss: createRealizedSupplyPattern(this, 'utxos_50pct_to_60pct_in_loss'),
loss60To70: createRealizedSupplyPattern(this, 'utxos_60pct_to_70pct_down'), _60pctTo70pctInLoss: createRealizedSupplyPattern(this, 'utxos_60pct_to_70pct_in_loss'),
loss70To80: createRealizedSupplyPattern(this, 'utxos_70pct_to_80pct_down'), _70pctTo80pctInLoss: createRealizedSupplyPattern(this, 'utxos_70pct_to_80pct_in_loss'),
loss80To90: createRealizedSupplyPattern(this, 'utxos_80pct_to_90pct_down'), _80pctTo90pctInLoss: createRealizedSupplyPattern(this, 'utxos_80pct_to_90pct_in_loss'),
loss90To100: createRealizedSupplyPattern(this, 'utxos_90pct_to_100pct_down'), _90pctTo100pctInLoss: createRealizedSupplyPattern(this, 'utxos_90pct_to_100pct_in_loss'),
}, },
profit: { profit: {
breakeven: createRealizedSupplyPattern(this, 'profit_ge_breakeven'), breakeven: createRealizedSupplyPattern(this, 'utxos_in_profit'),
_10pct: createRealizedSupplyPattern(this, 'profit_ge_10pct'), _10pct: createRealizedSupplyPattern(this, 'utxos_over_10pct_in_profit'),
_20pct: createRealizedSupplyPattern(this, 'profit_ge_20pct'), _20pct: createRealizedSupplyPattern(this, 'utxos_over_20pct_in_profit'),
_30pct: createRealizedSupplyPattern(this, 'profit_ge_30pct'), _30pct: createRealizedSupplyPattern(this, 'utxos_over_30pct_in_profit'),
_40pct: createRealizedSupplyPattern(this, 'profit_ge_40pct'), _40pct: createRealizedSupplyPattern(this, 'utxos_over_40pct_in_profit'),
_50pct: createRealizedSupplyPattern(this, 'profit_ge_50pct'), _50pct: createRealizedSupplyPattern(this, 'utxos_over_50pct_in_profit'),
_60pct: createRealizedSupplyPattern(this, 'profit_ge_60pct'), _60pct: createRealizedSupplyPattern(this, 'utxos_over_60pct_in_profit'),
_70pct: createRealizedSupplyPattern(this, 'profit_ge_70pct'), _70pct: createRealizedSupplyPattern(this, 'utxos_over_70pct_in_profit'),
_80pct: createRealizedSupplyPattern(this, 'profit_ge_80pct'), _80pct: createRealizedSupplyPattern(this, 'utxos_over_80pct_in_profit'),
_90pct: createRealizedSupplyPattern(this, 'profit_ge_90pct'), _90pct: createRealizedSupplyPattern(this, 'utxos_over_90pct_in_profit'),
_100pct: createRealizedSupplyPattern(this, 'profit_ge_100pct'), _100pct: createRealizedSupplyPattern(this, 'utxos_over_100pct_in_profit'),
_200pct: createRealizedSupplyPattern(this, 'profit_ge_200pct'), _200pct: createRealizedSupplyPattern(this, 'utxos_over_200pct_in_profit'),
_300pct: createRealizedSupplyPattern(this, 'profit_ge_300pct'), _300pct: createRealizedSupplyPattern(this, 'utxos_over_300pct_in_profit'),
_500pct: createRealizedSupplyPattern(this, 'profit_ge_500pct'), _500pct: createRealizedSupplyPattern(this, 'utxos_over_500pct_in_profit'),
_1000pct: createRealizedSupplyPattern(this, 'profit_ge_1000pct'),
}, },
loss: { loss: {
breakeven: createRealizedSupplyPattern(this, 'loss_ge_breakeven'), breakeven: createRealizedSupplyPattern(this, 'utxos_in_loss'),
_10pct: createRealizedSupplyPattern(this, 'loss_ge_10pct'), _10pct: createRealizedSupplyPattern(this, 'utxos_over_10pct_in_loss'),
_20pct: createRealizedSupplyPattern(this, 'loss_ge_20pct'), _20pct: createRealizedSupplyPattern(this, 'utxos_over_20pct_in_loss'),
_30pct: createRealizedSupplyPattern(this, 'loss_ge_30pct'), _30pct: createRealizedSupplyPattern(this, 'utxos_over_30pct_in_loss'),
_40pct: createRealizedSupplyPattern(this, 'loss_ge_40pct'), _40pct: createRealizedSupplyPattern(this, 'utxos_over_40pct_in_loss'),
_50pct: createRealizedSupplyPattern(this, 'loss_ge_50pct'), _50pct: createRealizedSupplyPattern(this, 'utxos_over_50pct_in_loss'),
_60pct: createRealizedSupplyPattern(this, 'loss_ge_60pct'), _60pct: createRealizedSupplyPattern(this, 'utxos_over_60pct_in_loss'),
_70pct: createRealizedSupplyPattern(this, 'loss_ge_70pct'), _70pct: createRealizedSupplyPattern(this, 'utxos_over_70pct_in_loss'),
_80pct: createRealizedSupplyPattern(this, 'loss_ge_80pct'), _80pct: createRealizedSupplyPattern(this, 'utxos_over_80pct_in_loss'),
_90pct: createRealizedSupplyPattern(this, 'loss_ge_90pct'),
}, },
}, },
matured: { matured: {
@@ -8620,7 +8616,7 @@ class BrkClient extends BrkClientBase {
}, },
}, },
address: { address: {
geAmount: { overAmount: {
_1sat: createAddrOutputsRealizedSupplyPattern(this, 'addrs_over_1sat'), _1sat: createAddrOutputsRealizedSupplyPattern(this, 'addrs_over_1sat'),
_10sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_over_10sats'), _10sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_over_10sats'),
_100sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_over_100sats'), _100sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_over_100sats'),
@@ -8652,7 +8648,7 @@ class BrkClient extends BrkClientBase {
_10kBtcTo100kBtc: createAddrOutputsRealizedSupplyPattern(this, 'addrs_above_10k_btc_under_100k_btc'), _10kBtcTo100kBtc: createAddrOutputsRealizedSupplyPattern(this, 'addrs_above_10k_btc_under_100k_btc'),
_100kBtcOrMore: createAddrOutputsRealizedSupplyPattern(this, 'addrs_above_100k_btc'), _100kBtcOrMore: createAddrOutputsRealizedSupplyPattern(this, 'addrs_above_100k_btc'),
}, },
ltAmount: { underAmount: {
_10sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_under_10sats'), _10sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_under_10sats'),
_100sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_under_100sats'), _100sats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_under_100sats'),
_1kSats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_under_1k_sats'), _1kSats: createAddrOutputsRealizedSupplyPattern(this, 'addrs_under_1k_sats'),
@@ -9084,6 +9080,36 @@ class BrkClient extends BrkClientBase {
return this.getJson(`/api/metric/${metric}/${index}/latest`); return this.getJson(`/api/metric/${metric}/${index}/latest`);
} }
/**
* Get metric data length
*
* Returns the total number of data points for a metric at the given index.
*
* Endpoint: `GET /api/metric/{metric}/{index}/len`
*
* @param {Metric} metric - Metric name
* @param {Index} index - Aggregation index
* @returns {Promise<number>}
*/
async getMetricLen(metric, index) {
return this.getJson(`/api/metric/${metric}/${index}/len`);
}
/**
* Get metric version
*
* Returns the current version of a metric. Changes when the metric data is updated.
*
* Endpoint: `GET /api/metric/{metric}/{index}/version`
*
* @param {Metric} metric - Metric name
* @param {Index} index - Aggregation index
* @returns {Promise<Version>}
*/
async getMetricVersion(metric, index) {
return this.getJson(`/api/metric/${metric}/${index}/version`);
}
/** /**
* Metrics catalog * Metrics catalog
* *

View File

@@ -2863,7 +2863,7 @@ class OutputsRealizedSupplyUnrealizedPattern:
self.outputs: UnspentPattern = UnspentPattern(client, _m(acc, 'utxo_count')) self.outputs: UnspentPattern = UnspentPattern(client, _m(acc, 'utxo_count'))
self.realized: CapLossMvrvNuplPriceProfitSoprPattern = CapLossMvrvNuplPriceProfitSoprPattern(client, acc) self.realized: CapLossMvrvNuplPriceProfitSoprPattern = CapLossMvrvNuplPriceProfitSoprPattern(client, acc)
self.supply: HalvedInTotalPattern = HalvedInTotalPattern(client, _m(acc, 'supply')) self.supply: HalvedInTotalPattern = HalvedInTotalPattern(client, _m(acc, 'supply'))
self.unrealized: LossProfitPattern2 = LossProfitPattern2(client, _m(acc, 'unrealized')) self.unrealized: LossProfitPattern = LossProfitPattern(client, _m(acc, 'unrealized'))
class _1m1w1y24hPattern(Generic[T]): class _1m1w1y24hPattern(Generic[T]):
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -3158,7 +3158,7 @@ class InPattern:
self.in_loss: RawPattern2[CentsSats] = RawPattern2(client, _m(acc, 'loss_raw')) self.in_loss: RawPattern2[CentsSats] = RawPattern2(client, _m(acc, 'loss_raw'))
self.in_profit: RawPattern2[CentsSats] = RawPattern2(client, _m(acc, 'profit_raw')) self.in_profit: RawPattern2[CentsSats] = RawPattern2(client, _m(acc, 'profit_raw'))
class LossProfitPattern2: class LossProfitPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -4450,7 +4450,7 @@ class MetricsTree_Market_Dca_Class_CostBasis:
self.from_2025: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2025') self.from_2025: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2025')
self.from_2026: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2026') self.from_2026: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2026')
class MetricsTree_Market_Dca_Class_R#return: class MetricsTree_Market_Dca_Class_Return:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
@@ -4473,7 +4473,7 @@ class MetricsTree_Market_Dca_Class:
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.stack: MetricsTree_Market_Dca_Class_Stack = MetricsTree_Market_Dca_Class_Stack(client) self.stack: MetricsTree_Market_Dca_Class_Stack = MetricsTree_Market_Dca_Class_Stack(client)
self.cost_basis: MetricsTree_Market_Dca_Class_CostBasis = MetricsTree_Market_Dca_Class_CostBasis(client) self.cost_basis: MetricsTree_Market_Dca_Class_CostBasis = MetricsTree_Market_Dca_Class_CostBasis(client)
self.r#return: MetricsTree_Market_Dca_Class_R#return = MetricsTree_Market_Dca_Class_R#return(client) self.r#return: MetricsTree_Market_Dca_Class_Return = MetricsTree_Market_Dca_Class_Return(client)
class MetricsTree_Market_Dca: class MetricsTree_Market_Dca:
"""Metrics tree node.""" """Metrics tree node."""
@@ -5044,7 +5044,7 @@ class MetricsTree_Distribution_Cohorts_Utxo_AgeRange:
self._12y_to_15y: ActivityOutputsRealizedSupplyUnrealizedPattern = ActivityOutputsRealizedSupplyUnrealizedPattern(client, 'utxos_12y_to_15y_old') self._12y_to_15y: ActivityOutputsRealizedSupplyUnrealizedPattern = ActivityOutputsRealizedSupplyUnrealizedPattern(client, 'utxos_12y_to_15y_old')
self.from_15y: ActivityOutputsRealizedSupplyUnrealizedPattern = ActivityOutputsRealizedSupplyUnrealizedPattern(client, 'utxos_over_15y_old') self.from_15y: ActivityOutputsRealizedSupplyUnrealizedPattern = ActivityOutputsRealizedSupplyUnrealizedPattern(client, 'utxos_over_15y_old')
class MetricsTree_Distribution_Cohorts_Utxo_MaxAge: class MetricsTree_Distribution_Cohorts_Utxo_UnderAge:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
@@ -5067,7 +5067,7 @@ class MetricsTree_Distribution_Cohorts_Utxo_MaxAge:
self._12y: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'utxos_under_12y_old') self._12y: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'utxos_under_12y_old')
self._15y: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'utxos_under_15y_old') self._15y: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'utxos_under_15y_old')
class MetricsTree_Distribution_Cohorts_Utxo_MinAge: class MetricsTree_Distribution_Cohorts_Utxo_OverAge:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
@@ -5123,7 +5123,7 @@ class MetricsTree_Distribution_Cohorts_Utxo_Class:
self._2025: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'class_2025') self._2025: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'class_2025')
self._2026: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'class_2026') self._2026: ActivityOutputsRealizedSupplyUnrealizedPattern2 = ActivityOutputsRealizedSupplyUnrealizedPattern2(client, 'class_2026')
class MetricsTree_Distribution_Cohorts_Utxo_GeAmount: class MetricsTree_Distribution_Cohorts_Utxo_OverAmount:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
@@ -5161,7 +5161,7 @@ class MetricsTree_Distribution_Cohorts_Utxo_AmountRange:
self._10k_btc_to_100k_btc: OutputsRealizedSupplyPattern = OutputsRealizedSupplyPattern(client, 'utxos_above_10k_btc_under_100k_btc') self._10k_btc_to_100k_btc: OutputsRealizedSupplyPattern = OutputsRealizedSupplyPattern(client, 'utxos_above_10k_btc_under_100k_btc')
self._100k_btc_or_more: OutputsRealizedSupplyPattern = OutputsRealizedSupplyPattern(client, 'utxos_above_100k_btc') self._100k_btc_or_more: OutputsRealizedSupplyPattern = OutputsRealizedSupplyPattern(client, 'utxos_above_100k_btc')
class MetricsTree_Distribution_Cohorts_Utxo_LtAmount: class MetricsTree_Distribution_Cohorts_Utxo_UnderAmount:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
@@ -5199,66 +5199,64 @@ class MetricsTree_Distribution_Cohorts_Utxo_Profitability_Range:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.profit_over_1000: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_1000pct_up') self.over_1000pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_1000pct_in_profit')
self.profit_500_to_1000: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_500pct_to_1000pct_up') self._500pct_to_1000pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_500pct_to_1000pct_in_profit')
self.profit_300_to_500: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_300pct_to_500pct_up') self._300pct_to_500pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_300pct_to_500pct_in_profit')
self.profit_200_to_300: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_200pct_to_300pct_up') self._200pct_to_300pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_200pct_to_300pct_in_profit')
self.profit_100_to_200: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_100pct_to_200pct_up') self._100pct_to_200pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_100pct_to_200pct_in_profit')
self.profit_90_to_100: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_90pct_to_100pct_up') self._90pct_to_100pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_90pct_to_100pct_in_profit')
self.profit_80_to_90: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_80pct_to_90pct_up') self._80pct_to_90pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_80pct_to_90pct_in_profit')
self.profit_70_to_80: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_70pct_to_80pct_up') self._70pct_to_80pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_70pct_to_80pct_in_profit')
self.profit_60_to_70: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_60pct_to_70pct_up') self._60pct_to_70pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_60pct_to_70pct_in_profit')
self.profit_50_to_60: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_50pct_to_60pct_up') self._50pct_to_60pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_50pct_to_60pct_in_profit')
self.profit_40_to_50: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_40pct_to_50pct_up') self._40pct_to_50pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_40pct_to_50pct_in_profit')
self.profit_30_to_40: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_30pct_to_40pct_up') self._30pct_to_40pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_30pct_to_40pct_in_profit')
self.profit_20_to_30: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_20pct_to_30pct_up') self._20pct_to_30pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_20pct_to_30pct_in_profit')
self.profit_10_to_20: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_10pct_to_20pct_up') self._10pct_to_20pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_10pct_to_20pct_in_profit')
self.profit_0_to_10: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_0pct_to_10pct_up') self._0pct_to_10pct_in_profit: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_0pct_to_10pct_in_profit')
self.loss_0_to_10: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_0pct_to_10pct_down') self._0pct_to_10pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_0pct_to_10pct_in_loss')
self.loss_10_to_20: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_10pct_to_20pct_down') self._10pct_to_20pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_10pct_to_20pct_in_loss')
self.loss_20_to_30: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_20pct_to_30pct_down') self._20pct_to_30pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_20pct_to_30pct_in_loss')
self.loss_30_to_40: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_30pct_to_40pct_down') self._30pct_to_40pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_30pct_to_40pct_in_loss')
self.loss_40_to_50: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_40pct_to_50pct_down') self._40pct_to_50pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_40pct_to_50pct_in_loss')
self.loss_50_to_60: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_50pct_to_60pct_down') self._50pct_to_60pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_50pct_to_60pct_in_loss')
self.loss_60_to_70: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_60pct_to_70pct_down') self._60pct_to_70pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_60pct_to_70pct_in_loss')
self.loss_70_to_80: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_70pct_to_80pct_down') self._70pct_to_80pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_70pct_to_80pct_in_loss')
self.loss_80_to_90: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_80pct_to_90pct_down') self._80pct_to_90pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_80pct_to_90pct_in_loss')
self.loss_90_to_100: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_90pct_to_100pct_down') self._90pct_to_100pct_in_loss: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_90pct_to_100pct_in_loss')
class MetricsTree_Distribution_Cohorts_Utxo_Profitability_Profit: class MetricsTree_Distribution_Cohorts_Utxo_Profitability_Profit:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.breakeven: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_breakeven') self.breakeven: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_in_profit')
self._10pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_10pct') self._10pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_10pct_in_profit')
self._20pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_20pct') self._20pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_20pct_in_profit')
self._30pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_30pct') self._30pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_30pct_in_profit')
self._40pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_40pct') self._40pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_40pct_in_profit')
self._50pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_50pct') self._50pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_50pct_in_profit')
self._60pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_60pct') self._60pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_60pct_in_profit')
self._70pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_70pct') self._70pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_70pct_in_profit')
self._80pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_80pct') self._80pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_80pct_in_profit')
self._90pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_90pct') self._90pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_90pct_in_profit')
self._100pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_100pct') self._100pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_100pct_in_profit')
self._200pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_200pct') self._200pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_200pct_in_profit')
self._300pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_300pct') self._300pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_300pct_in_profit')
self._500pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_500pct') self._500pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_500pct_in_profit')
self._1000pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'profit_ge_1000pct')
class MetricsTree_Distribution_Cohorts_Utxo_Profitability_Loss: class MetricsTree_Distribution_Cohorts_Utxo_Profitability_Loss:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.breakeven: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_breakeven') self.breakeven: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_in_loss')
self._10pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_10pct') self._10pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_10pct_in_loss')
self._20pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_20pct') self._20pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_20pct_in_loss')
self._30pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_30pct') self._30pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_30pct_in_loss')
self._40pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_40pct') self._40pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_40pct_in_loss')
self._50pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_50pct') self._50pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_50pct_in_loss')
self._60pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_60pct') self._60pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_60pct_in_loss')
self._70pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_70pct') self._70pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_70pct_in_loss')
self._80pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_80pct') self._80pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'utxos_over_80pct_in_loss')
self._90pct: RealizedSupplyPattern = RealizedSupplyPattern(client, 'loss_ge_90pct')
class MetricsTree_Distribution_Cohorts_Utxo_Profitability: class MetricsTree_Distribution_Cohorts_Utxo_Profitability:
"""Metrics tree node.""" """Metrics tree node."""
@@ -5302,18 +5300,18 @@ class MetricsTree_Distribution_Cohorts_Utxo:
self.sth: MetricsTree_Distribution_Cohorts_Utxo_Sth = MetricsTree_Distribution_Cohorts_Utxo_Sth(client) self.sth: MetricsTree_Distribution_Cohorts_Utxo_Sth = MetricsTree_Distribution_Cohorts_Utxo_Sth(client)
self.lth: MetricsTree_Distribution_Cohorts_Utxo_Lth = MetricsTree_Distribution_Cohorts_Utxo_Lth(client) self.lth: MetricsTree_Distribution_Cohorts_Utxo_Lth = MetricsTree_Distribution_Cohorts_Utxo_Lth(client)
self.age_range: MetricsTree_Distribution_Cohorts_Utxo_AgeRange = MetricsTree_Distribution_Cohorts_Utxo_AgeRange(client) self.age_range: MetricsTree_Distribution_Cohorts_Utxo_AgeRange = MetricsTree_Distribution_Cohorts_Utxo_AgeRange(client)
self.max_age: MetricsTree_Distribution_Cohorts_Utxo_MaxAge = MetricsTree_Distribution_Cohorts_Utxo_MaxAge(client) self.under_age: MetricsTree_Distribution_Cohorts_Utxo_UnderAge = MetricsTree_Distribution_Cohorts_Utxo_UnderAge(client)
self.min_age: MetricsTree_Distribution_Cohorts_Utxo_MinAge = MetricsTree_Distribution_Cohorts_Utxo_MinAge(client) self.over_age: MetricsTree_Distribution_Cohorts_Utxo_OverAge = MetricsTree_Distribution_Cohorts_Utxo_OverAge(client)
self.epoch: MetricsTree_Distribution_Cohorts_Utxo_Epoch = MetricsTree_Distribution_Cohorts_Utxo_Epoch(client) self.epoch: MetricsTree_Distribution_Cohorts_Utxo_Epoch = MetricsTree_Distribution_Cohorts_Utxo_Epoch(client)
self.class: MetricsTree_Distribution_Cohorts_Utxo_Class = MetricsTree_Distribution_Cohorts_Utxo_Class(client) self.class: MetricsTree_Distribution_Cohorts_Utxo_Class = MetricsTree_Distribution_Cohorts_Utxo_Class(client)
self.ge_amount: MetricsTree_Distribution_Cohorts_Utxo_GeAmount = MetricsTree_Distribution_Cohorts_Utxo_GeAmount(client) self.over_amount: MetricsTree_Distribution_Cohorts_Utxo_OverAmount = MetricsTree_Distribution_Cohorts_Utxo_OverAmount(client)
self.amount_range: MetricsTree_Distribution_Cohorts_Utxo_AmountRange = MetricsTree_Distribution_Cohorts_Utxo_AmountRange(client) self.amount_range: MetricsTree_Distribution_Cohorts_Utxo_AmountRange = MetricsTree_Distribution_Cohorts_Utxo_AmountRange(client)
self.lt_amount: MetricsTree_Distribution_Cohorts_Utxo_LtAmount = MetricsTree_Distribution_Cohorts_Utxo_LtAmount(client) self.under_amount: MetricsTree_Distribution_Cohorts_Utxo_UnderAmount = MetricsTree_Distribution_Cohorts_Utxo_UnderAmount(client)
self.r#type: MetricsTree_Distribution_Cohorts_Utxo_Type = MetricsTree_Distribution_Cohorts_Utxo_Type(client) self.r#type: MetricsTree_Distribution_Cohorts_Utxo_Type = MetricsTree_Distribution_Cohorts_Utxo_Type(client)
self.profitability: MetricsTree_Distribution_Cohorts_Utxo_Profitability = MetricsTree_Distribution_Cohorts_Utxo_Profitability(client) self.profitability: MetricsTree_Distribution_Cohorts_Utxo_Profitability = MetricsTree_Distribution_Cohorts_Utxo_Profitability(client)
self.matured: MetricsTree_Distribution_Cohorts_Utxo_Matured = MetricsTree_Distribution_Cohorts_Utxo_Matured(client) self.matured: MetricsTree_Distribution_Cohorts_Utxo_Matured = MetricsTree_Distribution_Cohorts_Utxo_Matured(client)
class MetricsTree_Distribution_Cohorts_Address_GeAmount: class MetricsTree_Distribution_Cohorts_Address_OverAmount:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
@@ -5351,7 +5349,7 @@ class MetricsTree_Distribution_Cohorts_Address_AmountRange:
self._10k_btc_to_100k_btc: AddrOutputsRealizedSupplyPattern = AddrOutputsRealizedSupplyPattern(client, 'addrs_above_10k_btc_under_100k_btc') self._10k_btc_to_100k_btc: AddrOutputsRealizedSupplyPattern = AddrOutputsRealizedSupplyPattern(client, 'addrs_above_10k_btc_under_100k_btc')
self._100k_btc_or_more: AddrOutputsRealizedSupplyPattern = AddrOutputsRealizedSupplyPattern(client, 'addrs_above_100k_btc') self._100k_btc_or_more: AddrOutputsRealizedSupplyPattern = AddrOutputsRealizedSupplyPattern(client, 'addrs_above_100k_btc')
class MetricsTree_Distribution_Cohorts_Address_LtAmount: class MetricsTree_Distribution_Cohorts_Address_UnderAmount:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
@@ -5373,9 +5371,9 @@ class MetricsTree_Distribution_Cohorts_Address:
"""Metrics tree node.""" """Metrics tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.ge_amount: MetricsTree_Distribution_Cohorts_Address_GeAmount = MetricsTree_Distribution_Cohorts_Address_GeAmount(client) self.over_amount: MetricsTree_Distribution_Cohorts_Address_OverAmount = MetricsTree_Distribution_Cohorts_Address_OverAmount(client)
self.amount_range: MetricsTree_Distribution_Cohorts_Address_AmountRange = MetricsTree_Distribution_Cohorts_Address_AmountRange(client) self.amount_range: MetricsTree_Distribution_Cohorts_Address_AmountRange = MetricsTree_Distribution_Cohorts_Address_AmountRange(client)
self.lt_amount: MetricsTree_Distribution_Cohorts_Address_LtAmount = MetricsTree_Distribution_Cohorts_Address_LtAmount(client) self.under_amount: MetricsTree_Distribution_Cohorts_Address_UnderAmount = MetricsTree_Distribution_Cohorts_Address_UnderAmount(client)
class MetricsTree_Distribution_Cohorts: class MetricsTree_Distribution_Cohorts:
"""Metrics tree node.""" """Metrics tree node."""
@@ -5956,7 +5954,7 @@ class BrkClient(BrkClientBase):
} }
} }
MAX_AGE_NAMES = { UNDER_AGE_NAMES = {
"_1w": { "_1w": {
"id": "under_1w_old", "id": "under_1w_old",
"short": "<1w", "short": "<1w",
@@ -6049,7 +6047,7 @@ class BrkClient(BrkClientBase):
} }
} }
MIN_AGE_NAMES = { OVER_AGE_NAMES = {
"_1d": { "_1d": {
"id": "over_1d_old", "id": "over_1d_old",
"short": "1d+", "short": "1d+",
@@ -6220,7 +6218,7 @@ class BrkClient(BrkClientBase):
} }
} }
GE_AMOUNT_NAMES = { OVER_AMOUNT_NAMES = {
"_1sat": { "_1sat": {
"id": "over_1sat", "id": "over_1sat",
"short": "1+ sats", "short": "1+ sats",
@@ -6288,7 +6286,7 @@ class BrkClient(BrkClientBase):
} }
} }
LT_AMOUNT_NAMES = { UNDER_AMOUNT_NAMES = {
"_10sats": { "_10sats": {
"id": "under_10sats", "id": "under_10sats",
"short": "<10 sats", "short": "<10 sats",
@@ -6612,6 +6610,22 @@ class BrkClient(BrkClientBase):
Endpoint: `GET /api/metric/{metric}/{index}/latest`""" Endpoint: `GET /api/metric/{metric}/{index}/latest`"""
return self.get_json(f'/api/metric/{metric}/{index}/latest') return self.get_json(f'/api/metric/{metric}/{index}/latest')
def get_metric_len(self, metric: Metric, index: Index) -> float:
"""Get metric data length.
Returns the total number of data points for a metric at the given index.
Endpoint: `GET /api/metric/{metric}/{index}/len`"""
return self.get_json(f'/api/metric/{metric}/{index}/len')
def get_metric_version(self, metric: Metric, index: Index) -> Version:
"""Get metric version.
Returns the current version of a metric. Changes when the metric data is updated.
Endpoint: `GET /api/metric/{metric}/{index}/version`"""
return self.get_json(f'/api/metric/{metric}/{index}/version')
def get_metrics_tree(self) -> TreeNode: def get_metrics_tree(self) -> TreeNode:
"""Metrics catalog. """Metrics catalog.

View File

@@ -50,6 +50,11 @@ Get the latest value:
GET /api/metric/{metric}/{index}/latest GET /api/metric/{metric}/{index}/latest
Get the data length or version:
GET /api/metric/{metric}/{index}/len
GET /api/metric/{metric}/{index}/version
Example — last 30 days of Bitcoin closing price: Example — last 30 days of Bitcoin closing price:
GET /api/metric/price/day?start=-30 GET /api/metric/price/day?start=-30